package testing;


import java.util.*;
import java.io.*;

import errorReachableAnalyzer.MultiConcurrentSystemModelMaker;
import errorReachableAnalyzer.MultiRequirementParser;
import multiConcurrentModel.Model;
import multiConcurrentModel.MultiConcurrentModel;
import multiConcurrentModel.State;
import multiConcurrentModel.Transition;
//評価実験用に用意したディレクトリ上で操作を行うクラス
public class DirectoryTracker {
	private File directory;
	private List<String> candidate;
	private List<String> cas;
	private List<Model> req;
	private Model e;
	private Model c;
	private boolean firstCheck;
	private MultiConcurrentModel cm;
	private MultiRequirementParser mrp;
	private String targetError="";
	private int[] checkerForMRP;
	
	private String sep=File.separator;
	public DirectoryTracker(String directory) {
		this.directory=new File(directory);
		if(this.directory.exists()){
			candidate=new ArrayList<String>(Arrays.asList(this.directory.list()));
			candidate.remove("Controller");
			cas=new ArrayList<String>();
		}
		firstCheck=false;
	}
	public boolean setDirectory(String dir){
		directory=new File(dir);
		if(directory.exists()){
			candidate=new ArrayList<String>(Arrays.asList(directory.list()));
			candidate.remove("Controller");
			cas=new ArrayList<String>();
			return true;
		}
		return false;
	}
	
	private File searchEnvInDirectory(){
		return new File(directory.getAbsolutePath()+sep+"Controller"+sep+"ENV.txt");
	}
	
