package iitb.cfilt.cpost.newstemmer;

import iitb.cfilt.cpost.ConfigReader;
import iitb.cfilt.cpost.lexicon.*;


import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
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 String suffixReplacementRuleFilename = "";
	private String specialCharactersRuleFilename = "";
	private String irregularVerbFilename = "";
	//private String uniqueSuffixReplacementRuleFilename = "";
	//private String auxiliaryVerbFilename = "";
	private String derivationalMorphologyRuleFilename = "";
	private String spellingVariationRuleFilename = "";
	private String suffixesFilename = "";
	//private String charametarSuff = "";
	//private String allSuff = "";
	private String NounSuff = "";
	private String particleFilename = "";
	/*******************************/
	/* Nikhilesh */
	private String auxSuffixRuleFileName="";
	private String newSuffixReplacementRuleFilename = "";
	private String newIrregularVerbFilename = "";
	private String newSuffixesFilename = "";
	private HashMap<String, HashMap<String, HashMap<String, Vector<String>>>> newSuffixesHash = new HashMap<String, HashMap<String, HashMap<String, Vector<String>>>>();
	private HashMap<String, HashMap<String, Vector<StemmerRule>>> newSuffixReplacementRuleHash = new HashMap<String, HashMap<String, Vector<StemmerRule>>>();
	private HashMap<String, HashMap<String, Vector<String>>> newIrregularVerbHash = new HashMap<String, HashMap<String, Vector<String>>>();
	private HashMap<String, HashMap<String, Vector<String>>> auxSuffixNextTokenRuleHash = new HashMap<String, HashMap<String, Vector<String>>>();
	private HashMap<String, HashMap<String, Vector<String>>> auxSuffixNextRootRuleHash = new HashMap<String, HashMap<String, Vector<String>>>();
	/* Nikhilesh */
	/*******************************/
	private HashMap<String, HashMap<String, Vector<StemmerRule>>> suffixReplacementRuleHash = new HashMap<String, HashMap<String, Vector<StemmerRule>>>();
	private HashMap<String, HashMap<String, HashMap<String,Vector<String>>>> suffixesHash = new HashMap<String, HashMap<String, HashMap<String,Vector<String>>>>();
	private HashMap<String, String> specialCharactersRuleHash = new HashMap<String, String>();
	private HashMap<String, String> irregularVerbHash = new HashMap<String, String>();
	private Vector<Vector<String>> irregularVerbVector = new Vector<Vector<String>>();
	//private HashMap<String, String> uniqueSuffixReplacementRuleHash = new HashMap<String, String>();
	//private HashMap<String, String> auxiliaryVerbHash = new HashMap<String, String>();
	private HashMap<String, HashMap<String, Vector<String>>> derivationalMorphologyRuleHash = new HashMap<String, HashMap<String, Vector<String>>>(); 
	private HashMap<String, String> spellingVariationRuleHash = new HashMap<String, String>();
	//private HashMap<String, Vector<String>> charametarSuffHash = new HashMap<String,Vector<String>>();
	//private HashMap<String, Vector<String>> allSuffHash = new HashMap<String,Vector<String>>();
	private Vector<String> NounSuffList = new Vector<String>();
	private Vector<String> SuffPriority = new Vector<String>();
	private Vector<String> particles = new Vector<String>();
	private static Vector<String> particlesStatic = new Vector<String>();
	private static Vector<String> suffixesList = new Vector<String>();
	private boolean populated = false;
	private static HashMap<String, HashMap<String, HashMap<String,Vector<String>>>> suffixesHashStatic = new HashMap<String, HashMap<String, HashMap<String,Vector<String>>>>();
	//private static HashMap<String,Vector<String>> nounSuffixes = new HashMap<String,Vector<String>>();
	private boolean multiSuffix = false; /* Nikhilesh */
	
	/**
	 * Default Constructor
	 */
	public StemmerRuleReader()
	{
			suffixReplacementRuleFilename = ConfigReader.get("NewStemmer.suffixReplacementRuleFilename");
			suffixesFilename = ConfigReader.get("NewStemmer.suffixesFilename");
			newSuffixReplacementRuleFilename = ConfigReader.get("NewStemmer.newSuffixReplacementRuleFilename");
			newSuffixesFilename = ConfigReader.get("NewStemmer.newSuffixesFilename");
			newIrregularVerbFilename = ConfigReader.get("Stemmer.newIrregularVerbFilename");
			specialCharactersRuleFilename = ConfigReader.get("Stemmer.specialCharactersRuleFilename");
			irregularVerbFilename = ConfigReader.get("Stemmer.irregularVerbFilename");
			derivationalMorphologyRuleFilename = ConfigReader.get("Stemmer.derivationalMorphologyRuleFilename");
			particleFilename = ConfigReader.get("NewStemmer.particlesFile");
			spellingVariationRuleFilename = ConfigReader.get("Lexicon.spellingVariationRuleFilename");
			auxSuffixRuleFileName = ConfigReader.get("Stemmer.AuxSuffixFile");
	}

	public void populate(){
		//System.out.println("Stemmer");
		if(!populated)
		{
			suffixReplacementRuleFilename = ConfigReader.get("NewStemmer.suffixReplacementRuleFilename");
			suffixesFilename = ConfigReader.get("NewStemmer.suffixesFilename");
			specialCharactersRuleFilename = ConfigReader.get("Stemmer.specialCharactersRuleFilename");
			irregularVerbFilename = ConfigReader.get("Stemmer.irregularVerbFilename");
			newSuffixReplacementRuleFilename = ConfigReader.get("NewStemmer.newSuffixReplacementRuleFilename");
			newSuffixesFilename = ConfigReader.get("NewStemmer.newSuffixesFilename");
			newIrregularVerbFilename = ConfigReader.get("Stemmer.newIrregularVerbFilename");
			//uniqueSuffixReplacementRuleFilename = ConfigReader.get("Stemmer.uniqueSuffixReplacementRuleFilename");
			//auxiliaryVerbFilename = ConfigReader.get("Lexicon.auxVerbFilename");
			derivationalMorphologyRuleFilename = ConfigReader.get("Stemmer.derivationalMorphologyRuleFilename");
			particleFilename = ConfigReader.get("NewStemmer.particlesFile");
			spellingVariationRuleFilename = ConfigReader.get("Lexicon.spellingVariationRuleFilename");
			//charametarSuff = ConfigReader.get("Stemmer.charametarSuff");
			//allSuff = ConfigReader.get("Stemmer.allSuff");
			NounSuff = ConfigReader.get("Stemmer.NounSuff");
			auxSuffixRuleFileName = ConfigReader.get("Stemmer.AuxSuffixFile");
			createAllRules();
			buildSuffixList();
		}
	}

	public void populate(String baseDir){
		//System.out.println("Stemmer");
		if(!populated)
		{
			suffixReplacementRuleFilename = baseDir + ConfigReader.get("NewStemmer.suffixReplacementRuleFilename");
			suffixesFilename = baseDir + ConfigReader.get("NewStemmer.suffixesFilename");
			specialCharactersRuleFilename = baseDir + ConfigReader.get("Stemmer.specialCharactersRuleFilename");
			irregularVerbFilename = baseDir + ConfigReader.get("Stemmer.irregularVerbFilename");
			newSuffixReplacementRuleFilename = ConfigReader.get("NewStemmer.newSuffixReplacementRuleFilename");
			newSuffixesFilename = ConfigReader.get("NewStemmer.newSuffixesFilename");
			newIrregularVerbFilename = ConfigReader.get("Stemmer.newIrregularVerbFilename");
			//uniqueSuffixReplacementRuleFilename = ConfigReader.get("Stemmer.uniqueSuffixReplacementRuleFilename");
			//auxiliaryVerbFilename = ConfigReader.get("Lexicon.auxVerbFilename");
			derivationalMorphologyRuleFilename = baseDir + ConfigReader.get("Stemmer.derivationalMorphologyRuleFilename");
			particleFilename = baseDir + ConfigReader.get("NewStemmer.particlesFile");
			spellingVariationRuleFilename = ConfigReader.get("Lexicon.spellingVariationRuleFilename");
			//charametarSuff = ConfigReader.get("Stemmer.charametarSuff");
			//allSuff = ConfigReader.get("Stemmer.allSuff");
			NounSuff = baseDir + ConfigReader.get("Stemmer.NounSuff");
			auxSuffixRuleFileName = baseDir + ConfigReader.get("Stemmer.AuxSuffixFile");
			createAllRules();
			buildSuffixList();
		}
	}
	
	/**
	 * This functions calls corresponding functions to read from different rule files  
	 */
	private void createAllRules(){
		//System.out.println("SRR reading begins : " + new Timestamp(System.currentTimeMillis()));
		createRules(suffixReplacementRuleFilename);
		createRules(suffixesFilename);
		
		createRules(newSuffixReplacementRuleFilename);
		createRules(newSuffixesFilename);
		createRules(newIrregularVerbFilename);
		//System.out.println("SRR reading ends : " + new Timestamp(System.currentTimeMillis()));
		createRules(specialCharactersRuleFilename);
		createRules(irregularVerbFilename);
		//createRules(uniqueSuffixReplacementRuleFilename);
		//createRules(auxiliaryVerbFilename);
		createRules(derivationalMorphologyRuleFilename);
		createRules(particleFilename);
		createRules(spellingVariationRuleFilename);
		//createRules(charametarSuff);
		//createRules(allSuff);
		createRules(NounSuff);
		createRules(auxSuffixRuleFileName);
	}

	/**
	 * 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 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 void hashIt(String line, String filename){
		if(filename.equals(suffixReplacementRuleFilename)){
			hashSuffixReplacementRule(line);
		}
		
		else if(filename.equals(suffixesFilename)){
			hashSuffixes(line);
		}
		
		else if(filename.equals(newSuffixReplacementRuleFilename)){
			hashNewSuffixReplacementRule(line);
		}
		
		else if(filename.equals(newSuffixesFilename)){
			hashNewSuffixes(line);
		}
		
		else if(filename.equals(specialCharactersRuleFilename)){
			hashSpecialCharactersRule(line);
		}
		else if(filename.equals(irregularVerbFilename)){
			hashIrregularVerb(line);
		}
		else if(filename.equals(newIrregularVerbFilename)){
			hashNewIrregularVerb(line);
		}
		else if(filename.equals(derivationalMorphologyRuleFilename)){
			hashDerivationalMorphologyRule(line);
		}
		
		else if(filename.equals(particleFilename))
		{
			hashParticles(line);
		}
		else if(filename.equals(NounSuff)){
			hashNounSuff(line);
		}
		else if(filename.equals(spellingVariationRuleFilename))
		{
			hashSpellingVariationRule(line);
		}
		else if(filename.equals(auxSuffixRuleFileName))
		{
			hashAuxSuffixRule(line);
		}
		
	}
	
	/************************************************************/
	/* Nikhilesh */
	private void hashNewSuffixReplacementRule(String line){
		String[] lineComponents = line.split(StemmerRule.DELIMITER);
		String category = lineComponents[0].trim();
		String paradigm = 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 suffixToReplace = lineComponents[7].trim();;
		String suffix = "";		
		if(lineComponents.length == 9)
		{
			suffix = lineComponents[8].trim();
		}		
		StemmerRule sr = new StemmerRule(paradigm, category, ultimateInsertion, ultimateDeletion, penultimateInsertion, penultimateDeletion, suffixToReplace, priority, suffix);

		if(newSuffixReplacementRuleHash.containsKey(category)){
			HashMap<String, Vector<StemmerRule>> suffixStemmerRuleHash = newSuffixReplacementRuleHash.get(category);
			if(suffixStemmerRuleHash.containsKey(paradigm)){
				Vector<StemmerRule> srv = suffixStemmerRuleHash.get(paradigm);
				//if(!srv.contains(sr))
					srv.add(sr);
			}
			else{
				Vector<StemmerRule> srv = new Vector<StemmerRule>(); 
				srv.add(sr);
				suffixStemmerRuleHash.put(paradigm, srv);
			}
		}
		else{
			Vector<StemmerRule> srv = new Vector<StemmerRule>(); 
			srv.add(sr);
			HashMap<String, Vector<StemmerRule>> suffixStemmerRuleHash = new HashMap<String, Vector<StemmerRule>>();
			suffixStemmerRuleHash.put(paradigm, srv);
			newSuffixReplacementRuleHash.put(category, suffixStemmerRuleHash);
		}
	}
	
	private void hashNewSuffixes(String line){
		String[] lineComponents = line.split(StemmerRule.DELIMITER);
		if(lineComponents.length == 4 ){
			String category = lineComponents[0].trim();
			String type = lineComponents[1].trim();
			String suffix = lineComponents[2].trim();
			String flag = lineComponents[3].trim();
			if(newSuffixesHash.containsKey(category)){
				HashMap<String, HashMap<String, Vector<String>>> catHash = newSuffixesHash.get(category);
				if(catHash.containsKey(type)){
					HashMap<String, Vector<String>> typeHash = catHash.get(type);
					if(typeHash.containsKey(flag)){
						Vector<String> suffixes = typeHash.get(flag);
						suffixes.add(suffix);
						//typeHash.put(arg0, arg1)
					}
					else{
						Vector<String> suffixes = new Vector<String>();
						suffixes.add(suffix);
						typeHash.put(flag, suffixes);
					}
				}
				else{
					Vector<String> suffixes = new Vector<String>();
					suffixes.add(suffix);
					HashMap<String, Vector<String>> typeHash = new HashMap<String, Vector<String>>();
					typeHash.put(flag, suffixes);
					catHash.put(type,typeHash);
				}
			}
			else{
				Vector<String> suffixes = new Vector<String>();
				suffixes.add(suffix);
				HashMap<String, Vector<String>> typeHash = new HashMap<String, Vector<String>>();
				typeHash.put(flag, suffixes);
				HashMap<String, HashMap<String, Vector<String>>> catHash = new HashMap<String, HashMap<String, Vector<String>>>();				
				catHash.put(type, typeHash);
				newSuffixesHash.put(category, catHash);
			}
		}
	}
	
	private void hashNewIrregularVerb(String line){
		String[] lineComponents = line.split(StemmerRule.DELIMITER);
		if(lineComponents.length == 4 || lineComponents.length == 5){
			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);
			if(newIrregularVerbHash.containsKey(category)){
				HashMap<String, Vector<String>> catHash = newIrregularVerbHash.get(category);
				catHash.put(irregularForm, temp);
			}
			else{
				HashMap<String, Vector<String>> catHash = new HashMap<String, Vector<String>>();
				catHash.put(irregularForm, temp);
				newIrregularVerbHash.put(category, catHash);
			}
			//newIrregularVerbHash.put(irregularForm,temp);
		}
	}	
	/* Nikhilesh */
	/************************************************************/
	/************************************************************/
	/* Nikhilesh */
	private void hashAuxSuffixRule(String line){
		boolean next_is_token = true;
		if(line.equalsIgnoreCase("Next-is-Token")){		
			next_is_token = true;
		}
		else if(line.equalsIgnoreCase("Next-is-Root")){
			next_is_token = false;
		}
		else{
			HashMap<String, HashMap <String, Vector<String>>> tmpHash;
			if(next_is_token){
				tmpHash = auxSuffixNextTokenRuleHash;
			}
			else{
				tmpHash = auxSuffixNextRootRuleHash;
			}
			String[] lineComponents = line.trim().split("/");
			String auxList = lineComponents[0].trim();
			String suffixList = lineComponents[1].trim();
			String nextAuxList = "Null";
			//System.out.println(lineComponents.length);			
			boolean nextAux = false;
			if(lineComponents.length == 3){
				nextAux = true;
				nextAuxList = lineComponents[2].trim();
			}
			//System.out.println(auxList + "\t" + suffixList + "\t" + nextAuxList);
			String[] aux = auxList.trim().split(",");
			String[] suffixes = suffixList.trim().split(",");
			Vector<String> next_aux = new Vector<String>();
			if(nextAux){
				String nextaux[] = nextAuxList.trim().split(",");
				for(int k=0; k<nextaux.length; k++){
					if(nextaux[k]!="" && nextaux[k].trim()!=" ")
						next_aux.add(nextaux[k].trim());
				}
			}
			for(int i = 0; i < aux.length; i++){
				String curAux = aux[i].trim();
				
				if(tmpHash.containsKey(curAux)){
					HashMap<String, Vector<String>> aux_suffixRuleHash = tmpHash.get(curAux);
					for(int j = 0; j < suffixes.length; j++){
						String curSuffix = suffixes[j].trim();
						if(curSuffix!="" && curSuffix!=" "){
							if(aux_suffixRuleHash.containsKey(curSuffix)){						
								Vector<String> curNextAuxList = aux_suffixRuleHash.get(curSuffix);						
								curNextAuxList.addAll(next_aux);					
							}
							else{
								aux_suffixRuleHash.put(curSuffix, next_aux);
							}
						}
					}
				}
				else{
					HashMap<String, Vector<String>> aux_suffixRuleHash = new HashMap<String, Vector<String>>();
					for(int j = 0; j < suffixes.length; j++){
						String curSuffix = suffixes[j].trim();
						if(curSuffix!="" && curSuffix!=" "){
							if(aux_suffixRuleHash.containsKey(curSuffix)){						
								Vector<String> curNextAuxList = aux_suffixRuleHash.get(curSuffix);						
								curNextAuxList.addAll(next_aux);					
							}
							else{
								aux_suffixRuleHash.put(curSuffix, next_aux);
							}
						}					
					}
					tmpHash.put(curAux, aux_suffixRuleHash);
				}
			}
		}
	}
	/* Nikhilesh */
	/************************************************************/
	
	private 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 void hashParticles(String line)
	{
		particles.add(line.trim());
	}
	
	/*private 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 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 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 void hashAuxiliaryVerb(String line) {
		String[] lineComponents = line.split(StemmerRule.DELIMITER);
		auxiliaryVerbHash.put(lineComponents[0].trim(), "");
	}*/

	
	private void hashIrregularVerb(String line) {
		String[] lineComponents = line.split(StemmerRule.DELIMITER);
		if(lineComponents.length == 4 || lineComponents.length == 5){
			String irregularForm = lineComponents[0].trim();
			String regularForm = lineComponents[1].trim();
			String paradigm = lineComponents[2].trim();
			String category = lineComponents[3].trim();
			String suffix = null;
			if(lineComponents.length == 5)
				suffix = lineComponents[4].trim();
			
			Vector<String> temp = new Vector<String>();
			temp.add(irregularForm);
			temp.add(regularForm);
			temp.add(paradigm);
			temp.add(category);
			if(suffix != null)
				temp.add(suffix);
			
			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 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 void hashSuffixReplacementRule(String line){
		//System.err.println("Line : "+line);
		String[] lineComponents = line.split(StemmerRule.DELIMITER);
		String category = lineComponents[0].trim();
		String paradigm = lineComponents[1].trim();
		String ultimateInsertion = lineComponents[2].trim();
		String ultimateDeletion = lineComponents[3].trim();
		String penultimateInsertion = lineComponents[4].trim();
		String penultimateDeletion = lineComponents[5].trim();
		//if(lineComponents[6].equals("") || lineComponents[6] == null || lineComponents.length < 7)
		//	UTFConsole.out.println(lineComponents);
		int priority = Integer.parseInt(lineComponents[6].trim());
		String suffix = null;
		if(lineComponents.length == 8)
		{
			suffix = lineComponents[7].trim();
		}
			

		StemmerRule sr = new StemmerRule(paradigm, category, ultimateInsertion, ultimateDeletion, penultimateInsertion, penultimateDeletion, suffix, priority);

		if(suffixReplacementRuleHash.containsKey(category)){
			HashMap<String, Vector<StemmerRule>> suffixStemmerRuleHash = suffixReplacementRuleHash.get(category);
			if(suffixStemmerRuleHash.containsKey(paradigm)){
				Vector<StemmerRule> srv = suffixStemmerRuleHash.get(paradigm);
				//if(!srv.contains(sr))
					srv.add(sr);
			}
			else{
				Vector<StemmerRule> srv = new Vector<StemmerRule>(); 
				srv.add(sr);
				suffixStemmerRuleHash.put(paradigm, srv);
			}
		}
		else{
			Vector<StemmerRule> srv = new Vector<StemmerRule>(); 
			srv.add(sr);
			HashMap<String, Vector<StemmerRule>> suffixStemmerRuleHash = new HashMap<String, Vector<StemmerRule>>();
			suffixStemmerRuleHash.put(paradigm, srv);
			suffixReplacementRuleHash.put(category, suffixStemmerRuleHash);
		}
	}
	
	private void hashSuffixes(String line)
	{
		String[] lineComponents = line.split(StemmerRule.DELIMITER);
		String category = lineComponents[0].trim();
		String type = lineComponents[1].trim();
		String suffix = lineComponents[2].trim();
		int l = suffix.length();
		String lastchar = suffix.substring(l-1);
		
//**********************************************
		
		if(!suffixesList.contains(suffix))
		{
			suffixesList.add(suffix);
		}
		
//**********************************************
		
		if(suffixesHash.containsKey(category))
		{
			HashMap<String, HashMap<String, Vector<String>>> typeSuffixHash = suffixesHash.get(category);
			if(typeSuffixHash.containsKey(type))
			{
				HashMap<String, Vector<String>> lastcharSuffixHash = typeSuffixHash.get(type);
				if(lastcharSuffixHash.containsKey(lastchar))
				{
					Vector<String> suffixVector = lastcharSuffixHash.get(lastchar);
					suffixVector.add(suffix);
					lastcharSuffixHash.put(lastchar,suffixVector);
					typeSuffixHash.put(type,lastcharSuffixHash);
					suffixesHash.put(category,typeSuffixHash);
				}
				else
				{
					Vector<String> suffixVector = new Vector<String>();
					suffixVector.add(suffix);
					lastcharSuffixHash.put(lastchar,suffixVector);
					typeSuffixHash.put(type,lastcharSuffixHash);
					suffixesHash.put(category,typeSuffixHash);
				}
			}
			else
			{
				HashMap<String, Vector<String>> lastcharSuffixHash = new HashMap<String, Vector<String>>();
				Vector<String> suffixVector = new Vector<String>();
				suffixVector.add(suffix);
				lastcharSuffixHash.put(lastchar,suffixVector);
				typeSuffixHash.put(type,lastcharSuffixHash);
				suffixesHash.put(category,typeSuffixHash);
			}
		}
		else
		{
			HashMap<String, HashMap<String, Vector<String>>> typeSuffixHash = new HashMap<String, HashMap<String, Vector<String>>>();
			HashMap<String, Vector<String>> lastcharSuffixHash = new HashMap<String, Vector<String>>();
			Vector<String> suffixVector = new Vector<String>();
			suffixVector.add(suffix);
			lastcharSuffixHash.put(lastchar,suffixVector);
			typeSuffixHash.put(type,lastcharSuffixHash);
			suffixesHash.put(category,typeSuffixHash);
		}
	}
	
	public String removeParticle(String token)
	{
		for(int i=0;i<particles.size();i++)
		{
			if(token.endsWith(particles.get(i)))
			{
				token = token.replaceAll(particles.get(i)+"$","");
				return(token);
			}
		}
		return(token);
	}
	
	/**
	 * This function is used to remove type 3 suffixes i.e. charam suffixes. Internal working is quite same as function applySRRs. Only difference is that no recursion is required.
	 * 
	 * @param token The token which is to be stemmed
	 * @param category The category whose suffixes have to be considered 
	 * @return A Vector of <code>StemmeerRuleResult</code> is returned depending upon the matches found in the lexicon
	 */
	
	public Vector<StemmerRuleResult> removeCharamSuffix(String token, String category)
	{
		Vector<StemmerRuleResult> retVal = new Vector<StemmerRuleResult>();
		int l = token.length();
		if(l == 0)
			return(null);
		String lastchar = token.substring(l-1);
		
		Vector<String> suffixes3 = new Vector<String>();
		Vector<String> endsuffixes3 = new Vector<String>();
		
		if(suffixesHash.containsKey(category) && suffixesHash.get(category).containsKey("3"))
			suffixes3 = suffixesHash.get(category).get("3").get(lastchar);
		
		for(int i=0;suffixes3 != null && i<suffixes3.size();i++)
		{
			if(token.endsWith(suffixes3.get(i)))
				endsuffixes3.add(suffixes3.get(i));
		}
		
		if(endsuffixes3.size() == 0)
			return(null);
		else
		{
			Set<String> paradigms = suffixReplacementRuleHash.get(category).keySet();
			
			for(int i=0;i<endsuffixes3.size();i++)
			{
				String suff = endsuffixes3.get(i);
				Iterator<String> parIter = paradigms.iterator();
				String newtoken = token.replaceAll(suff+"$", "");
				while(parIter.hasNext())
				{
					String par = parIter.next();
					Vector<StemmerRule> rules = suffixReplacementRuleHash.get(category).get(par);
					for(int j=0;j<rules.size();j++)
					{
						StemmerRule currentRule = rules.get(j);
						StemmerRuleResult str = currentRule.applyOn(newtoken,suff);
						if(str != null)
						{
							//WordProperties wp = Wordlist.searchWordlistFor(str.getRoot(),str.getParadigm());
							WordProperties wp = Wordlist.lookup(str.getRoot(),str.getParadigm());
							if(wp != null)
							{
								if(!retVal.contains(str)){
									//System.out.println("Mila : " + str.toString());
									retVal.add(str);
								}
								break;
							}
						}
							
					}
					
				}
				
				if(hasIrregularRootForm(newtoken)||hasIrregularRootForm(token))
				{
					String regularRootForm=null;
					String new_paradigm = "";
					String new_category = "";
					String suffixStart = "";
					Vector<Vector<String>> results = getRegularRootForm(newtoken);
					for(int z=0;z<results.size();z++)
					{
						regularRootForm = results.get(z).get(1);
						new_paradigm = results.get(z).get(2);
						new_category = results.get(z).get(3);
						if(results.get(z).size() == 5)
						{
							suffixStart = results.get(z).get(4);
							if(suff != null && !suff.startsWith(suffixStart))
								break;
						}
						StemmerRuleResult str = new StemmerRuleResult(regularRootForm, new_paradigm, new_category, "", suff);
						if(!retVal.contains(str) && new_category.equals(category)){
							//System.out.println("Mila : " + str.toString());
							retVal.add(str);
						}
					}
				}
			}
		}
		if(retVal.size() == 0)
			return(null);
		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
	 * @param category The category which has to be considered for stemming
	 * @return A <code>Vector</code> of results obtained on application of all possible rules.
	 */
	
	public Vector<StemmerRuleResult> applySRRs(String token, String category)
	{
		//System.out.println("Working for : " + category);
		if(token.length() == 0 || token == null)
			return(null);
		Vector<StemmerRuleResult> retval = new Vector<StemmerRuleResult>();
		
		String firstchar = token.substring(0,1);
		
		int l = token.length();
		String lastchar = token.substring(l-1);
		//endsuffixes1 are all the possible type 1 suffixes for the current token/word.
		Vector<String> suffixes1 = new Vector<String>();
		Vector<String> endsuffixes1 = new Vector<String>();
		
		if(suffixesHash.containsKey(category) && suffixesHash.get(category).containsKey("1"))
			suffixes1 = suffixesHash.get(category).get("1").get(lastchar);
		
		for(int i=0;suffixes1 != null && i<suffixes1.size();i++)
		{
			if(token.endsWith(suffixes1.get(i)))
				endsuffixes1.add(suffixes1.get(i));
		}
		//System.out.println(endsuffixes1.toString());
		Set<String> paradigms = suffixReplacementRuleHash.get(category).keySet();
		//Set<String> paradigms = Wordlist.firstcharCatParHash.get(firstchar).get(category);
		
		//Considering each suffix one by one.
		for(int i=0;i<endsuffixes1.size();i++)
		{
			String suff = endsuffixes1.get(i);
			Iterator<String> parIter = paradigms.iterator();
			//Removing suffix from the token.
			//System.out.println("Removing suffix " + suff + " from the token " + token);
			String newtoken = token.replaceAll(suff+"$", "");
			//System.out.println("Removing suffix " + suff + " and now token is " + newtoken);
			//Considering each paradigm one by one.
			while(parIter.hasNext())
			{
				String par = parIter.next();
				//Consider all possible SRRs for the current category and paradigm.
				Vector<StemmerRule> rules = suffixReplacementRuleHash.get(category).get(par);
				for(int j=0;rules != null && j<rules.size();j++)
				{
					StemmerRule currentRule = rules.get(j);
					//Apply the curent rule.
					StemmerRuleResult str = currentRule.applyOn(newtoken,suff);					
					if(str != null)
					{
						//Verifying the result of the rule against lexicon.
						//If found in the lexicon, result is considered valid.
						//WordProperties wp = Wordlist.searchWordlistFor(str.getRoot(),str.getParadigm());
						
						WordProperties wp = Wordlist.lookup(str.getRoot(),str.getParadigm());
						// Nikhilesh  : start//
						boolean valid = true;
						if(category.equals("verb_aux")){							
							valid = auxSuffixNextRootRuleHash.containsKey(str.getRoot());
							if(valid){
								valid = auxSuffixNextRootRuleHash.get(str.getRoot()).containsKey(str.getSuffixList().get(0));
							}
							if(!valid){
								valid = auxSuffixNextTokenRuleHash.containsKey(str.getRoot());
								if(valid){
									valid = auxSuffixNextTokenRuleHash.get(str.getRoot()).containsKey(str.getSuffixList().get(0));
								}
							}
						}
						// Nikhilesh : end //
						if(wp != null && valid)
						{
							if(!retval.contains(str)){
								//System.out.println("1. Rule successful : " + currentRule.string() + "SRR : " + str.toString() + " and Result is : " + str.toString());
								retval.add(str);
							}
							break;
						}
					}
						
				}
				
			}
			//System.out.println("For " + suff +" Before Irregular : " + retval.toString());
			//Checking whether the token has irregular behaviour as mentioned in IRREGULAR rule file.
			if(hasIrregularRootForm(newtoken)||hasIrregularRootForm(token))
			{
				String regularRootForm=null;
				String new_paradigm = "";
				String new_category = "";
				String suffixStart = "";
				Vector<Vector<String>> results = getRegularRootForm(newtoken);
				for(int z=0;z<results.size();z++)
				{
					regularRootForm = results.get(z).get(1);
					new_paradigm = results.get(z).get(2);
					new_category = results.get(z).get(3);
					if(results.get(z).size() == 5)
					{
						suffixStart = results.get(z).get(4);
						if(suff != null && !suff.startsWith(suffixStart))
							break;
					}
					StemmerRuleResult str = new StemmerRuleResult(regularRootForm, new_paradigm, new_category, "", suff);
					if(!retval.contains(str) && new_category.equals(category))
						retval.add(str);
				}
			}
			//System.out.println("For " + suff +" After Irregular : " + retval.toString());
			
		}
		
		
		if(multiSuffix){
		//	endsuffixes2 are all the possible type 2 suffixes for the current token/word.
		Vector<String> suffixes2 = new Vector<String>();
		Vector<String> endsuffixes2 = new Vector<String>();
		
		if(suffixesHash.containsKey(category) && suffixesHash.get(category).containsKey("2"))
			suffixes2 = suffixesHash.get(category).get("2").get(lastchar);
		
		for(int i=0;suffixes2 != null && i<suffixes2.size();i++)
		{
			if(token.endsWith(suffixes2.get(i)))
				endsuffixes2.add(suffixes2.get(i));
		}
		
		int maxl = 0;
		String maxSuff = "";
		String newtoken_maxl = "";
		//Considering each suffix one by one.
		for(int i=0;i<endsuffixes2.size();i++)
		{
			String suff = endsuffixes2.get(i);
			Iterator<String> parIter = paradigms.iterator();
			//Deleting the suffix from the token.
			String newtoken = token.replaceAll(suff+"$", "");
			//Considering each category one by one.
			while(parIter.hasNext())
			{
				String par = parIter.next();
				//Consider all possible SRRs for the current category and paradigm.
				Vector<StemmerRule> rules = suffixReplacementRuleHash.get(category).get(par);
				for(int j=0;rules != null && j<rules.size();j++)
				{
					StemmerRule currentRule = rules.get(j);
					//Apply the current rule.
					StemmerRuleResult str = currentRule.applyOn(newtoken,suff);
					if(str != null)
					{
//						Verifying the result of the rule against lexicon.
						//If found in the lexicon, result is considered valid.
						//WordProperties wp = Wordlist.searchWordlistFor(str.getRoot(),str.getParadigm());
						WordProperties wp = Wordlist.lookup(str.getRoot(),str.getParadigm());
//						 Nikhilesh  : start//
						boolean valid = true;
						if(category.equals("verb_aux")){							
							valid = auxSuffixNextRootRuleHash.containsKey(str.getRoot());
							if(valid){
								valid = auxSuffixNextRootRuleHash.get(str.getRoot()).containsKey(str.getSuffixList().get(0));
							}
							if(!valid){
								valid = auxSuffixNextTokenRuleHash.containsKey(str.getRoot());
								if(valid){
									valid = auxSuffixNextTokenRuleHash.get(str.getRoot()).containsKey(str.getSuffixList().get(0));
								}
							}
						}
						// Nikhilesh : end //
						if(wp != null)
						{
							if(!retval.contains(str))
								retval.add(str);
							break;
						}
					}
					
				}
				
			}
			
			//Checking whether the token has irregular behaviour as mentioned in IRREGULAR rule file.
			
			if(hasIrregularRootForm(newtoken)||hasIrregularRootForm(token))
			{
				String regularRootForm=null;
				String new_paradigm = "";
				String new_category = "";
				String suffixStart = "";
				Vector<Vector<String>> results = getRegularRootForm(newtoken);
				for(int z=0;z<results.size();z++)
				{
					regularRootForm = results.get(z).get(1);
					new_paradigm = results.get(z).get(2);
					new_category = results.get(z).get(3);
					if(results.get(z).size() == 5)
					{
						suffixStart = results.get(z).get(4);
						if(suff != null && !suff.startsWith(suffixStart))
							break;
					}
					StemmerRuleResult str = new StemmerRuleResult(regularRootForm, new_paradigm, new_category, "", suff);
					if(!retval.contains(str) && new_category.equals(category))
						retval.add(str);
				}
			}
			
			if(suff.length() > maxl)
			{
				maxl = suff.length();
				newtoken_maxl = newtoken;
				maxSuff = suff;
			}
			
		}
		
		if(retval.size() == 0 && endsuffixes2.size() > 0)
		{
			//If type 2 suffix was removed then reccurse with new token.
			//New token is the token obtained by removing longest type 2 suffix.
			Vector<StemmerRuleResult> strv = applySRRs(newtoken_maxl,category);
			//Adding current suffix to the suffix list of each result obtained above.
			for(int k=0;strv != null && k<strv.size();k++)
			{
				if(strv.get(k) != null)
				{
					strv.get(k).addSuffix(maxSuff);
					if(!retval.contains(strv.get(k)))
						retval.add(strv.get(k));
				}
			}
		}
		}
		return(retval);
	}
	
	/* Nikhilesh : Start */
	
	public Vector<StemmerRuleResult> checkLexEntries(String token, String category, String suffix) {
		Vector<StemmerRuleResult> retVal = new Vector<StemmerRuleResult>();
		Vector<WordProperties> tokenProperties = Wordlist.searchWordlistFor(token);
		if(tokenProperties != null){
			for(int i = 0; i < tokenProperties.size(); i++){
				WordProperties tokenProperty = tokenProperties.get(i);
//				System.out.println("Found in Lexicon (fullsearch): " + token + " lexiconParadigm : " + tokenProperty.getParadigm() + " Category : " + tokenProperty.getCategory());
				if(tokenProperty.getCategory().equals(category)){
					StemmerRuleResult srresult = new StemmerRuleResult(token, tokenProperty.getParadigm(), category,"", suffix);
					if(!retVal.contains(srresult))
						retVal.add(srresult);
				}
			}
		}
		return retVal;
	}
	
	public Vector<StemmerRuleResult> checkLexEntries(String token, String category, String paradigm, String suffix) {
		Vector<StemmerRuleResult> retVal = new Vector<StemmerRuleResult>();
		Vector<WordProperties> tokenProperties = Wordlist.searchWordlistFor(token);
		if(tokenProperties != null){
			for(int i = 0; i < tokenProperties.size(); i++){
				WordProperties tokenProperty = tokenProperties.get(i);
//				System.out.println("Found in Lexicon (fullsearch): " + token + " lexiconParadigm : " + tokenProperty.getParadigm() + " Category : " + tokenProperty.getCategory());
				if(tokenProperty.getCategory().equals(category) && tokenProperty.getParadigm().equals(paradigm)){
					StemmerRuleResult srresult = new StemmerRuleResult(token, paradigm, category,"", suffix);
					if(!retVal.contains(srresult))
						retVal.add(srresult);
				}
			}
		}
		return retVal;
	}
	/* Nikhilesh : This function is written to take place of the function above (applySRRs)*/
	public Vector<StemmerRuleResult> applySRR(String token, String category)
	{
		//System.out.println("Working for : " + category);
		if(token.length() == 0 || token == null)
			return(null);
		Vector<StemmerRuleResult> retval = new Vector<StemmerRuleResult>();
		if(newSuffixReplacementRuleHash.keySet().contains(category)){
			//System.out.println("Found..");
			HashMap<String, Vector<StemmerRule>> catHash = newSuffixReplacementRuleHash.get(category);
			Set paradigmKeys = catHash.keySet();
			Iterator it = paradigmKeys.iterator();
			while(it.hasNext()){
				String paradigm = (String) it.next();
				Vector<StemmerRule> stemmerRules = newSuffixReplacementRuleHash.get(category).get(paradigm);
				for(int i =0; i<stemmerRules.size(); i++){
					StemmerRule stemmerRule = stemmerRules.get(i);
					String stem = stemmerRule.applyRule(token);
					Vector<StemmerRuleResult> srv = checkLexEntries(stem,category,paradigm,stemmerRule.getSuffix());
					if(!srv.isEmpty()){
						for(int j = 0; j<srv.size(); j++){			//												
							retval.add(srv.get(j));
						}
					}
				}
			}
		}	
				
		return(retval);
	}
	
	public Vector<StemmerRuleResult> applyIrregularVerbMapping(String token, String category){
		Vector<StemmerRuleResult> srrv = new Vector<StemmerRuleResult>();
		Vector<String> suffixes = new Vector<String>();
		if(newSuffixesHash.keySet().contains(category.trim())){
			//System.out.println("Found..");
			HashMap<String, HashMap<String, Vector<String>>> catHash = newSuffixesHash.get(category.trim());
			Set typeKeys = catHash.keySet();
			Iterator it = typeKeys.iterator();
			while(it.hasNext()){
				String type = (String) it.next();
				HashMap<String, Vector<String>> typeHash = newSuffixesHash.get(category).get(type);
				/*if(typeHash.keySet().contains("0"))
					suffixes.addAll(typeHash.get("0"));*/
				if(typeHash.keySet().contains("1"))
					suffixes.addAll(typeHash.get("1"));
			}		
			//System.out.println("Suffixes are : " + suffixes.toString());			
		}
		/*else
			System.out.println("Not Found..");*/
		if(!newIrregularVerbHash.keySet().contains(category)){
			return srrv;
		}
		HashMap<String, Vector<String>> catHash = newIrregularVerbHash.get(category);
		if(!suffixes.isEmpty()){
			for(int suf = 0; suf<suffixes.size(); suf++ ){
				String suffix = suffixes.get(suf);
				if(token.endsWith(suffix)){					
					String stem = token.replaceAll(suffix+"$", "");
					//System.out.println("Removing suffix : " + suffix + " Now token is : " + stem);
					if(catHash.keySet().contains(stem) && catHash.get(stem).get(2).equals(category)){
						String regularStem = catHash.get(stem).get(0);
						String cat = catHash.get(stem).get(2);
						String paradigm =  catHash.get(stem).get(1);						
						Vector<StemmerRuleResult> srv = checkLexEntries(regularStem,cat,paradigm,suffix);
					
						if(!srv.isEmpty()){
							for(int i = 0; i<srv.size(); i++){
									srrv.add(srv.get(i));
							}
						}
					}
				}
			}
		}
		return srrv;
	}
	
	public Vector<StemmerRuleResult> applySuffixRules(String token, String category){
		Vector<StemmerRuleResult> srrv = new Vector<StemmerRuleResult>();
		Vector<String> suffixes = new Vector<String>();
		if(newSuffixesHash.keySet().contains(category.trim())){
			//System.out.println("Found..");
			HashMap<String, HashMap<String, Vector<String>>> catHash = newSuffixesHash.get(category.trim());
			Set typeKeys = catHash.keySet();
			Iterator it = typeKeys.iterator();
			while(it.hasNext()){
				String type = (String) it.next();
				HashMap<String, Vector<String>> typeHash = newSuffixesHash.get(category).get(type);
				if(typeHash.keySet().contains("0"))
					suffixes.addAll(typeHash.get("0"));
				if(typeHash.keySet().contains("1"))
					suffixes.addAll(typeHash.get("1"));
				if(typeHash.keySet().contains("2"))
					suffixes.addAll(typeHash.get("2"));
			}		
			//System.out.println("Suffixes are : " + suffixes.toString());			
		}
		else
			System.out.println("Not Found..");
		if(!suffixes.isEmpty()){
			for(int suf = 0; suf<suffixes.size(); suf++ ){
				String suffix = suffixes.get(suf);
				if(token.endsWith(suffix)){					
					String stem = token.replaceAll(suffix+"$", "");
					//System.out.println("Removing suffix : " + suffix + " Now token is : " + stem);
					Vector<StemmerRuleResult> srv = checkLexEntries(stem,category,suffix);
					if(!srv.isEmpty()){
						for(int i = 0; i<srv.size(); i++){
			//				srv.get(i).se
							//if(srv.get(i).getCategory().equals(category))								
								srrv.add(srv.get(i));
						}
					}
				}
			}
		}
		/* Nikhilesh : see you in evening. */
		
		return srrv;
	}
	/* Nikhilesh : end */
	
	public 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);
	}
	
	
	/**
	 * This function is used to check if the word is a special character like number or punctuation mark
	 * 
	 * @param token The token which is to be stemmed
	 * @return A <code>StemmerRuleResult</code> is returned with appropriate type identified
	 */
	public 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;
	}
	
