package jp.hasc.hasctool.core.runtime.filter.file.label;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;

import jp.hasc.hasctool.core.data.EnumCommand;
import jp.hasc.hasctool.core.runtime.FileStreamProvider;
import jp.hasc.hasctool.core.runtime.RuntimeContext;
import jp.hasc.hasctool.core.runtime.filter.AbstractFilter;
import jp.hasc.hasctool.core.util.CSVUtil;
import jp.hasc.hasctool.core.util.CoreUtil;

/**
 *　ラベルファイル系列をマッチングするフィルタ
 *　マッチング方法：DPマッチング
 * @author hiro
 */
public class LabelMatchFilter extends AbstractFilter{

	String labelDir_;
	String[] labelFileList_;
	String[] labelList_;
	String[][] correct_ = new String[100][100000];
	int[] cIndex_ = new int[100];
	int cListNum_ = 0;
	String[] presumption_ = new String[100000];
	int pIndex_ = 0;
	double timeStep_ = 1.0;//単位：sec
	boolean start_ = true;
	double time_ = 0.0;

	public void setTimeStep(double tstep) {
		timeStep_ = tstep;
	}

	public void setLabeldir(String path) {
		labelDir_ = path;
	}

	public void setLabelList(String labelList) {
		labelList_ = labelList.split(",");
	}

