import numpy as np

# Import scikit libraries.
from sklearn import svm
import numpy as np

# References:
#   https://scikit-learn.org/stable/modules/svm.html

# text labels for the numeric class labels
labels = ["still", "left", "right"]

# number of rows of history used to detect features
history_rows = 8

#================================================================

# Convert a matrix of raw motion detection samples into a matrix of feature
# vectors by assembling the raw samples with finite differences across rows.
# Returns a matrix of feature vectors with fewer rows than the source.

def raw_to_features(samples):
    # skip the first rows which are used solely for differencing
    raw = samples[history_rows:]
    num_samples = raw.shape[0]

    # take the short interval finite difference
    diff1 = raw - samples[4:4+num_samples]

    # take the long interval finite difference
    diff2 = raw - samples[0:num_samples]

    # concatenate the rows into feature vectors
    features = np.hstack((raw, diff1, diff2))

    # and rescale to unit dimensions
    return features * (1.0/255.0)


# Load individual labeled sample sets and return a training set and label
# vector.
def load_training_data():
    still   = raw_to_features(np.loadtxt("data/still.data"))
    left    = raw_to_features(np.loadtxt("data/left.data"))
    right   = raw_to_features(np.loadtxt("data/right.data"))

    # Assemble a matrix of training data.
    training = np.vstack((still, left, right))

    # Assemble a vector of integer labels, one per sample.
    labels = np.hstack((0 + np.zeros(still.shape[0], dtype=int),
                        1 + np.zeros(left.shape[0], dtype=int),
                        2 + np.zeros(right.shape[0], dtype=int)))

    return training, labels

# Build and return a SVM classifier from previously saved data files.
def build_model():
    training, labels = load_training_data()
    classifier = svm.SVC()
    classifier.fit(training, labels)
    return classifier

# Given a new raw sample vector and a history matrix of raw samples, return a new history matrix.
def update_history(history, sample):
    if history is None:
        history = np.zeros((history_rows + 1, 16))

    # drop the first row and append the new sample
    return np.vstack((history[1:], sample.reshape(1, 16)))

# Given a classifier and a history matrix, return the current classification as
# a label string.
def classify_history(classifier, history):
    features = raw_to_features(history)
    numeric_labels = classifier.predict(features.reshape(1, 48))
    return labels[numeric_labels[-1]]