//******************************************************************
	
	/** Nikhilesh **/
	boolean valid(StemmerRuleResult str, String category){
		boolean valid = true;
		if(category.equals("verb_aux")){							
			valid = auxSuffixNextRootRuleHash.containsKey(str.getRoot());
			if(valid){
				valid = auxSuffixNextRootRuleHash.get(str.getRoot()).containsKey(str.getSuffixList().get(0));
			}
			if(!valid){
				valid = auxSuffixNextTokenRuleHash.containsKey(str.getRoot());
				if(valid){
					valid = auxSuffixNextTokenRuleHash.get(str.getRoot()).containsKey(str.getSuffixList().get(0));
				}
			}
		}
		return valid;
	}

//	******************************************************************	
	
	public void buildSuffixList()
	{
		suffixesHashStatic = suffixesHash;
		particlesStatic = particles;
		
	}
	
	public static boolean endsWithNounSuff(String word)
	{
		int l = word.length();
		String lastchar = word.substring(l-1);
		
		Vector<String> suffixes1 = new Vector<String>();
		Vector<String> suffixes2 = new Vector<String>();
		Vector<String> suffixes3 = new Vector<String>();
		Vector<String> endsuffixes = new Vector<String>();
		
		if(suffixesHashStatic.containsKey("noun") && suffixesHashStatic.get("noun").containsKey("1"))
			suffixes1 = suffixesHashStatic.get("noun").get("1").get(lastchar);
		if(suffixesHashStatic.containsKey("noun") && suffixesHashStatic.get("noun").containsKey("2"))
			suffixes2 = suffixesHashStatic.get("noun").get("2").get(lastchar);
		if(suffixesHashStatic.containsKey("noun") && suffixesHashStatic.get("noun").containsKey("3"))
			suffixes3 = suffixesHashStatic.get("noun").get("3").get(lastchar);
		
		for(int i=0;i<particlesStatic.size();i++)
		{
			if(word.endsWith(particlesStatic.get(i)))
			{
				word = word.replaceAll(particlesStatic.get(i)+"$","");
				break;
				//endsuffixes.add(particlesStatic.get(i));
			}
		}
		
		for(int i=0;suffixes1 != null && i<suffixes1.size();i++)
		{
			if(word.endsWith(suffixes1.get(i)))
				endsuffixes.add(suffixes1.get(i));
		}
		for(int i=0;suffixes2 != null && i<suffixes2.size();i++)
		{
			if(word.endsWith(suffixes2.get(i)))
				endsuffixes.add(suffixes2.get(i));
		}
		for(int i=0;suffixes3 != null && i<suffixes3.size();i++)
		{
			if(word.endsWith(suffixes3.get(i)))
				endsuffixes.add(suffixes3.get(i));
		}
		
		
		if(endsuffixes.size() == 0)
			return(false);
		else
		{
			if((endsuffixes.contains("ा") || endsuffixes.contains("ी") || endsuffixes.contains("े")) && endsuffixes.size() == 1)
				return(false);
			else
				return(true);
		}
	}
	
	public static String getSuffix(String word)
	{
		int l = word.length();
		String lastchar = word.substring(l-1);
		
		Vector<String> suffixes1 = new Vector<String>();
		Vector<String> suffixes2 = new Vector<String>();
		Vector<String> suffixes3 = new Vector<String>();
		Vector<String> suffixes4 = new Vector<String>();
		Vector<String> suffixes5 = new Vector<String>();
		Vector<String> suffixes6 = new Vector<String>();
		Vector<String> endsuffixes = new Vector<String>();
		
		if(suffixesHashStatic.containsKey("noun") && suffixesHashStatic.get("noun").containsKey("1"))
			suffixes1 = suffixesHashStatic.get("noun").get("1").get(lastchar);
		if(suffixesHashStatic.containsKey("noun") && suffixesHashStatic.get("noun").containsKey("2"))
			suffixes2 = suffixesHashStatic.get("noun").get("2").get(lastchar);
		if(suffixesHashStatic.containsKey("noun") && suffixesHashStatic.get("noun").containsKey("3"))
			suffixes3 = suffixesHashStatic.get("noun").get("3").get(lastchar);
		
		if(suffixesHashStatic.containsKey("verb") && suffixesHashStatic.get("noun").containsKey("1"))
			suffixes4 = suffixesHashStatic.get("verb").get("1").get(lastchar);
		if(suffixesHashStatic.containsKey("verb") && suffixesHashStatic.get("noun").containsKey("2"))
			suffixes5 = suffixesHashStatic.get("verb").get("2").get(lastchar);
		if(suffixesHashStatic.containsKey("verb") && suffixesHashStatic.get("noun").containsKey("3"))
			suffixes6 = suffixesHashStatic.get("verb").get("3").get(lastchar);
		
		for(int i=0;i<particlesStatic.size();i++)
		{
			if(word.endsWith(particlesStatic.get(i)))
			{
				word = word.replaceAll(particlesStatic.get(i)+"$","");
				break;
				//endsuffixes.add(particlesStatic.get(i));
			}
		}
		
		for(int i=0;suffixes1 != null && i<suffixes1.size();i++)
		{
			if(word.endsWith(suffixes1.get(i)))
				endsuffixes.add(suffixes1.get(i));
		}
		for(int i=0;suffixes2 != null && i<suffixes2.size();i++)
		{
			if(word.endsWith(suffixes2.get(i)))
				endsuffixes.add(suffixes2.get(i));
		}
		for(int i=0;suffixes3 != null && i<suffixes3.size();i++)
		{
			if(word.endsWith(suffixes3.get(i)))
				endsuffixes.add(suffixes3.get(i));
		}
		for(int i=0;suffixes4 != null && i<suffixes4.size();i++)
		{
			if(word.endsWith(suffixes4.get(i)))
				endsuffixes.add(suffixes4.get(i));
		}
		for(int i=0;suffixes5 != null && i<suffixes5.size();i++)
		{
			if(word.endsWith(suffixes5.get(i)))
				endsuffixes.add(suffixes5.get(i));
		}
		for(int i=0;suffixes6 != null && i<suffixes6.size();i++)
		{
			if(word.endsWith(suffixes6.get(i)))
				endsuffixes.add(suffixes6.get(i));
		}
		
		
		if(endsuffixes.size() == 0)
			return(null);
		else
		{
			if((endsuffixes.contains("ा") || endsuffixes.contains("ी") || endsuffixes.contains("े")) && endsuffixes.size() == 1)
				return(null);
			else
			{
				int maxlen = 0;
				String maxSuff = "";
				for(int z=0;z<endsuffixes.size();z++)
				{
					if(endsuffixes.get(z).length() > maxlen)
					{
						maxlen = endsuffixes.get(z).length();
						maxSuff = endsuffixes.get(z);
					}
				}
				if(maxSuff.equals("ा") || maxSuff.equals("ी") || maxSuff.equals("े"))
					return(null);
				else
				{
					String tempword = word;
					tempword = tempword.replaceAll(maxSuff+"$","");
					if(tempword.length() <= 1)
						return(null);
					else
						return(maxSuff);
				}
			}
		}
	}
	
	public static int getSuffixIndex(String suffix)
	{
		return(suffixesList.indexOf(suffix));
	}
	
	/**
	 * This function is used to check whether input word ends with any of the noun suffixes
	 * 
	 * @param token The token which is to be checked
	 * @return A Vector of <code>StemmeerRuleResult</code> is returned depending upon whether the suffixes are found and removed
	 */
	
	public 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 boolean hasIrregularRootForm(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 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 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 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 boolean isAuxiliary(String token) {
		return auxiliaryVerbHash.containsKey(token);
	}*/

	public 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 Set<String> getCategories()
	{
		return(suffixesHash.keySet());
	}
	
	
	
	public 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(args[0].trim());
		StemmerRuleReader ob = new StemmerRuleReader();
		ob.populate();
		String tmp = "सक/ ूँगा, ूँगी, ेंगे,गे, ोगी, ेगा, ेगी, ेंगी, ोंगी";//रह  ा, ी, े है,था,हो,थी,थीं,हों,हैं,थे";//रह ना है,था,हो";
		/*tmp = tmp.replaceAll(" ", "/");
		System.out.println(tmp);
		tmp = tmp.replaceAll(",", "-");
		System.out.println(tmp);
		tmp = tmp.replaceAll("/", ",");
		System.out.println(tmp);*/
		/*String t[] = tmp.split("/");
		System.out.println(t.length);
		for(int i=0; i<t.length; i++){
			System.out.println(t[i]);
		}
		String t2[] = t[1].split(",");
		System.out.println(t2.length);
		for(int i=0; i<t2.length; i++){
			System.out.println(t2[i]);
		}*/
		/*String rule = "verb_aux,vaux, ो ,,,,1,ु";
		String [] comps = rule.split(",");
		System.out.println(comps.length);
		for(int i=0; i<comps.length; i++){
			System.out.println(i + " .\t" + comps[i]);
		}*/
		String word = "लगाना";
		if(word.endsWith("ा")){
			System.out.println("Failed... " + word);
		}
		else{
			System.out.println("Working... " + word);
		}
		String test = "";
		if(test.isEmpty()){
			System.out.println("Working...");
		}
		else{
			System.out.println("Failed...");
		}
		//System.out.println("Done!");
		//String category = 
		/*boolean valid = true;
		if(category.equals("verb_aux")){							
			valid = auxSuffixNextRootRuleHash.containsKey(str.getRoot());
			if(valid){
				valid = auxSuffixNextRootRuleHash.get(str.getRoot()).containsKey(str.getSuffixList().get(0));
			}
			if(!valid){
				valid = auxSuffixNextTokenRuleHash.containsKey(str.getRoot());
				if(valid){
					valid = auxSuffixNextTokenRuleHash.get(str.getRoot()).containsKey(str.getSuffixList().get(0));
				}
			}
		}*/
	}
}
