package iitb.cfilt.cpost.stemmer;

import iitb.cfilt.cpost.ConfigReader;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
//import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
import java.util.Vector;

/**
 * @author Dinesh Gadge
 *
 */
public class StemmerRuleReader {

	private static String suffixReplacementRuleFilename = "";
	private static String specialCharactersRuleFilename = "";
	private static String irregularVerbFilename = "";
	private static String uniqueSuffixReplacementRuleFilename = "";
	private static String auxiliaryVerbFilename = "";
	private static String derivationalMorphologyRuleFilename = "";
	private static String spellingVariationRuleFilename = "";
	
	private static String charametarSuff = "";
	private static String allSuff = "";
	private static String NounSuff = "";
	
	private static HashMap<String, HashMap<String, Vector<StemmerRule>>> suffixReplacementRuleHash = new HashMap<String, HashMap<String, Vector<StemmerRule>>>();
	private static HashMap<String, String> specialCharactersRuleHash = new HashMap<String, String>();
	private static HashMap<String, String> irregularVerbHash = new HashMap<String, String>();
	private static Vector<Vector<String>> irregularVerbVector = new Vector<Vector<String>>();
	private static HashMap<String, String> uniqueSuffixReplacementRuleHash = new HashMap<String, String>();
	private static HashMap<String, String> auxiliaryVerbHash = new HashMap<String, String>();
	private static HashMap<String, HashMap<String, Vector<String>>> derivationalMorphologyRuleHash = new HashMap<String, HashMap<String, Vector<String>>>(); 
	private static HashMap<String, String> spellingVariationRuleHash = new HashMap<String, String>();
	private static HashMap<String, Vector<String>> charametarSuffHash = new HashMap<String,Vector<String>>();
	private static HashMap<String, Vector<String>> allSuffHash = new HashMap<String,Vector<String>>();
	private static Vector<String> NounSuffList = new Vector<String>();
	private static Vector<String> SuffPriority = new Vector<String>();
	private static boolean populated = false;

	/**
	 * Default Constructor
	 */
	private StemmerRuleReader(){
		if(!suffixReplacementRuleFilename.equals(ConfigReader.get("Stemmer.suffixReplacementRuleFilename")) ||
				!specialCharactersRuleFilename.equals(ConfigReader.get("Stemmer.specialCharactersRuleFilename")) ||
				!irregularVerbFilename.equals(ConfigReader.get("Stemmer.irregularVerbFilename")) ||
				!uniqueSuffixReplacementRuleFilename.equals(ConfigReader.get("Stemmer.uniqueSuffixReplacementRuleFilename")) ||
				!auxiliaryVerbFilename.equals(ConfigReader.get("Lexicon.auxVerbFilename")) ||
				!derivationalMorphologyRuleFilename.equals(ConfigReader.get("Stemmer.derivationalMorphologyRuleFilename")) ||
				!charametarSuff.equals(ConfigReader.get("Stemmer.charametarSuff")) ||
				!allSuff.equals(ConfigReader.get("Stemmer.allSuff")) ||
				!NounSuff.equals(ConfigReader.get("Stemmer.NounSuff")) ||
				!spellingVariationRuleFilename.equals(ConfigReader.get("Lexicon.spellingVariationRuleFilename"))){
			populated = false;
		}
		if(!populated){
			suffixReplacementRuleFilename = ConfigReader.get("Stemmer.suffixReplacementRuleFilename");
			specialCharactersRuleFilename = ConfigReader.get("Stemmer.specialCharactersRuleFilename");
			irregularVerbFilename = ConfigReader.get("Stemmer.irregularVerbFilename");
			uniqueSuffixReplacementRuleFilename = ConfigReader.get("Stemmer.uniqueSuffixReplacementRuleFilename");
			auxiliaryVerbFilename = ConfigReader.get("Lexicon.auxVerbFilename");
			derivationalMorphologyRuleFilename = ConfigReader.get("Stemmer.derivationalMorphologyRuleFilename");
			spellingVariationRuleFilename = ConfigReader.get("Lexicon.spellingVariationRuleFilename");
			charametarSuff = ConfigReader.get("Stemmer.charametarSuff");
			allSuff = ConfigReader.get("Stemmer.allSuff");
			NounSuff = ConfigReader.get("Stemmer.NounSuff");
			createAllRules();
			populated = true;
		}
	}

	public static void populate(){
		//System.out.println("Stemmer");
		suffixReplacementRuleFilename = ConfigReader.get("Stemmer.suffixReplacementRuleFilename");
		specialCharactersRuleFilename = ConfigReader.get("Stemmer.specialCharactersRuleFilename");
		irregularVerbFilename = ConfigReader.get("Stemmer.irregularVerbFilename");
		uniqueSuffixReplacementRuleFilename = ConfigReader.get("Stemmer.uniqueSuffixReplacementRuleFilename");
		auxiliaryVerbFilename = ConfigReader.get("Lexicon.auxVerbFilename");
		derivationalMorphologyRuleFilename = ConfigReader.get("Stemmer.derivationalMorphologyRuleFilename");
		spellingVariationRuleFilename = ConfigReader.get("Lexicon.spellingVariationRuleFilename");
		charametarSuff = ConfigReader.get("Stemmer.charametarSuff");
		allSuff = ConfigReader.get("Stemmer.allSuff");
		NounSuff = ConfigReader.get("Stemmer.NounSuff");
		createAllRules();
	}

