package Controller;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StreamTokenizer;
import java.io.StringReader;
import java.util.LinkedList;


/**
 * 
 *
 */
public class Parser {
	
	
	/**
	 *
	 * this method parses an input utterance file to a list of list of string
	 * and stems the words represented by the strings
	 * @param file
	 * @return the parsed and stemmed utterance file
	 * @throws IOException 
	 * @throws FileNotFoundException 
	 */
	public LinkedList<LinkedList<String>> parse (File file) throws FileNotFoundException, IOException {
		LinkedList<String> utteranceSentences = readFileToStrLst(file);
		utteranceSentences = removeClassification(file);
		LinkedList<LinkedList<String>> utteranceWords = splitStrLstToStrLstLst(utteranceSentences);
		LinkedList<LinkedList<String>> stemmedUtteranceWords = stemStrLstLst(utteranceWords);
		
		return stemmedUtteranceWords;
	}

	/**
	 * this method removes classifications from the input utterance file, as they are in the CHILDES database
	 * 
	 * @param utteranceSentences
	 * @return a list of the original sentences
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public LinkedList<String> removeClassification(File file) throws FileNotFoundException, IOException {
		
		LinkedList<String> utteranceSentences = readFileToStrLst(file);
		// remove the 'word class' part of the utterance file - no good solution !!!
		LinkedList<String> utteranceSentencesToRemove = new LinkedList<String>();
		for (String utteranceSentence : utteranceSentences) {
			if(utteranceSentence.startsWith("pro ")
			|| utteranceSentence.startsWith("co ")
			|| utteranceSentence.startsWith("adj ")
			|| utteranceSentence.startsWith("aux ")
			|| utteranceSentence.startsWith("part ")
			|| utteranceSentence.startsWith("inf ")
			|| utteranceSentence.startsWith("v ")
			|| utteranceSentence.startsWith("prep ")
			|| utteranceSentence.startsWith("det ")
			|| utteranceSentence.startsWith("n ")
			|| utteranceSentence.startsWith("neg ")
			|| utteranceSentence.startsWith("conj ")
			|| utteranceSentence.startsWith("qn ")	
			|| utteranceSentence.startsWith("int ")
			|| utteranceSentence.startsWith("post ")	
			|| utteranceSentence.startsWith("adv ")
			|| utteranceSentence.equals("pro")
			|| utteranceSentence.equals("co")
			|| utteranceSentence.equals("adj")
			|| utteranceSentence.equals("aux")
			|| utteranceSentence.equals("part")
			|| utteranceSentence.equals("inf")
			|| utteranceSentence.equals("v")
			|| utteranceSentence.equals("prep")
			|| utteranceSentence.equals("det")
			|| utteranceSentence.equals("n")
			|| utteranceSentence.equals("neg")
			|| utteranceSentence.equals("conj")
			|| utteranceSentence.equals("qn")	
			|| utteranceSentence.equals("int")
			|| utteranceSentence.equals("post")	
			|| utteranceSentence.equals("adv")	
			|| utteranceSentence.isEmpty()
			) {
				utteranceSentencesToRemove.add(utteranceSentence);
			}
		}
		for (String utteranceSentenceToRemove : utteranceSentencesToRemove) {
			utteranceSentences.remove(utteranceSentenceToRemove);
		}
	
		return utteranceSentences;
				
		
	}
	
	
	/**
	 * this method read the utterance file and splits it to a list of string
	 * which represents in each case a line in the utterance
	 * @param file
	 * @return the list of read lines
	 * @throws IOException 
	 */
	private LinkedList<String> readFileToStrLst(File file) throws IOException, FileNotFoundException {
		LinkedList<String> utteranceSentences = new LinkedList<String>();
		
		FileReader fileContent = new FileReader(file);
		BufferedReader bufferedReader = new BufferedReader(fileContent); 
		
		while (true) {
			String line = bufferedReader.readLine();
			if (line != null) {	utteranceSentences.add(line); } 
		    else { break; }
		}
	
		return utteranceSentences;
	}
	
	/**
	 * this method splits the lines in the utterance into a list of list of string
	 * in which every word is lowered and only alphabetic characters are accepted
	 * @param utteranceSentences
	 * @return the list of list of split words 
	 * @throws IOException 
	 */
	private LinkedList<LinkedList<String>> splitStrLstToStrLstLst(LinkedList<String> utteranceSentences) throws IOException {
		LinkedList<LinkedList<String>> utteranceWords = new LinkedList<LinkedList<String>>();
		
		for (String line: utteranceSentences) {
			utteranceWords.add(splitStrToStrLst(line));
		}
	
		return utteranceWords;
	}
	
	public LinkedList<String> splitStrToStrLst(String strToSplit) throws IOException {
		LinkedList<String> splittedLine = new LinkedList<String>();
		
		StringReader reader = new StringReader(strToSplit);
		StreamTokenizer streamTokenizer = new StreamTokenizer(reader);
        
		// tokenizer setting - lower case and only alphabetic characters (a-z)
        streamTokenizer.whitespaceChars(0, 64);
        streamTokenizer.whitespaceChars(91, 96);
        streamTokenizer.whitespaceChars(123, 255);
        streamTokenizer.lowerCaseMode(true);

        while (streamTokenizer.nextToken() != StreamTokenizer.TT_EOF) {
			splittedLine.add(streamTokenizer.sval);
		}
        
		return splittedLine;
	}
	
	/**
	 * this method stems the list of list of string using the porter stemming algorithm
	 * @param utteranceWords
	 * @return the list of list of stemmed words
	 */
	private LinkedList<LinkedList<String>> stemStrLstLst(LinkedList<LinkedList<String>> utteranceWords) {
		LinkedList<LinkedList<String>> stemmedUtteranceWords = new LinkedList<LinkedList<String>>();
		
		for (LinkedList<String> line: utteranceWords) {
			LinkedList<String> stemmedLine = new LinkedList<String>();
			for (String word: line) {
				stemmedLine.add(stem(word));
			}
			stemmedUtteranceWords.add(stemmedLine);
		}
		
		return stemmedUtteranceWords;
	}
	
	public String stem(String strToStem) {
		String stemmedStr = null;
		Stemmer stemmer = new Stemmer();
		
		stemmer.add(strToStem.toCharArray(), strToStem.length());
		stemmer.stem();
		stemmedStr = stemmer.toString();
		
		return stemmedStr;
	}
	
}
