using System;
using System.Collections.Generic;
using System.Text;

namespace Intemi
{
    public class OneNNConfig : IConfiguration
    {
        public void Configure(ConfigBuilder confBuilder)
        {
	        confBuilder.DeclareInput("Dataset",
	            new Type[] { typeof(IDataTable), typeof(ITargets) }, false);
	        confBuilder.DeclareOutput("Classifier", null,
	            new Type[] { typeof(IClassifier) });
        }
        public object Clone() { return new OneNNConfig(); }
    }

    [Machine("1NN",typeof(OneNNConfig))]
    public class OneNN : IMachine, IClassifier
    {
        IMachineBase machineBase;
        public void SetMachineBase(IMachineBase mb) { machineBase = mb; }

        IFeature targetsInfo;
        public IFeature TargetsInfo { get { return targetsInfo; } }
        public void Run(ref bool shouldTerminate) 
        { 
	        IDataTable dataTable = machineBase.GetInput("Input dataset") as IDataTable;
	        targetsInfo = (dataTable as ITargets).Targets.FeatureInfo;
        }
        public IOneFeatureData Classify(IDataSet dataSetToClassify)
        {
	        IDataTable dataTable = machineBase.GetInput("Input dataset") as IDataTable;
            IOneFeatureData tt = (dataTable as ITargets).Targets;
            IOneFeatureDataBuilder t = tt.CopyStructure(dataSetToClassify.InstanceCount);
	        IFeatureEnumerator t2 = tt.FeatureEnumerator();
	        IVectorEnumerator ve = (IVectorEnumerator)dataSetToClassify.InstanceEnumerator();
            IVectorEnumerator ve2 = (IVectorEnumerator)dataTable.InstanceEnumerator();
	        float[] a1 = ve.Vector, a2 = ve2.Vector, labels = t2.Vector;
	        for (int i = 0; i < dataSetToClassify.InstanceCount; i++)
	        {
                ve.GoToInstance(i);
	            double d, minDist = System.Double.PositiveInfinity;
	            int k, minId = -1;
                for (int j = 0; j < dataTable.InstanceCount; j++)
                {
                    ve2.GoToInstance(j);
                    for (k = 0, d = 0; k < a1.Length; k++)
                    {
                        double dp = a1[k] - a2[k];
                        d += dp * dp;
                    }
                    if (d < minDist) { minId = j; minDist = d; }
                }
	            t.AddValue(labels[minId]);
	        }
	        return (IOneFeatureData)t.Build();
        }
        public bool VerifyTestData(IDataSet d) 
        { 
	        IDataTable inputDT = machineBase.GetInput("Input dataset") as IDataTable;
	        int featureCount = inputDT != null? inputDT.FeaturesInfo.Count : 0;
	        IDataTable dt = d as IDataTable;
	        return dt != null && dt.FeaturesInfo.Count == featureCount; 
        }
    }
}