	/**
	 * This functions calls corresponding functions to read from different rule files  
	 */
	private static void createAllRules(){
		//System.out.println("SRR reading begins : " + new Timestamp(System.currentTimeMillis()));
		createRules(suffixReplacementRuleFilename);
		//System.out.println("SRR reading ends : " + new Timestamp(System.currentTimeMillis()));
		createRules(specialCharactersRuleFilename);
		createRules(irregularVerbFilename);
		createRules(uniqueSuffixReplacementRuleFilename);
		createRules(auxiliaryVerbFilename);
		createRules(derivationalMorphologyRuleFilename);
		createRules(spellingVariationRuleFilename);
		createRules(charametarSuff);
		createRules(allSuff);
		createRules(NounSuff);
	}

	/**
	 * This is a 'reader' function which reads opens the given file for reading and calls the 
	 * <code>hashIt(String line, String filename)</code> function to hash the lines which are 
	 * not 'comment-lines' and which are not 'empty-lines.'  
	 * @param filename Name of the rule file
	 */
	private static void createRules(String filename){
		try {
			BufferedReader bsrr = new BufferedReader(new InputStreamReader(new FileInputStream(filename), "UTF8"));
			String line = " ";

			while (line != null){
				line = bsrr.readLine();
				if(line != null){
					line = line.trim();
					if(line.length()!=0 && !line.startsWith("//")) // To ensure that line is not empty and line is not to be ignored.
						hashIt(line, filename);
				}
			}
			bsrr.close();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * This function calls the corresponding hashing function for different filenames. 
	 * @param line The line to be hashed
	 * @param filename The name of the file from which <code>line</code> has been taken
	 */
	private static void hashIt(String line, String filename){
		if(filename.equals(suffixReplacementRuleFilename)){
			hashSuffixReplacementRule(line);
		}
		if(filename.equals(specialCharactersRuleFilename)){
			hashSpecialCharactersRule(line);
		}
		if(filename.equals(irregularVerbFilename)){
			hashIrregularVerb(line);
		}
		if(filename.equals(uniqueSuffixReplacementRuleFilename)){
			hashUniqueSuffixReplacementRule(line);
		}
		if(filename.equals(auxiliaryVerbFilename)){
			hashAuxiliaryVerb(line);
		}
		if(filename.equals(derivationalMorphologyRuleFilename)){
			hashDerivationalMorphologyRule(line);
		}
		if(filename.equals(spellingVariationRuleFilename)){
			hashSpellingVariationRule(line);
		}
		if(filename.equals(charametarSuff)){
			hashCharametarSuff(line);
		}
		if(filename.equals(allSuff)){
			hashAllSuff(line);
		}
		if(filename.equals(NounSuff)){
			hashNounSuff(line);
		}
	}
	
	private static void hashNounSuff(String line)
	{
		String[] lineComponents = line.split(",");
		
		if(NounSuffList.indexOf(lineComponents[0].trim()) == -1)
		{
			NounSuffList.add(lineComponents[0].trim());
			SuffPriority.add(lineComponents[1].trim());
		}
	}

	private static void hashCharametarSuff(String line)
	{
		line = line.trim();
		String lastChar = line.substring(line.length()-1);
		if(charametarSuffHash.containsKey(lastChar))
		{
			Vector<String> temp = charametarSuffHash.get(lastChar);
			temp.add(line.trim());
			charametarSuffHash.put(lastChar,temp);
		}
		else
		{
			Vector<String> temp = new Vector<String>();
			temp.add(line.trim());
			charametarSuffHash.put(lastChar,temp);
		}
	}
	
	private static void hashAllSuff(String line)
	{
		line = line.trim();
		String lastChar = line.substring(line.length()-1);
		if(allSuffHash.containsKey(lastChar))
		{
			Vector<String> temp = allSuffHash.get(lastChar);
			temp.add(line.trim());
			allSuffHash.put(lastChar,temp);
		}
		else
		{
			Vector<String> temp = new Vector<String>();
			temp.add(line.trim());
			allSuffHash.put(lastChar,temp);
		}
	}
	
	
	private static void hashSpellingVariationRule(String line) {
		String[] lineComponents = line.split(",");
		if(lineComponents.length == 2){
			spellingVariationRuleHash.put(lineComponents[0].trim(), lineComponents[1].trim());
		}
		else{
			spellingVariationRuleHash.put(lineComponents[0].trim(), "");
		}
	}

	private static void hashDerivationalMorphologyRule(String line) {
		String[] lineComponents = line.trim().split(" ");
		String suffix = lineComponents[1].trim();
		String rootCat = lineComponents[3].trim();
		String newCat = lineComponents[5].trim();

		if(derivationalMorphologyRuleHash.containsKey(suffix)){
			HashMap<String, Vector<String>> rootCategoryToNewCatogoriesHash = derivationalMorphologyRuleHash.get(suffix);
			if(rootCategoryToNewCatogoriesHash.containsKey(rootCat)){
				Vector<String> newCategoriesVector = rootCategoryToNewCatogoriesHash.get(rootCat);
				String[] newCategories = newCat.split("\\,");
				for(int i = 0; i < newCategories.length; i++){
					if(!newCategoriesVector.contains(newCategories[i]))
						newCategoriesVector.add(newCategories[i]);
				}
			}
			else{
				String[] newCategories = newCat.split("\\,");
				Vector<String> newCategoriesVector = new Vector<String>();
				for(int i = 0; i < newCategories.length; i++){
					if(!newCategoriesVector.contains(newCategories[i]))
						newCategoriesVector.add(newCategories[i]);
				}
				rootCategoryToNewCatogoriesHash.put(rootCat, newCategoriesVector);
			}
		}
		else{
			HashMap<String, Vector<String>> rootCategoryToNewCatogoriesHash = new HashMap<String, Vector<String>>();
			String[] newCategories = newCat.split("\\,");
			Vector<String> newCategoriesVector = new Vector<String>();
			for(int i = 0; i < newCategories.length; i++){
				if(!newCategoriesVector.contains(newCategories[i]))
					newCategoriesVector.add(newCategories[i]);
			}
			rootCategoryToNewCatogoriesHash.put(rootCat, newCategoriesVector);
			derivationalMorphologyRuleHash.put(suffix, rootCategoryToNewCatogoriesHash);
		}

	}

	private static void hashAuxiliaryVerb(String line) {
		String[] lineComponents = line.split(StemmerRule.DELIMITER);
		auxiliaryVerbHash.put(lineComponents[0].trim(), "");
	}

	private static void hashUniqueSuffixReplacementRule(String line) {
		String[] lineComponents = line.split(StemmerRule.DELIMITER);
		uniqueSuffixReplacementRuleHash.put(lineComponents[1].trim(), "");
	}

	private static void hashIrregularVerb(String line) {
		String[] lineComponents = line.split(StemmerRule.DELIMITER);
		if(lineComponents.length == 4){
			String irregularForm = lineComponents[0].trim();
			String regularForm = lineComponents[1].trim();
			String paradigm = lineComponents[2].trim();
			String category = lineComponents[3].trim();
			
			Vector<String> temp = new Vector<String>();
			temp.add(irregularForm);
			temp.add(regularForm);
			temp.add(paradigm);
			temp.add(category);
			
			irregularVerbVector.add(temp);
			irregularVerbHash.put(irregularForm,regularForm);
			
			/*String irregularForm = lineComponents[0].trim();
			String regularForm[] = new String[2];
			regularForm[0] = lineComponents[1].trim();
			regularForm[1] = lineComponents[2].trim();
			irregularVerbHash.put(irregularForm, regularForm);
//			System.out.println(irregularForm+" "+regularForm);*/
		}
	}

	private static void hashSpecialCharactersRule(String line) {
		line = line.replaceFirst(",", "-split-");
		String[] lineComponents = line.split("-split-");
		String paradigm;
		String regex;
		if(lineComponents.length == 2){
			paradigm = lineComponents[0].trim();
			regex = lineComponents[1].trim();
		}
		else{
			paradigm = "";
			regex = lineComponents[0].trim();
		}
		specialCharactersRuleHash.put(regex, paradigm);
	}

	/**
	 * This function creates a 2 level hash. 
	 * First level hash is a map from last character of the suffix to another hash.
	 * This second level hash is a map from the actual suffix to a <code>Vector</code> of <code>StemmerRule</code>s
	 * @param line The line to be hashed
	 */
	private static void hashSuffixReplacementRule(String line){
		//System.err.println("Line : "+line);
		String[] lineComponents = line.split(StemmerRule.DELIMITER);
		String paradigm = lineComponents[0].trim();
		String suffix = lineComponents[1].trim();
		String ultimateInsertion = lineComponents[2].trim();
		String ultimateDeletion = lineComponents[3].trim();
		String penultimateInsertion = lineComponents[4].trim();
		String penultimateDeletion = lineComponents[5].trim();
		int priority = Integer.parseInt(lineComponents[6].trim());

		String lastChar = suffix.substring(suffix.length()-1);
		StemmerRule sr = new StemmerRule(paradigm, suffix, ultimateInsertion, ultimateDeletion, penultimateInsertion, penultimateDeletion, priority);

		if(suffixReplacementRuleHash.containsKey(lastChar)){
			HashMap<String, Vector<StemmerRule>> suffixStemmerRuleHash = suffixReplacementRuleHash.get(lastChar);
			if(suffixStemmerRuleHash.containsKey(suffix)){
				Vector<StemmerRule> srv = suffixStemmerRuleHash.get(suffix);
				if(!srv.contains(sr))
					srv.add(sr);
			}
			else{
				Vector<StemmerRule> srv = new Vector<StemmerRule>(); 
				srv.add(sr);
				suffixStemmerRuleHash.put(suffix, srv);
			}
		}
		else{
			Vector<StemmerRule> srv = new Vector<StemmerRule>(); 
			srv.add(sr);
			HashMap<String, Vector<StemmerRule>> suffixStemmerRuleHash = new HashMap<String, Vector<StemmerRule>>();
			suffixStemmerRuleHash.put(suffix, srv);
			suffixReplacementRuleHash.put(lastChar, suffixStemmerRuleHash);
		}
	}

//	public static Vector<StemmerRuleResult> applySuffixReplacementRulesOnHelper(String token){
//	System.out.println("Token : " + token);
//	Vector<StemmerRuleResult> retVal = applySuffixReplacementRulesOn(token);
//	if(retVal == null){
//	StemmerRuleResult tempResult = new StemmerRuleResult(token, "rootword", "", "");
//	retVal = new Vector<StemmerRuleResult>();
//	retVal.add(tempResult);
//	}
//	return retVal;
//	}

	/**
	 * This function applies all possible suffix replacement rules on the given token.
	 * 
	 * @param token The token on which rules are to be applied
	 * @return A <code>Vector</code> of results obtained on application of all possible rules.
	 */
	public static Vector<StemmerRuleResult> applySuffixReplacementRulesOn(String token){
		if(token.equals("")){
			return null;
		}
//		UTFConsole.out.println("applySuffixReplacementRules called with token : '" + token +"'");
		Vector<StemmerRuleResult> retVal = new Vector<StemmerRuleResult>();
//		UTFConsole.out.println("applying specialCharacterRules");

		/*Random Hack*/
		StemmerRuleResult specialCharacterResult = StemmerRuleReader.applySpecialCharacterRulesOn(token);
		if(specialCharacterResult != null){
//			UTFConsole.out.println("specialCharacterResult != null");
			retVal.add(specialCharacterResult);
		}
		else{
//			UTFConsole.out.println("specialCharacterResult == null");
		}
		/*Random Hack*/

		String lastChar = token.substring(token.length()-1);

		if(suffixReplacementRuleHash.containsKey(lastChar)){
			HashMap<String, Vector<StemmerRule>> suffixStemmerRuleHash = suffixReplacementRuleHash.get(lastChar);
			Set suffixes = suffixStemmerRuleHash.keySet();
			Iterator suffixIter = suffixes.iterator();
			retVal = new Vector<StemmerRuleResult>();
			while(suffixIter.hasNext()){
				String suffix = (String) suffixIter.next();
//				UTFConsole.out.println("Checking if " + token + " endsWith " + suffix);
				if(token.endsWith(suffix)){ 
//					System.out.println("Yes");
					boolean tokenIsSuffix = token.equals(suffix);

					Vector<StemmerRuleResult> tempRetVal = null;
					if(!tokenIsSuffix){
//						UTFConsole.out.println("Token is not suffix");
						tempRetVal = applySuffixReplacementRulesOn(token.replaceAll(suffix+"$", ""));

						StemmerRuleResult currentResult;
						if(tempRetVal != null){
							Iterator<StemmerRuleResult> tempRetValIter = tempRetVal.iterator();
							while(tempRetValIter.hasNext()){
								StemmerRuleResult temp = (StemmerRuleResult)tempRetValIter.next();
								
								/*Vector<StemmerRule> stemmerRules = suffixStemmerRuleHash.get(suffix);
								Iterator<StemmerRule> stemmerRulesIter = stemmerRules.iterator();
								StemmerRule currentRule = null;
								boolean flag = true;
								while(stemmerRulesIter.hasNext()){
									currentRule = stemmerRulesIter.next();
									if(temp.getParadigm().trim().equals(currentRule.getParadigm().trim()) && currentRule.getPriority() == 2)
									{
										flag = false;
										break;
									}
								}
								if(flag == true)
								{
									temp.addSuffix(suffix);
									retVal.add(temp);
								}*/
								temp.addSuffix(suffix);
//								System.out.println("Temp : " + temp.toString());
							}
							retVal.addAll(tempRetVal);
						}
//						else{
//						System.out.println("Got null, So applying all possible StemmerRules");
						Vector<StemmerRule> stemmerRules = suffixStemmerRuleHash.get(suffix);
						Iterator<StemmerRule> stemmerRulesIter = stemmerRules.iterator();
						StemmerRule currentRule = null;
						while(stemmerRulesIter.hasNext()){
							currentRule = stemmerRulesIter.next();
//							UTFConsole.out.println("Rule :: Paradigm : " + currentRule.getParadigm() +" Suffix : " + currentRule.suffix + " replacement : " + currentRule.ultimateInsertion);
							//New Code Begins
							String newToken = token.replaceAll(suffix+"$", "");
							boolean goFurther = false;
							currentResult = null;
							if(!currentRule.getUltimateDeletion().equals("")){
								if(newToken.endsWith(currentRule.getUltimateDeletion())){
									currentResult = currentRule.applyOn(newToken);
									goFurther = true;
								}
							}
							else{
								currentResult = currentRule.applyOn(newToken);
								goFurther = true;						
								
							}
							//New Code Ends
							if(goFurther && auxiliaryVerbHash.containsKey(currentResult.getRoot())){
								StemmerRuleResult newResult = new StemmerRuleResult(currentResult.getRoot(), "vaux", "verb_aux", "", currentRule.suffix);
								if(!retVal.contains(newResult)){
									retVal.add(newResult);
//									System.out.println("Added :: " + newResult.toString());
//									System.out.println("Rule :: Paradigm : " + currentRule.getParadigm() +" Suffix : " + currentRule.suffix + " replacement : " + currentRule.ultimateInsertion);
								}
							}
//							PrintStream out = null;
//							try {
//							out = new PrintStream(System.out, true, "UTF8");
//							} catch (UnsupportedEncodingException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//							}
//							out.println(currentResult);

							if(goFurther && !retVal.contains(currentResult)){
								retVal.add(currentResult);
//								System.out.println("Added :: " + currentResult.toString());
//								System.out.println("Rule :: Paradigm : " + currentRule.getParadigm() +" Suffix : " + currentRule.suffix + " replacement : " + currentRule.ultimateInsertion);
							}
						}
					}
				}
				else{
					// TODO Code needs to be added after testing if necessary
//					System.out.println("No");
				}
			}
			if(retVal.isEmpty()){
//				System.out.println("Returning null");
				retVal = null;
			}
		}
		return retVal;
	}
	
	
	public static boolean checkForSuffixPriority(String token, StemmerRuleResult currentResult)
	{
		
		
		if(currentResult.getSuffixList().size() > 1)
		{
			String suff = currentResult.getSuffixList().getLast().trim();
			
			if(suff.length() > 0)
			{
				String lastChar = suff.substring(suff.length()-1);
				HashMap<String, Vector<StemmerRule>> suffixStemmerRuleHash = suffixReplacementRuleHash.get(lastChar);
				
				Vector<StemmerRule> stemmerRules = suffixStemmerRuleHash.get(suff);
				Iterator<StemmerRule> stemmerRulesIter = stemmerRules.iterator();
				StemmerRule currentRule = null;
				while(stemmerRulesIter.hasNext())
				{
					currentRule = stemmerRulesIter.next();
					if(currentResult.getParadigm().trim().equals(currentRule.getParadigm().trim()))
						if(currentRule.getPriority() == 2)
							return(false);
						else if(currentRule.getPriority() != 2)
							return(true);
				}
			}
		}
		return(true);
		
	}
	
//*******************************************************************
	
	
	public static Vector<StemmerRuleResult> applySuffixReplacementRulesOn1(String token){
		if(token.equals("")){
			return null;
		}
//		UTFConsole.out.println("applySuffixReplacementRules called with token : '" + token +"'");
		Vector<StemmerRuleResult> retVal = new Vector<StemmerRuleResult>();
//		
		String lastChar = token.substring(token.length()-1);

		if(charametarSuffHash.containsKey(lastChar)){
			HashMap<String, Vector<StemmerRule>> suffixStemmerRuleHash = suffixReplacementRuleHash.get(lastChar);
			//Set suffixes = suffixStemmerRuleHash.keySet();
			
			
			
			
			Iterator suffixIter = charametarSuffHash.get(lastChar).iterator();
			retVal = new Vector<StemmerRuleResult>();
			while(suffixIter.hasNext()){
				String suffix = (String) suffixIter.next();
//				UTFConsole.out.println("Checking if " + token + " endsWith " + suffix);
				if(token.endsWith(suffix)){ 
//					System.out.println("Yes");
					boolean tokenIsSuffix = token.equals(suffix);

					Vector<StemmerRuleResult> tempRetVal = null;
					if(!tokenIsSuffix){
//						UTFConsole.out.println("Token is not suffix");
						tempRetVal = applySuffixReplacementRulesOn1(token.replaceAll(suffix+"$", ""));

						StemmerRuleResult currentResult;
						if(tempRetVal != null){
							Iterator<StemmerRuleResult> tempRetValIter = tempRetVal.iterator();
							while(tempRetValIter.hasNext()){
								StemmerRuleResult temp = (StemmerRuleResult)tempRetValIter.next();
								temp.addSuffix(suffix);
//								System.out.println("Temp : " + temp.toString());
							}
							retVal.addAll(tempRetVal);
						}
//						else{
//						System.out.println("Got null, So applying all possible StemmerRules");
						Vector<StemmerRule> stemmerRules = suffixStemmerRuleHash.get(suffix);
						Iterator<StemmerRule> stemmerRulesIter = stemmerRules.iterator();
						StemmerRule currentRule = null;
						while(stemmerRulesIter.hasNext()){
							currentRule = stemmerRulesIter.next();
//							UTFConsole.out.println("Rule :: Paradigm : " + currentRule.getParadigm() +" Suffix : " + currentRule.suffix + " replacement : " + currentRule.ultimateInsertion);
							//New Code Begins
							String newToken = token.replaceAll(suffix+"$", "");
							boolean goFurther = false;
							currentResult = null;
							if(!currentRule.getUltimateDeletion().equals("")){
								if(newToken.endsWith(currentRule.getUltimateDeletion())){
									currentResult = currentRule.applyOn(newToken);
									goFurther = true;
								}
							}
							else{
								currentResult = currentRule.applyOn(newToken);
								goFurther = true;						
								
							}
							//New Code Ends
							if(goFurther && auxiliaryVerbHash.containsKey(currentResult.getRoot())){
								StemmerRuleResult newResult = new StemmerRuleResult(currentResult.getRoot(), "vaux", "verb_aux", "", currentRule.suffix);
								if(!retVal.contains(newResult)){
									retVal.add(newResult);
//									System.out.println("Added :: " + newResult.toString());
//									System.out.println("Rule :: Paradigm : " + currentRule.getParadigm() +" Suffix : " + currentRule.suffix + " replacement : " + currentRule.ultimateInsertion);
								}
							}
//							PrintStream out = null;
//							try {
//							out = new PrintStream(System.out, true, "UTF8");
//							} catch (UnsupportedEncodingException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//							}
//							out.println(currentResult);

							if(goFurther && !retVal.contains(currentResult)){
								retVal.add(currentResult);
//								System.out.println("Added :: " + currentResult.toString());
//								System.out.println("Rule :: Paradigm : " + currentRule.getParadigm() +" Suffix : " + currentRule.suffix + " replacement : " + currentRule.ultimateInsertion);
							}
						}
					}
				}
				else{
					// TODO Code needs to be added after testing if necessary
//					System.out.println("No");
				}
			}
			if(retVal.isEmpty()){
//				System.out.println("Returning null");
				retVal = null;
			}
		}
		return retVal;
	}
	
	
	public static Vector<StemmerRuleResult> applySuffixReplacementRulesOn2(String token)
	{
		if(token.equals("")){
			return null;
		}
		Vector<StemmerRuleResult> retVal = new Vector<StemmerRuleResult>();
		StemmerRuleResult specialCharacterResult = StemmerRuleReader.applySpecialCharacterRulesOn(token);
		if(specialCharacterResult != null){
//			UTFConsole.out.println("specialCharacterResult != null");
			retVal.add(specialCharacterResult);
		}
		
		String lastChar = token.substring(token.length()-1);
		if(allSuffHash.containsKey(lastChar))
		{
			HashMap<String, Vector<StemmerRule>> suffixStemmerRuleHash = suffixReplacementRuleHash.get(lastChar);
			//Set suffixes = suffixStemmerRuleHash.keySet();
			
			
			Iterator suffixIter = allSuffHash.get(lastChar).iterator();
			
			retVal = new Vector<StemmerRuleResult>();
			
			Vector<String> validSuff = new Vector<String>();
			
			while(suffixIter.hasNext())
			{
				String suffix = (String) suffixIter.next();
				if(token.endsWith(suffix))
					validSuff.add(suffix);
			}
			for(int i=0;i<validSuff.size();i++)
			{
				boolean tokenIsSuffix = token.equals(validSuff.get(i));

				Vector<StemmerRuleResult> tempRetVal = null;
				if(!tokenIsSuffix)
				{
//					UTFConsole.out.println("Token is not suffix");
					tempRetVal = applySuffixReplacementRulesOn1(token.replaceAll(validSuff.get(i)+"$", ""));

					StemmerRuleResult currentResult;
					if(tempRetVal != null)
					{
						Iterator<StemmerRuleResult> tempRetValIter = tempRetVal.iterator();
						while(tempRetValIter.hasNext()){
							StemmerRuleResult temp = (StemmerRuleResult)tempRetValIter.next();
							temp.addSuffix(validSuff.get(i));
//							System.out.println("Temp : " + temp.toString());
						}
						retVal.addAll(tempRetVal);
					}
					
					Vector<StemmerRule> stemmerRules = suffixStemmerRuleHash.get(validSuff.get(i));
					Iterator<StemmerRule> stemmerRulesIter = stemmerRules.iterator();
					StemmerRule currentRule = null;
					while(stemmerRulesIter.hasNext()){
						currentRule = stemmerRulesIter.next();
//						UTFConsole.out.println("Rule :: Paradigm : " + currentRule.getParadigm() +" Suffix : " + currentRule.suffix + " replacement : " + currentRule.ultimateInsertion);
						//New Code Begins
						String newToken = token.replaceAll(validSuff.get(i)+"$", "");
						boolean goFurther = false;
						currentResult = null;
						if(!currentRule.getUltimateDeletion().equals("")){
							if(newToken.endsWith(currentRule.getUltimateDeletion())){
								currentResult = currentRule.applyOn(newToken);
								goFurther = true;
							}
						}
						else{
							currentResult = currentRule.applyOn(newToken);
							goFurther = true;						
							
						}
						//New Code Ends
						if(goFurther && auxiliaryVerbHash.containsKey(currentResult.getRoot())){
							StemmerRuleResult newResult = new StemmerRuleResult(currentResult.getRoot(), "vaux", "verb_aux", "", currentRule.suffix);
							if(!retVal.contains(newResult)){
								retVal.add(newResult);
//								System.out.println("Added :: " + newResult.toString());
//								System.out.println("Rule :: Paradigm : " + currentRule.getParadigm() +" Suffix : " + currentRule.suffix + " replacement : " + currentRule.ultimateInsertion);
							}
						}
//						PrintStream out = null;
//						try {
//						out = new PrintStream(System.out, true, "UTF8");
//						} catch (UnsupportedEncodingException e) {
//						// TODO Auto-generated catch block
//						e.printStackTrace();
//						}
//						out.println(currentResult);

						if(goFurther && !retVal.contains(currentResult)){
							retVal.add(currentResult);
//							System.out.println("Added :: " + currentResult.toString());
//							System.out.println("Rule :: Paradigm : " + currentRule.getParadigm() +" Suffix : " + currentRule.suffix + " replacement : " + currentRule.ultimateInsertion);
						}
					}
				}
			}
		}
		
		return retVal;
	}
	
	
//*******************************************************************
	
	
	
	

	public static StemmerRuleResult applySpecialCharacterRulesOn(String token) {
		StemmerRuleResult retVal = null;
		Set<String> regexes = specialCharactersRuleHash.keySet();
		Iterator regexesIter = regexes.iterator();
		while(regexesIter.hasNext()){
			String regex = (String) regexesIter.next();
			if(token.matches(regex)){
				String paradigm = specialCharactersRuleHash.get(regex);
				//if(token.equals("\u002E") || token.equals("\u0964") || token.equals("\u003F"))
					//paradigm = "END";
				retVal = new StemmerRuleResult(token, paradigm, paradigm, "", "");
			}
		}
		return retVal;
	}
	
//******************************************************************	
	
	public static Vector<StemmerRuleResult> checkForNounSuffixes(String token)
	{
		Vector<StemmerRuleResult> retval = new Vector<StemmerRuleResult>();
		token = token.trim();
		
		LinkedList<String> SuffList = new LinkedList<String>();
		String maxSuff = "";
		//int maxSuffPos = 0;
		int iter = 0;
		int flag = 0;
		while(true)
		{
			if(flag == 1)
				break;
			if(iter == 0)
			{
				maxSuff = "";
				for(int i=0;i<NounSuffList.size();i++)
				{
					if(token.endsWith(NounSuffList.get(i).trim()) && SuffPriority.get(i).trim().equals("p"))
					{
						if(NounSuffList.get(i).trim().length() > maxSuff.length())
							maxSuff = NounSuffList.get(i).trim();
					}
				}
				if(maxSuff != "")
				{
					token = token.replaceAll(maxSuff+"$","");
					if(token.endsWith("्"))
						token = token.concat(maxSuff);
					else if(token.length() <= 2)
						token = token.concat(maxSuff);
					else
						SuffList.add(maxSuff);
				}
			}
			else if(iter == 1)
			{
				maxSuff = "";
				for(int i=0;i<NounSuffList.size();i++)
				{
					if(token.endsWith(NounSuffList.get(i).trim()) && !SuffPriority.get(i).trim().equals("p"))
					{
						if(NounSuffList.get(i).trim().length() > maxSuff.length())
							maxSuff = NounSuffList.get(i).trim();
					}
				}
				if(maxSuff != "")
				{
					token = token.replaceAll(maxSuff+"$","");
					if(maxSuff.equals("त") && token.endsWith("ा") == false)
					{
						token = token + "त";
						flag = 1;
					}
					else if(token.endsWith("्"))
					{
						token = token.concat(maxSuff);
						flag = 1;
					}
					else if(token.length() <= 2)
					{
						token = token.concat(maxSuff);
						flag = 1;
					}
					else
						SuffList.add(maxSuff);
				}
				else
					flag = 1;
			}
			else
			{
				maxSuff = "";
				for(int i=0;i<NounSuffList.size();i++)
				{
					if(token.endsWith(NounSuffList.get(i).trim()) && SuffPriority.get(i).trim().equals("3"))
					{
						if(NounSuffList.get(i).trim().length() > maxSuff.length())
							maxSuff = NounSuffList.get(i).trim();
					}
				}
				if(maxSuff != "")
				{
					token = token.replaceAll(maxSuff+"$","");
					if(token.endsWith("्"))
					{
						token = token.concat(maxSuff);
						flag = 1;
					}
					else if(token.length() <= 2)
					{
						token = token.concat(maxSuff);
						flag = 1;
					}
					else
						SuffList.add(maxSuff);
				}
				else
					flag = 1;
			}
			iter++;
		}
		
		if(SuffList.size() != 0 && SuffPriority.get(NounSuffList.indexOf(SuffList.getLast().trim())).trim().equals("2"))
		{
			String tmp = SuffList.getLast().trim();
			SuffList.removeLast();
			token = token.concat(tmp);
		}
		
		//Hacking Code
		String token1 = "";
		String ud = "";
		if(SuffList.size() != 0)
		{
			if(token.endsWith("्या".trim()))
			{
				token = token.replaceAll("्या"+"$","ा");
				ud = "्या";
			}
			else if(token.endsWith("्यां".trim()))
			{
				token = token.replaceAll("्यां"+"$","ा");
				ud = "्यां";
			}
			else if(token.endsWith("ा"))
			{
				token1 = token.replaceAll("ा"+"$","");
				retval.add(new StemmerRuleResult(token1, "ppppp", "noun", ud, SuffList));
				ud = "ा";
			}
			else if(token.endsWith("ां"))
			{
				token = token.replaceAll("ां"+"$","");
				ud = "ां";
			}
			else if(token.endsWith("ं"))
			{
				token = token.replaceAll("ं"+"$","");
				ud = "ं";
			}
		}
		//Hacking Code ends
	
		
		if(SuffList.size() == 0)
			retval.add(new StemmerRuleResult(token, "unknown", "unknown", "", ""));
		else
			retval.add(new StemmerRuleResult(token, "ppppp", "pnoun", ud, SuffList));
			//retval.add(new StemmerRuleResult(token, "ppppp", "noun", ud, SuffList));

		
		return retval;
	}

//******************************************************************
	
	public static boolean hasRegularRootForm(String token) {
		return irregularVerbHash.containsKey(token);
		
		/*for(int i=0;i<irregularVerbVector.size();i++)
		{
			if(irregularVerbVector.get(i).get(0).trim().equals(token))
				return(true);
		}
		return(false);*/
	}

	public static Vector<Vector<String>> getRegularRootForm(String irregularForm) {
		//return irregularVerbHash.get(irregularForm);
		
		Vector<Vector<String>> retval = new Vector<Vector<String>>();		
		for(int i=0;i<irregularVerbVector.size();i++)
		{
			if(irregularVerbVector.get(i).get(0).trim().equals(irregularForm))
			{
				retval.add(irregularVerbVector.get(i));
			}
		}
		
		return(retval);
	}

	public static boolean hasUniqueSuffix(LinkedList<String> suffixes) {
		boolean retVal = false;
		Iterator suffixesIter = suffixes.iterator();
		while(suffixesIter.hasNext()){
			String currentSuffix = (String)suffixesIter.next();
			if(uniqueSuffixReplacementRuleHash.containsKey(currentSuffix)){
				retVal = true;
				break;
			}
		}
		return retVal;
	}

	public static String getUniqueSuffix(LinkedList<String> suffixes) {
		String retVal = "";
		Iterator suffixesIter = suffixes.iterator();
		while(suffixesIter.hasNext()){
			String currentSuffix = (String)suffixesIter.next();
			if(currentSuffix.length() > retVal.length() && uniqueSuffixReplacementRuleHash.containsKey(currentSuffix)){
				retVal = currentSuffix;
			}
		}
		return retVal;
	}

	public static boolean isAuxiliary(String token) {
		return auxiliaryVerbHash.containsKey(token);
	}

	public static Vector<String[]> checkDerivationalMorphology(String token) {
		Vector<String[]> retVal = new Vector<String[]>();
		Set suffixes = derivationalMorphologyRuleHash.keySet();

		String currentSuffix;
		Iterator suffixesIter = suffixes.iterator();

		while(suffixesIter.hasNext()){
			currentSuffix = (String)suffixesIter.next();
			if(token.endsWith(currentSuffix)){
				String root = token.replaceAll(currentSuffix + "$", "");
				HashMap<String, Vector<String>> rootCatToNewCatsHash = derivationalMorphologyRuleHash.get(currentSuffix);

				Set rootCategories = rootCatToNewCatsHash.keySet();
				String currentRootCategory;
				Vector<String> newCategoriesVector;
				Iterator rootCategoriesIter = rootCategories.iterator();

				String[] properties = new String[3];

				while(rootCategoriesIter.hasNext()){
					currentRootCategory = (String)rootCategoriesIter.next();
					newCategoriesVector = rootCatToNewCatsHash.get(currentRootCategory);
					for(int i = 0; i < newCategoriesVector.size(); i++){
						properties[0] = root;
						properties[1] = currentRootCategory;
						properties[2] = newCategoriesVector.get(i);
						retVal.add(properties);
					}
				}
			}
		}
		if(retVal.size() == 0){
			retVal = null;
		}
		return retVal;
	}

	public static Vector<String> getSpellingVariations(String token) {
		Vector<String> retVal = new Vector<String>();

		Set chars = spellingVariationRuleHash.keySet();
		Iterator charsIter = chars.iterator();

		while(charsIter.hasNext()){
			String currentChar = (String) charsIter.next();
			if(token.contains(currentChar)){
				// TODO Refine this.
				retVal.add(token.replaceAll(currentChar, spellingVariationRuleHash.get(currentChar)));
			}
		}

		if(retVal.size() == 0){
			retVal = null;
		}
		return retVal;
	}

	public static void main(String args[]){
		ConfigReader.read("Resources/hindiConfig");
		//StemmerRuleReader srreader = new StemmerRuleReader();
		StemmerRuleReader.createAllRules();

//		try {
//		BufferedReader bfr = new BufferedReader(new InputStreamReader(new FileInputStream("Resources/hindiTokens"), "UTF8"));
//		String token = null;
//		token = bfr.readLine();
//		while(token != null){
//		Vector<StemmerRuleResult> srresult = StemmerRuleReader.applySuffixReplacementRulesOnHelper(token);
//		for(int i=0; i < srresult.size(); i++){
//		System.out.println(srresult.elementAt(i).toString());
//		}
//		token = bfr.readLine();
//		}
//		} catch (FileNotFoundException e) {
//		e.printStackTrace();
//		} catch (IOException e) {
//		e.printStackTrace();
//		}
	}	
}
