//
// Mining module for TETDM 
// FLR.java Version 1.0
// Copyright(C) 2012 YASUFUMI TAKAMA All RIGHTS RESERVED.
// This program is provided under the license.
// You Should read the README file.
//

package module.MiningModules.FLR;

import module.MiningModules.TermMiningBase.*;
import java.util.*;
import java.lang.Math.*;

import java.io.File;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.PrintWriter;
import java.io.IOException;

@SuppressWarnings("serial")
public class FLR extends TermMiningBase
{
	int LIST_LEN;
	private String[] tlist;
	private WordList biGramList;
	private WordList nGramList;
	private WordList allNGramList;
	private WordList cValueList;
	private HashMap<String, Double> nGramLRHash;
	private boolean isLoadKeyword;
	
	public FLR()
	{
//		super();
		setModuleID(47);
//		initializeData();
        setCategoryID(2);
        pairingVisualizationID = new int[]{25};
	}
	
	public void initializeData(){// initialize class field variable
//		N_GRAM=20;
		LIST_LEN=150;
		tlist = new String[1];
		tlist[0] = "NoData";
		isLoadKeyword = false;
	}
	
	public int[] SetValues() // return list of values correspondings to keywords
	{
				
		if(!isLoadKeyword){
			int[] a = new int[1];
			a[0] = -1;
			return a;
		}else {
			int[] values = new int[tlist.length];
			for(int i=0; i<tlist.length; i++){
				int freq = 0;
				for(int k=0; k<cValueList.size(); k++){
					String str = ngramWordToString(cValueList.get(k));
					if(str.indexOf(tlist[i])>=0){
						freq++;
					}
				}
				values[i] = freq;
			}
			return values;
		}
	}
	
	public String[] SetKeyword()
	{
		WordList singleWordList = new WordList();
		for(int i=0; i<text.segmentNumber;i++){
			for(int j=0; j<text.segment[i].sentenceNumber;j++){
				Word singleWord = new Word();
				for(int k=0; k<text.segment[i].sentence[j].wordNumber;k++){
						char c = text.segment[i].sentence[j].word[k].charAt(0);
						if(c >= 0x8340 && c <= 0x8396 ){
							singleWord.append(new Word(i, j, k));
						}else if(!singleWord.isEmpty){
							singleWordList.add(new NGramWord(singleWord));
							singleWord = new Word();
						}
						if(text.segment[i].sentence[j].wordIDList[k]>=0){
							singleWord = new Word(i, j, k);
							singleWordList.add(new NGramWord(singleWord));
							singleWord = new Word();
						}
					}
				}
			}

			if(singleWordList.size()==0){
				return tlist;
			}

			biGramList = new WordList();
			allNGramList = new WordList();
			cValueList = new WordList();
			
			NGramWord appendList = new NGramWord();
			appendList = singleWordList.get(0);

			for(int i=0;i < singleWordList.size()-1;i++){
				NGramWord cValueListMae = singleWordList.get(i);
				NGramWord cValueListUsiro = singleWordList.get(i+1);
				if(isBiGram(cValueListMae.getLastWord(), cValueListUsiro.getLastWord())){
					appendList.add(cValueListUsiro.getLastWord());
				}else {
					cValueList.add(appendList);
					appendList= new NGramWord();
					appendList.add(cValueListUsiro.getLastWord());
				}
			}
			cValueList.add(appendList);
		
		for(int i=0; i<singleWordList.size()-1;i++){
			NGramWord biGramWordMae = singleWordList.get(i);
			NGramWord biGramWordUsiro = singleWordList.get(i+1);
			if(isBiGram(biGramWordMae.getLastWord(),
				biGramWordUsiro.getLastWord())){
				NGramWord res = new NGramWord();
				res.addAll(biGramWordMae);
				res.add(biGramWordUsiro.getLastWord());
				biGramList.add(res);
			}
		}

		allNGramList.addAll(singleWordList);
		nGramList = biGramList;

		while(nGramList.size()>1){
			WordList inputWordList = nGramList;
			allNGramList.addAll(nGramList);
			nGramList = new WordList();
			
			for(int i=0; i<inputWordList.size()-1;i++){
				NGramWord nGramWordMae = inputWordList.get(i);
				NGramWord nGramWordUsiro = inputWordList.get(i+1);
				
				if(isBiGram(nGramWordMae.getLastWord(), nGramWordUsiro.getLastWord())){
					NGramWord res = new NGramWord();
					res.addAll(nGramWordMae);
					res.add(nGramWordUsiro.getLastWord());
					nGramList.add(res);
				}
			}
		}

		nGramLRHash = new HashMap<String,Double>();
		for(int i=0; i<allNGramList.size(); i++){
			NGramWord nowWord = allNGramList.get(i);
			if(nowWord.size()<2){
				continue;
			}
			if(nGramLRHash.containsKey(ngramWordToString(nowWord))){
				continue;
			}
			double LR=1;
			double FLR;
			int F=0;
			for(int k=0; k<cValueList.size(); k++){
				if(ngramWordToString(cValueList.get(k)).equals(ngramWordToString(nowWord))){
					F++;
				}
			}
			for(int j=0; j<nowWord.size(); j++){
				int LN = maeCount(biGramList, wordToString(nowWord.get(j)));
				int RN = usiroCount(biGramList, wordToString(nowWord.get(j)));
				LR *= ((double)LN+1)*((double)RN+1);
			}
			LR = Math.pow(LR, (1/(double)(2*nowWord.size())));
			FLR = LR * (double)F;
			nGramLRHash.put(ngramWordToString(nowWord), FLR);
		}
		
		List<Map.Entry> entries = new ArrayList<Map.Entry>(nGramLRHash.entrySet());
		Collections.sort(entries, new Comparator(){
		    public int compare(Object o1, Object o2){
		        Map.Entry e1 =(Map.Entry)o1;
		        Map.Entry e2 =(Map.Entry)o2;
		        return (-1)*((Double)e1.getValue()).compareTo((Double)e2.getValue());
		    }
		});
		
		try{
			File file = new File(myModulePath + "score.txt");
			PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file, false)));
			
			int len=setListLength(entries);
			if(len>0){
				tlist = new String[len];
				for(int i=0; i<len; i++){
					tlist[i] = (String)(entries.get(i).getKey());
				}
				isLoadKeyword = true;
			}