	private void readFile(String labelFile){
		try{
			InputStream inps;
			try {
				inps = getRuntimeContext().getFileStreamProvider().openInputStream(labelFile);
				BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inps, RuntimeContext.DEFAULT_CHARSET));
				boolean start = true;
				double time = 0.0;
				while(true){
					String line = bufferedReader.readLine();
					if (line == null) break;
					String[] columns = CSVUtil.parseCSVRecord(line);
					if(columns.length == 3 && !(columns[1].equals(""))){
						if(start){
							time = Double.parseDouble(columns[0]);
							start = false;
						}
						for(int i=0; i<labelList_.length; i++){
							if(0 <= columns[2].indexOf(labelList_[i])){
								while(time < Double.parseDouble(columns[0])){
									correct_[cListNum_][cIndex_[cListNum_]] = "nan";
									cIndex_[cListNum_]++;
									time += timeStep_;
								}
								while(time < Double.parseDouble(columns[1])){
									correct_[cListNum_][cIndex_[cListNum_]] = labelList_[i];
									cIndex_[cListNum_]++;
									time += timeStep_;
								}
								break;
							}
						}
					}
				}
				bufferedReader.close();
				inps.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}catch(RuntimeException ex) {
			CoreUtil.throwAsRuntimeException(ex);
		}
		cListNum_++;
	}

	private String[] getLabelFile(){
		//ファイルオブジェクトを生成
		FileStreamProvider fsp = getRuntimeContext().getFileStreamProvider();
		ArrayList<String> dirList = new ArrayList<String>();
		fsp.listSubFolderNames(labelDir_, dirList);
		ArrayList<String> dir2List;
		for (int i=0; i<dirList.size(); i++){
			dirList.set(i,labelDir_+"/"+dirList.get(i));
			dir2List = new ArrayList<String>();
			fsp.listFileNames(dirList.get(i), dir2List);
			for(int j=0; j<dir2List.size(); j++){
				if(0 <= dir2List.get(j).indexOf("label")){
					dirList.set(i, dirList.get(i)+"/"+dir2List.get(j));
					break;
				}
			}
		}
		return dirList.toArray(new String[dirList.size()]);
	}

	@Override
	public void setup(RuntimeContext context) {
		super.setup(context);
	}

	/*
	 * ＜DPマッチング・ルール＞
	 * 縦軸:correct_
	 * 横軸:presumption_
	 */
	
	/*マッチングの重み設定*/
	int agree_ = 1;//一致
	//手法１
	/*
		int stayVal_ = 50;//stayの認識率（重み）
		int walkVal_ = 50;//walkの認識率（重み）
		int stUpVal_ = 50;//stUpの認識率（重み）
		int stDownVal_ = 50;//stDownの認識率（重み）
		int nanVal_ = 50;//空ラベルの場合
	 */

	//手法２
	/*
		int stayVal_ = 91;//stayの認識率（重み）
		int walkVal_ = 41;//walkの認識率（重み）
		int stUpVal_ = 65;//stUpの認識率（重み）
		int stDownVal_ = 71;//stDownの認識率（重み）
		int nanVal_ = 50;//空ラベルの場合
	 */

	//手法３
	/*
		public int getVal(int val){
			return val*val/50;
		}
		int stayVal_ = getVal(91);//stayの認識率（重み）
		int walkVal_ = getVal(41);//walkの認識率（重み）
		int stUpVal_ = getVal(65);//stUpの認識率（重み）
		int stDownVal_ = getVal(71);//stDownの認識率（重み）
		int nanVal_ = 50;//空ラベルの場合
	 */

	public int getVal(int val){
		return 1000/(100-val);
	}
	int stayVal_ = getVal(91);//stayの認識率（重み）
	int walkVal_ = getVal(41);//walkの認識率（重み）
	int stUpVal_ = getVal(65);//stUpの認識率（重み）
	int stDownVal_ = getVal(71);//stDownの認識率（重み）
	int nanVal_ = 13;//空ラベルの場合

	HashMap<String, Integer> dMap_ = new HashMap<String, Integer>();
	int len_ = 10;//縦
	int wid_ = 10;//横
	int sla_ = 1;//斜め
	
	private int match(int index) throws InterruptedException{
		//不一致の際の重みの設定
		dMap_.put("stay", stayVal_);
		dMap_.put("walk", walkVal_);
		dMap_.put("stUp", stUpVal_);
		dMap_.put("stDown", stDownVal_);
		dMap_.put("nan", nanVal_);

		//不一致コスト表の作成
		int[][] icTable = new int[cIndex_[index]][pIndex_];
		for(int i=0; i<cIndex_[index]; i++){
			for(int j=0; j<pIndex_; j++){
				if(correct_[index][i].equals(presumption_[j])){
					icTable[i][j] = agree_;
				} else {
					int val = dMap_.get(correct_[index][i]);
					icTable[i][j] = val;
				}
			}
		}
		
		int x = 0;
		int y = 0;
		//不一致コスト表を用いてDPマッチングを計算
		int[][] dpTable = new int[cIndex_[index]][pIndex_];
		dpTable[x][y] = icTable[0][0];
		
		while(x < cIndex_[index]-1 || y < pIndex_-1){
			if(x < cIndex_[index]-1 && y < pIndex_-1){
				dpTable[x+1][y+1] = dpTable[x][y]+icTable[x+1][y+1]+sla_;//斜め移動
				dpTable[x+1][y] = dpTable[x][y]+icTable[x+1][y]+len_;//縦移動
				dpTable[x][y+1] = dpTable[x][y]+icTable[x][y+1]+wid_;//横移動
				if(dpTable[x+1][y+1] < dpTable[x+1][y]){
					if(dpTable[x+1][y+1] < dpTable[x][y+1]){
						x++;
						y++;
						wid_ = 10;
						len_ = 10;
					}else{
						y++;
						wid_ = wid_ + 5;
						len_ = 10;
					}
				}else{
					if(dpTable[x+1][y] < dpTable[x][y+1]){
						x++;
						wid_ = 10;
						len_ = len_ +5;
					}else{
						y++;
						wid_ = wid_ +5;
						len_ = 10;
					}
				}
			}else if(x < cIndex_[index]-1){
				dpTable[x+1][y] = dpTable[x][y]+icTable[x+1][y]+len_;//縦移動
					x++;
					wid_ = 5;
					len_ = len_ + 3;
			}else{
				dpTable[x][y+1] = dpTable[x][y]+icTable[x][y+1]+wid_;//横移動
				y++;
				wid_++;
				len_ = 5;
		
			}
		}
		
		//書き出し
		/*
		if(labelFileList_[index].contains("888")){
			System.out.println("labelFile:"+labelFileList_[index]);
			String label = "table"+",";
			for(int j=0; j<pIndex_; j++){
				label += presumption_[j];
				if(j != pIndex_-1)label += ",";
			}
			outputMessage(label);
			for(int i=0; i<cIndex_[index]; i++){
				String line = correct_[index][i]+",";
				for(int j=0; j<pIndex_; j++){
					line += dpTable[i][j];
					if(j != pIndex_-1)line += ",";
				}
				outputMessage(line);
				}
			}
			*/
		
			return dpTable[cIndex_[index]-1][pIndex_-1];
			}

		@Override
		public void processMessage(Object message) throws InterruptedException {
			if (message instanceof String) {
				// label line
				String line=(String)message;String[] columns = CSVUtil.parseCSVRecord(line);
				if(columns.length == 3 && !(columns[1].equals(""))){
					if(start_){
						time_ = Double.parseDouble(columns[0]);
						start_ = false;
					}
					for(int i=0; i<labelList_.length; i++){
						if(0 <= columns[2].indexOf(labelList_[i])){
							while(time_ < Double.parseDouble(columns[0])){
								presumption_[pIndex_] = "nan";
								pIndex_++;	
								time_ += timeStep_;
							}
							while(time_ < Double.parseDouble(columns[1])){
								presumption_[pIndex_] = labelList_[i];
								pIndex_++;
								time_ += timeStep_;
							}
							break;
						}
					}
				}
				
			}else if (message==EnumCommand.BEGIN) {
				labelFileList_ = getLabelFile();
				for(int i=0; i<labelFileList_.length; i++){
					readFile(labelFileList_[i]);
				}

			} else if (message == EnumCommand.END){
				outputMessage(EnumCommand.BEGIN);
				for(int k=0; k<labelFileList_.length; k++){
					int dpVal =match(k);
					outputMessage(labelFileList_[k]+","+dpVal);
				}
				outputMessage(EnumCommand.END);
			} else {
			}
		}
	}
