package pkg1;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

public class proteinTest {
	public static HashMap<String, Integer> proteinHash = new HashMap<String, Integer>();//realProtein:ID, this way we can get ID convenient 
	
	/*
	 * getNameById() get the protein name by ID
	 */
	public String getNameById(int id)
	{
		for(String s : proteinHash.keySet())
		{
			if(proteinHash.get(s) == id)
				return s;
		}
		System.out.print("no such an ID");
		return null;
	}
	/*
	 * linkHash() returns a hash with each protein as key and its related proteins as the value: e.g. 1: 2345
	 */
	public HashMap<Integer, ArrayList<Integer>> linkHash(HashMap<ArrayList<Integer>, Integer> h)
	{
		HashMap<ArrayList<Integer>, Integer> scoreHash = h;
		HashMap<Integer, ArrayList<Integer>> links = new HashMap<Integer, ArrayList<Integer>>();
		
		for(ArrayList<Integer> a: scoreHash.keySet())
		{
			if(!links.containsKey(a.get(0)))//if [11,12]:200, and links doesn't contain 11 as a key
			{
				ArrayList<Integer> newList = new ArrayList<Integer>();
				newList.add(a.get(1));
				links.put(a.get(0), newList);
			}
			else
			{
				links.get(a.get(0)).add(a.get(1));
			}
		}
		return links;
	}
	
	/*
	 * copyArray() copys an array to another, not just make a pointer to it.
	 */
	public ArrayList<Integer> copyArray(ArrayList<Integer> a)
	{
		ArrayList<Integer> r = new ArrayList<Integer>();
		for(int i= 0 ; i < a.size(); i++)
			r.add(a.get(i));
		return r;
	}
	/*
	 * closure() gets all related proteins together according to the links'hashtable: e.g. 1:2345, 2: 4567....
	 * first add 1 to the array:[1] then add all its links: [12345], set a cursor, then move the cursor to second position and then add all cursor's 
	 * number's links: [1234567]
	 */
	public ArrayList<Integer> closure(HashMap<Integer, ArrayList<Integer>> l)
	{
		HashMap<Integer, ArrayList<Integer>> links = l;
		int cursor = 0;
		ArrayList<Integer> clo = new ArrayList<Integer>();   
		clo.add(2);//every time just add the key 
		cursor++;
		ArrayList<Integer> newClo = copyArray(clo);  
	
		for(Integer i: l.get(0))
			newClo.add(i);
		while(clo.size()!=newClo.size())
		{
			clo = copyArray(newClo); 
			if(!newClo.contains(clo.get(cursor)))
				newClo.add(clo.get(cursor));
			if(links.containsKey( (clo.get(cursor)) ))
			{
				for(Integer each: links.get(clo.get(cursor)))
				{
					if(!newClo.contains(each))
					{
						newClo.add(each);
					}
				}
			}
			cursor++;
		}
		//Set<Integer> mySet = new HashSet<Integer>(clo);//convert array to set 
		System.out.print(clo.size());
		//System.out.print(mySet);
		return clo;
	}
	/*
	 * createMatrix() creates the matrix for protein and the corresponding score according to the scorehash: E.g., (pro1,pro2):200
	 */
	public int[][] createMatrix(HashMap<ArrayList<Integer>, Integer> h)
	{
		HashMap<ArrayList<Integer>, Integer> scoreHash = h;
		int row = h.size();
		int[][] scoreMatrix = new int[row][row];
		for(ArrayList<Integer> a: scoreHash.keySet())
		{
			scoreMatrix[a.get(0)][a.get(1)] = scoreHash.get(a);
		}
		return scoreMatrix;
	}
	/*
	 * readin file and create two hashes: pro:ID and pair:score
	 * return the pair of scores as a hashtable
	 */
	public HashMap<ArrayList<Integer>, Integer> loadFile(String filepath) throws IOException {
		String thisLine;
		BufferedReader myInput = null;  
		HashMap<ArrayList<Integer>, Integer> scoreHash = new HashMap<ArrayList<Integer>, Integer>();//pro1,pro2:score

		try {
			FileInputStream fin = new FileInputStream(new File(filepath));
			myInput = new BufferedReader(new InputStreamReader(fin));
			int id = 0;//give each protein an ID

			while ((thisLine = myInput.readLine()) != null) {
				 
				String[] split = thisLine.split(" ");
				ArrayList<Integer> pair = new ArrayList<Integer>();
				if(!proteinHash.containsKey(split[0]))
				{
					proteinHash.put(split[0], id);
					pair.add(id);
					id++;
				}
				else
					pair.add(proteinHash.get(split[0]));
				if(!proteinHash.containsKey(split[1]))
				{
					proteinHash.put(split[1], id);
					pair.add(id);
					id++;
				}
				else
					pair.add(proteinHash.get(split[1]));

				scoreHash.put(pair, Integer.parseInt(split[2])); 
			} 
		} catch (Exception e) {
			e.printStackTrace();
		} 
		myInput.close();
		return scoreHash;
	}
	