//			pw.println((String)("# of words  "+(entries.size())));
            pw.println((String)("# of words  "+(entries.size())));
			for(int i=0; i<entries.size(); i++){
				pw.println((String)(entries.get(i).getKey()) +": score_"+ (Double)(entries.get(i).getValue()));

			}

			pw.close();
		}catch(IOException e){
	      		System.out.println(e);
		}
		return tlist;
	}
	
	String wordToString(Word word){
		String stWord = "";
		for(int i=word.wordNumberStart; i<=word.wordNumberEnd; i++){
			stWord += text.segment[word.segmentNumber].sentence[word.sentenceNumber].word[i];
		}
		return stWord;
	}
	
	String ngramWordToString(NGramWord ngramWord){
		String word = "";
		for(int i=0; i<ngramWord.size(); i++){
			word += wordToString(ngramWord.get(i));
		}
		return word;
	}
	
	Boolean isBiGram(Word ngwMae, Word ngwUsiro){
		if((ngwMae.segmentNumber == ngwUsiro.segmentNumber)
			&& (ngwMae.sentenceNumber == ngwUsiro.sentenceNumber)
			&& ( (ngwMae.wordNumberEnd+1) == ngwUsiro.wordNumberStart) ){
			return true;
		}
		return false;
	}

	public int maeCount(WordList bigramMae, String key){
		int count = 0;
		for(int i=0; i<bigramMae.size(); i++){
			NGramWord bgw = bigramMae.get(i);
			if(wordToString(bgw.getLastWord()).equals(key)){
				count++;
			}
		}
		return count;
	}
	public int usiroCount(WordList bigramUsiro, String key){
		int count = 0;
		for(int i=0; i<bigramUsiro.size(); i++){
			NGramWord bgw = bigramUsiro.get(i);
			if(wordToString(bgw.get(0)).equals(key)){
				count++;
			}
		}
		return count;
	}
	
	class Word{
		public int segmentNumber;
		public int sentenceNumber;
		public int wordNumberStart;
		public int wordNumberEnd;
		public boolean isEmpty;
		public Word(){
			this.isEmpty = true;
		}
		public Word(int segmentNum, int sentenceNum, int wordNum){
			this.segmentNumber = segmentNum;
			this.sentenceNumber = sentenceNum;
			this.wordNumberStart = wordNum;
			this.wordNumberEnd = wordNum;
			this.isEmpty = false;
		}
		public void append(Word word){
			if(this.isEmpty){
				this.segmentNumber = word.segmentNumber;
				this.sentenceNumber = word.sentenceNumber;
				this.wordNumberStart = word.wordNumberStart;
				this.isEmpty = false;
			}
			this.wordNumberEnd = word.wordNumberStart;
		}
	}
	
	class NGramWord extends ArrayList<Word>{
		public NGramWord(){
			;
		}
		
		public NGramWord(Word word){
			this.add(word);
		}
		
		public Word getLastWord(){
			return this.get(this.size()-1);
		}
		
	}
	
	class WordList extends ArrayList<NGramWord>{
		public WordList(){
			;
		}
	}

	int setListLength(List<Map.Entry> entries){
		int i=0;
		int limit = Math.min(entries.size(),LIST_LEN);
		while(i<limit){
			if((Double)(entries.get(i).getValue())<=0)
				break;
			i++;
		}
		return i;
	}
}