	private void setControllableAction(){
		File caFile=new File(directory.getAbsolutePath()+sep+"Controller"+sep+"CA.txt");
			
		try {
			BufferedReader reader =new BufferedReader(new FileReader(caFile));
			String c;
			while((c=reader.readLine())!=null){
				//System.out.println("ControllablAction:"+c);
				cas.add(c);
			}
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}
	private String setDegradationTargets(){
		File caFile=new File(directory.getPath()+sep+"Controller"+sep+"DegradationTargets.txt");
		try {
			BufferedReader reader =new BufferedReader(new FileReader(caFile));
			String c;
			checkerForMRP=new int[(candidate.size()/32)+1];
			for(int i=0;i<checkerForMRP.length;i++)
				checkerForMRP[i]=0;
			while((c=reader.readLine())!=null){
				int i=candidate.indexOf(c);
				if(i!=-1){
					if(targetError=="")
						targetError="ERROR"+i;
					else
						targetError=targetError+"&&ERROR"+i;					
					checkerForMRP[i/32]+=(1<<(i%32));
				}
			}
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		//System.out.println(targetError);
		return targetError;
	}

	public MultiConcurrentModel getMCModelFromDirectory(){
		File env;
		FSP_FileReader reader;
		req=new ArrayList<Model>();
		
		if((env=searchEnvInDirectory())==null){
			return null;
		}
		setControllableAction();
		reader=new FSP_FileReader(env);
		e=reader.getModel();
		for(int i=0;i<candidate.size();i++){
			if (new File(directory.getPath()+sep+candidate.get(i)).isFile()){
				reader=new FSP_FileReader(directory.getPath()+sep+candidate.get(i));
//				System.out.println(candidate.get(i));
				req.add(reader.getModel());				
			}
		}	
		targetError=setDegradationTargets();
		return cm = MultiConcurrentSystemModelMaker.makeConcurrentSystem(e, req,cas,targetError);
	}	
	public List<int[]> checkSimulate(String controller){
		if(cm==null){
			getMCModelFromDirectory();
		}
		FSP_FileReader reader=new FSP_FileReader(directory.getPath()+sep+"Controller"+sep+controller);
		c=reader.getModel();
		mrp=new MultiRequirementParser(cm,checkerForMRP);
		firstCheck=true;
		return mrp.checkSimulate(c);
		
	}
	private boolean modelUpdate(String updatedPart){
		if(!firstCheck){
			System.out.println("ERROR: First check have not been done yet");
			return false;
		}
		String[] materials=updatedPart.split(",");
		if(materials.length!=3){
			System.out.println("ERROR:Input type is wong");
			return false;
		}
		cm=MultiConcurrentSystemModelMaker.modelUpdate(cm, e, req, materials[0],materials[1], materials[2]);
		return true;
	}
	
	
	public List<int[]> checkUpdated(String updatedPart){
		if(!modelUpdate(updatedPart))return null;
		if(mrp==null)mrp=new MultiRequirementParser(cm,checkerForMRP);
		return mrp.checkUpdatedSimulate(c);
	}

	public List<String> checkUpdateFromFile(String fileName){
		mrp=new MultiRequirementParser(cm,checkerForMRP);
		BufferedReader reader=null;
		List<String> result=new ArrayList<String>();
		List<int[]> resultBits=null;
		try {
			reader=new BufferedReader(new FileReader(new File(directory.getPath()+sep+"Controller"+sep+fileName)));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return null;
		}
		try {
			String temp;
			while((temp=reader.readLine())!=null){
				resultBits=checkUpdated(temp);
			}
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		for(int i=0;i<resultBits.size();i++){
			result.add(convertResults(resultBits.get(i)));
		}
		if(result.size()==0)result.add("");
		return result;
	}
	
	private String convertResults(int[] result){
		String resultString="";
		for(int i=0;i<result.length;i++){
			int p=0;
			for(int j=result[i];j>0;j/=2){
				if(j%2==1){
					if(resultString=="")
						resultString=candidate.get((i*32)+p);
					else
						resultString+="&&"+candidate.get((i*32)+p);
					
				}
				p++;
			}
		}		
		return resultString;
	}
	
	//Extracting model's difference between 2 files.
	public void extractDifference(File before,File after){
		Model 	m1=new FSP_FileReader(before).getModel(),
				m2=new FSP_FileReader(after).getModel();
		HashMap<String,State> stateMap=new HashMap<String,State>(); 
		String t=null;
		List<String> l=new ArrayList<String>();
		BufferedWriter f=null;
		if(m1.getSize()!=m2.getSize()){
			System.out.println("ERROR:These models are not similar");
			return;
		}
		makeStateMapWithoutR(stateMap,m1.getInitialState(),m2.getInitialState());
		
		for(int i=0;i<m2.getSize();i++){
			State s2=m2.getState(i);
			State s1=stateMap.get(s2.toString());
			System.out.println("standard"+s2+","+s1);
			for(int j=0;j<s2.getToTransitionNum();j++){
				t=s2.getToTransition(j).toString();
				if(s1.getToTransition(t)==null){
					System.out.println(s2.getToStateByTransition(t)+","+stateMap.get(s2.getToStateByTransition(t).toString()));
					l.add(stateMap.get(s2.toString())+","+t+","+stateMap.get(s2.getToStateByTransition(t).toString()).toString());
				}
			}
		}//*/
		if(l.size()==0){
			System.out.println("ERROR:There is no difference");
		}
		try {
			 f=new BufferedWriter(new FileWriter(new File(directory.getPath()+sep+"Controller"+sep+t+".txt")));
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			f.write(l.get(0));
			for(int i=1;i<l.size();i++){
				f.newLine();
				f.write(l.get(i));
			}
			f.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	//used for extractDifference()
	private void makeStateMapWithoutR(HashMap<String,State>stateMap,State s1,State s2){
		Stack<State> stack=new Stack<State>();
		State c2=s2;
		stateMap.put(s2.toString(), s1);
		stack.push(c2);
		while(!stack.isEmpty()){
			c2=stack.pop();
			s1=stateMap.get(c2.toString());
			while(c2.hasNext()){
				Transition t2 =(Transition)c2.next(),t1;
				if((t1=s1.getToTransition(t2.toString()))!=null)
					if(stateMap.get(t2.getTo().toString())==null){
						if(t1==t2)System.out.println(t1.getTo()+","+t2.getTo());
						stateMap.put(t2.getTo().toString(),t1.getTo());					
						stack.push(t2.getTo());
					}					
			}
		}
		System.out.println("model size:"+stateMap.size());
	}//*/
	public String toString() {
		return "Directory's path:"+this.directory.getAbsolutePath();
	}
}