	/*
	 * printMatrix() prints a matrix
	 */
	public void printMatrix(int[][] m)
	{
		for(int i = 0 ; i < m.length; i ++)
		{
			for(int j = 0 ; j < m.length ; j ++)
			{
				System.out.print(m[i][j]);
				System.out.print(",");
			}
			System.out.println();
		}
	}
	/*
	 * getHash() gets the hash for a certain number of proteins: e.g. num = 100, get 0-100's hashscores and make a 100*100 matrix
	 */
	public HashMap<ArrayList<Integer>, Integer> getHash(HashMap<ArrayList<Integer>, Integer> h, int num)
	{
		HashMap<ArrayList<Integer>, Integer> r = new HashMap<ArrayList<Integer>, Integer>();
		
		for(int i = 0; i < num; i++)
		{
			for(int j = i; j < num; j++)
			{
				ArrayList<Integer> temp = new ArrayList<Integer>();
				temp.add(i);
				temp.add(j);
				if(h.containsKey(temp))
				{
					r.put(temp, h.get(temp));
					ArrayList<Integer> temp1 = new ArrayList<Integer>();
					temp1.add(j);
					temp1.add(i);
					r.put(temp1, h.get(temp));//h.get(temp)==h.get(temp1)
				}
			}
		}
		return r;
	}
	/*
	public static void main(String args[]) throws IOException
	{
		proteinTest l = new proteinTest();
		HashMap<ArrayList<Integer>, Integer> h = l.loadFile("PlasmodiumfalciparumLink.txt");//pair of scores as a hashtable
		//System.out.print(h);
		HashMap<ArrayList<Integer>, Integer> newH = l.getHash(h, 100);
		optiMatrix m = new optiMatrix();
		m.createHyperShare(newH);
		m.initLenList(newH);
		PrintWriter out;
		try{
			for(int length = 10; length < 11; length++)
			{ 
				HashMap<ArrayList<Integer>, Integer> b = m.getLenArrayRec(length);
				for(int weight = 3000; weight < 3500; weight = weight + 100)
				{

					out = new PrintWriter(new FileWriter("out"+length+"t"+(weight+length*400)+".txt"));
					ArrayList<ArrayList<Integer>> result = m.pHashN(weight+length*400);
					for(int ind = 0 ; ind < result.size(); ind++ )
					{
						for(int k = 0; k < result.get(ind).size(); k++)
						{
							out.print(l.getNameById(result.get(ind).get(k)));
							out.print(",");
						}
						//out.print(result.get(ind));
						out.print(m.calWeight(result.get(ind)));
						out.print("\t\n");
					}
					out.close();
				}
			}
	    }
	    catch(IOException ex){
	        System.out.println (ex.toString());
	        System.out.println("Could not find file " );
	    }

		//System.out.print(proteinHash.size());
		//HashMap<Integer, ArrayList<Integer>> links = l.linkHash(h);
		//l.closure(links);
		
		//int[][] m = l.createMatrix(h);
		//System.out.print(h);
		//l.printMatrix(m);
	}
}
*/
	public static void main(String args[]) throws IOException
	{
		proteinTest l = new proteinTest();
		HashMap<ArrayList<Integer>, Integer> h = l.loadFile("PlasmodiumfalciparumLink.txt");//pair of scores as a hashtable
		//System.out.print(h);
		HashMap<ArrayList<Integer>, Integer> newH = l.getHash(h, 100);
		matrix m = new matrix();
		int[][][] a = m.initArray(m.createHyperShareUsingHash(newH));
		m.initLenList(a);


		PrintWriter out;
		try{
			for(int length = 5 ; length < 6; length++)
			{ 
				int[][][] b = m.getLenArrayRec(length); 
				for(int weight = 2000; weight < 2500; weight = weight + 100)
				{

					out = new PrintWriter(new FileWriter("out"+length+"t"+(weight+length*300)+".txt"));
					//print out how many paths found
					//System.out.print(length+" " + (weight+length*300) + " " );
					ArrayList<ArrayList<Integer>> paths = m.pHashN(weight+length*300);

					for(int ind = 0 ; ind < paths.size(); ind++ )
					{
						for(int k = 0; k < paths.get(ind).size(); k++)
						{
							out.print(l.getNameById(paths.get(ind).get(k)));
							out.print(",");
						}
						//out.print(result.get(ind));
						//out.print(m.calWeight(paths.get(ind)));
						out.print("\t\n");
					}
					out.close();
				}
			}
	    }
	    catch(IOException ex){
	        System.out.println (ex.toString());
	        System.out.println("Could not find file " );
	    }

		//System.out.print(proteinHash.size());
		//HashMap<Integer, ArrayList<Integer>> links = l.linkHash(h);
		//l.closure(links);
		
		//int[][] m = l.createMatrix(h);
		//System.out.print(h);
		//l.printMatrix(m);
	}
}