% This function uses K nearest neighbos (KNN) to find output labels for 
% test samples based on the mode of nearest neighbors (using Euclidean 
% distance) from a training set. inputData is the source data containing 
% the feature vectors where the # of rows represent the # of samples and 
% columns represent # of features(e.g. 'feat_vec_foo' - foo = 'train', 
% 'val', or 'evl'), and labels (e.g. 'labels_foo'), the max # of nearest
% neighbors (maxK), the type of data being used for KNN (testData), and the
% name of the output .mat file (outputData). testData can take the value of
% 'val' or 'test' and is used to specify which features to use in the
% script (i.e. devtest for validation or evltest for evaluation sets)

function mainFunc(inputData, maxK, testData, outputData)
    % Add basic function to path
    addpath('../common');
    eval(['load ' inputData ]);
    
    % Determine whether to use validation or evaluation sets
    if strcmp(testData, 'val') == 1
        testingSet=feat_vec_devtest;
        testingLabels = labels_devtest;
    elseif strcmp(testData, 'test') == 1
        testingSet=feat_vec_evltest;
        testingLabels = labels_evltest;
    else
        disp('Error: Invalid testData selection');
        return
    end
    [n_examples, n_features] = size(testingSet);

    % Normalize the data to mean=0 stdv=1 using the training data
    [meanv, stdv, feat_vec_train] = normalize(feat_vec_train, [], []);
    [~, ~, testingSet] = normalize(testingSet, [], []);

    X=feat_vec_train;
    Y=testingSet;

    IDX = cell([n_examples, 1]);
    D = cell([n_examples, 1]);
    neighbor_label = cell(size(IDX));

    % Find the nearest neighbors using Euclidean distance
    tic;    % Begin timing of algorithm
    for itr=1:n_examples
        [IDX{itr} D{itr}] = knnsearch(X,Y(itr,:),'K',maxK);
    end
    training_time = toc; % Record training time

    % Find error rates and save results
    [error conf_matrix] = findBestK(D, IDX, labels_train, testingLabels);
    save(outputData, 'IDX', 'D', 'error', 'conf_matrix', 'training_time');
end
