package jp.hasc.hasctool.core.runtime.filter.weka.learning;

import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;
import jp.hasc.hasctool.core.data.EnumCommand;
import jp.hasc.hasctool.core.runtime.RuntimeContext;
import jp.hasc.hasctool.core.runtime.filter.AbstractFilter;
import jp.hasc.hasctool.core.runtime.filter.weka.WekaDataInstance;

/**
 * wekaライブラリを利用して機械学習を行うフィルタです
 * @author hiro
 */

public abstract class MachineLearning extends AbstractFilter {

	//識別対象を指定
	String element_;
	String[] eList_;
	int eLength_;

	//特徴量を指定
	String feature_;
	String[] fList_;
	int fLength_;

	protected WekaDataInstance wdi_;
	protected Instances learningDataset_;

	@Override
	public void setup(RuntimeContext context) {
		super.setup(context);
		eList_ = element_.split(",");
		eLength_ = eList_.length;
		fList_ = feature_.split(",");
		fLength_ = fList_.length;
		wdi_ = new WekaDataInstance();
	}

	public void setElement(String element) {
		element_ = element;
	}

	public void setFeature(String feature) {
		feature_ = feature;
	}

	//属性作成メソッド
	private FastVector createAttributes() {
		Attribute[] attribute_ = new Attribute[fLength_+1];
		//create the numeric attribute feature
		for(int i=0; i<fLength_; i++){
			attribute_[i] = new Attribute(fList_[i]);
		}
		//create the nominal attribute element
		FastVector elementAttributeValues = new FastVector(eLength_);
		for(int j=0; j<eLength_; j++){
			elementAttributeValues.addElement(eList_[j]);		
		}
		attribute_[fLength_] = new Attribute("element", elementAttributeValues);
		FastVector allAttributes = new FastVector(fLength_+1);
		for(int k=0; k<fLength_+1; k++){
			allAttributes.addElement(attribute_[k]);
		}
		return allAttributes;
	}

	//学習データセットを作成するメソッド
	private Instances createLearningDataSet(FastVector allAttributes) {
		Instances trainingDataSet = 
			new Instances("learningData", allAttributes, fLength_); 
		trainingDataSet.setClassIndex(fLength_);
		return trainingDataSet;
	}

	//インスタンス追加メソッド
	private void addInstance(Instances trainingDataSet, String[] data)  {        
		Instance instance = createInstance(trainingDataSet, data);
		trainingDataSet.add(instance);
	}

	//インスタンス作成メソッド
	private Instance createInstance(Instances associatedDataSet, String[] data) {
		Instance instance = new Instance(fLength_+1);
		instance.setDataset(associatedDataSet);
		for(int i=0; i<fLength_; i++){
			instance.setValue(i, Double.parseDouble(data[i]));
		}
		instance.setValue(fLength_, data[fLength_]);
		return instance;
	}

	//予測モデルの作成＆評価を行うメソッド
	abstract void evaluatepredictiveModel();

	public void processMessage(Object message) throws InterruptedException {
		if (message instanceof String) {
			String s = (String)message;
			String[] data = s.split(",");
			addInstance(learningDataset_, data);

		} else if (message == EnumCommand.BEGIN) {
			try {
				FastVector allAttributes = createAttributes();
				learningDataset_ = createLearningDataSet(allAttributes);

			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		} else if (message == EnumCommand.END) {
			try {
				System.out.println("START CREATE CLASSIFIER");
				evaluatepredictiveModel();
				outputMessage(EnumCommand.BEGIN);
				outputMessage(wdi_);
				outputMessage(EnumCommand.END);

			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		} else {
			// その他のメッセージはそのまま出力
			outputMessage(message);
		}
	}
}
