package iitb.cfilt.cpost.lexicon;
import java.io.*;
import java.sql.Timestamp;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import iitb.cfilt.cpost.dmstemmer.MorphResult;
import iitb.cfilt.cpost.*;

public class LexRuleReader {
	private String suffixRuleForNNFilename = "";
	private String reAdjustmentRuleForNNFilename = "";
	private String rulesForAdjFilename = "";
	private String rulesForQuantifierIntensifierFileName = "";
	private String rulesForOrdinalsFileName = "";
	private String rulesForVerbsFileName = "";
	public HashMap<String, Vector<NNSuffixRule>> suffixRuleNNHash = new HashMap<String, Vector<NNSuffixRule>>();
	public HashMap<String, Vector<NNReadjustmentRule>> reAdjustmentRuleNNHash = new HashMap<String, Vector<NNReadjustmentRule>>();
	public HashMap<String, Vector<LexGeneralRule>> adjRuleHash = new HashMap<String, Vector<LexGeneralRule>>();
	public HashMap<String, Vector<LexGeneralRule>> QnfInfRuleHash = new HashMap<String, Vector<LexGeneralRule>>();
	public HashMap<String, Vector<LexGeneralRule>> OrdinalRuleHash = new HashMap<String, Vector<LexGeneralRule>>();
	public HashMap<String, HashMap<String, Vector<VerbRule>>> verbRuleHash = new HashMap<String, HashMap<String,Vector<VerbRule>>>();
	public HashMap<String, Vector<VerbReadjustmentRule>> verbReadjustmentRuleHash = new HashMap<String, Vector<VerbReadjustmentRule>>();
	//public HashMap
	public Vector<String> suffixes = new Vector<String>();
	public Vector<String> verbSuffixes = new Vector<String>();
	public Properties normRulesMapping;
	public String devNormRulesFile;
	//private boolean populated = false;
	public LexRuleReader()
	{
		devNormRulesFile = ConfigReader.get("Lexicon.devNormRulesFile");
		normRulesMapping = new Properties();
		try{
			normRulesMapping.load(new FileInputStream(devNormRulesFile));
		}catch(IOException e) {
			e.printStackTrace();
		}
			suffixRuleForNNFilename = ConfigReader.get("NewStemmer.NN_suffix_Rules");
			reAdjustmentRuleForNNFilename = ConfigReader.get("NewStemmer.NN_ReAdjustment_Rules");
			rulesForAdjFilename = ConfigReader.get("NewStemmer.Adj_Rules");
			rulesForQuantifierIntensifierFileName = ConfigReader.get("NewStemmer.Qnf_Inf_Rules");
			rulesForOrdinalsFileName = ConfigReader.get("NewStemmer.Ordinal_Rules");
			rulesForVerbsFileName = ConfigReader.get("NewStemmer.Verb_Rules");
			try
			{
				BufferedReader bsrr = new BufferedReader(new InputStreamReader(new FileInputStream(suffixRuleForNNFilename), "UTF8"));
				String line = "";
		
				while (line != null)
				{				
					line = bsrr.readLine();
					if(line != null)
					{
						line = line.trim();
						if(line.length()!=0 && !line.startsWith("//"))
						{
							String lineComponents[] = line.split("/");
							if(lineComponents.length == 3)
							{
								String suffix = lineComponents[0].trim();
								String constraint = lineComponents[1].trim();
								String morphAnalysis = lineComponents[2].trim();
								/*String morphs[] = morphAnalysis.split(",");
								if(morphs.length>2){
									
								}*/
								String stemFeatures[] = constraint.split(",");
								char clas = stemFeatures[0].trim().charAt(0);
								char gender = stemFeatures[1].trim().charAt(0); // Here, in all rules, Gender is mentioned as 'X'. Therefor no treatment is given. Otherwise It should be read as +/- and given M/F accordingly. 
								String ending = stemFeatures[2].trim();
								NNSuffixRule sr = new NNSuffixRule(suffix, clas,gender,ending,morphAnalysis);
								if(suffixRuleNNHash.containsKey(suffix)){
									Vector<NNSuffixRule> srv = suffixRuleNNHash.get(suffix);
									srv.add(sr);
									suffixRuleNNHash.put(suffix, srv);
								}
								else{
									Vector<NNSuffixRule> srv = new Vector<NNSuffixRule>();
									srv.add(sr);
									suffixRuleNNHash.put(suffix, srv);
								}
								
								if(!suffixes.contains(suffix)){
									suffixes.add(suffix);
								}
								
							}
						}
					}
				}
				
				bsrr.close();
				
				bsrr = new BufferedReader(new InputStreamReader(new FileInputStream(reAdjustmentRuleForNNFilename), "UTF8"));
				line = "";
				
				while (line != null)
				{
					line = bsrr.readLine();
					if(line != null)
					{
						line = line.trim();
						if(line.length()!=0 && !line.startsWith("//"))
						{
							String lineComponents[] = line.split("/");
							String suffixListToAdd[] = lineComponents[0].trim().split("or");							
							String suffixToDelete = lineComponents[1].trim();
							String featuresANDsuffix[] = lineComponents[2].trim().split(":");							
							String stemFeatureStrings[] = featuresANDsuffix[0].trim().split("or");
							String suffixesObserved[] = featuresANDsuffix[1].trim().split("or");
							
							Vector<StemFeatures> sfv = new Vector<StemFeatures>();
							for(int sfs=0; sfs<stemFeatureStrings.length; sfs++){
								String stemFeatures[] = stemFeatureStrings[sfs].trim().split(",");
								char clas = stemFeatures[0].trim().charAt(0);
								char gender = stemFeatures[1].trim().charAt(0);
								String ending = stemFeatures[2].trim();
								StemFeatures sf = new StemFeatures(clas,gender,ending);
								sfv.add(sf);
							}
							for(int so=0; so<suffixesObserved.length; so++){
								String suffixObserved = suffixesObserved[so].trim();
								
								Vector<NNReadjustmentRule> rrv;			
								if(reAdjustmentRuleNNHash.containsKey(suffixObserved)){
									rrv = reAdjustmentRuleNNHash.get(suffixObserved);
								} else{
									rrv = new Vector<NNReadjustmentRule>();
									reAdjustmentRuleNNHash.put(suffixObserved, rrv);
								}
								for(int sfs=0; sfs<sfv.size(); sfs++){
									for(int sla=0; sla<suffixListToAdd.length; sla++){
										String suffixToAdd = suffixListToAdd[sla].trim();
										NNReadjustmentRule rr = new NNReadjustmentRule(suffixToAdd,suffixToDelete,sfv.get(sfs),suffixObserved);
										rrv.add(rr);
									}
								}
								
//								if(reAdjustmentRuleNNHash.containsKey(suffixObserved)){
//									Vector<NNReadjustmentRule> rrv = reAdjustmentRuleNNHash.get(suffixObserved);									
//									for(int sfs=0; sfs<sfv.size(); sfs++){
//										for(int sla=0; sla<suffixListToAdd.length; sla++){
//											String suffixToAdd = suffixListToAdd[sla].trim();
//											NNReadjustmentRule rr = new NNReadjustmentRule(suffixToAdd,suffixToDelete,sfv.get(sfs),suffixObserved);
//											rrv.add(rr);
//										}
//									}
//									reAdjustmentRuleNNHash.put(suffixObserved, rrv);
//								}
//								else{
//									Vector<NNReadjustmentRule> rrv = new Vector<NNReadjustmentRule>();
//									for(int sfs=0; sfs<sfv.size(); sfs++){
//										for(int sla=0; sla<suffixListToAdd.length; sla++){
//											String suffixToAdd = suffixListToAdd[sla].trim();
//											NNReadjustmentRule rr = new NNReadjustmentRule(suffixToAdd,suffixToDelete,sfv.get(sfs),suffixObserved);
//											rrv.add(rr);
//										}
//									}
//									reAdjustmentRuleNNHash.put(suffixObserved, rrv);
//								}
							}
		
						}
					}
					
				}
				
				bsrr.close();
				
				bsrr = new BufferedReader(new InputStreamReader(new FileInputStream(rulesForAdjFilename), "UTF8"));
				line = "";
				
				while (line != null)
				{
					line = bsrr.readLine();
					if(line != null)
					{
						line = line.trim();
						if(line.length()!=0 && !line.startsWith("//"))
						{
							String lineComponents[] = line.split("/");
							String suffixToAdd = lineComponents[0].trim();
							String suffixToDelete = lineComponents[1].trim();
							char clas = lineComponents[2].trim().charAt(0);
							String morphAnalysis = lineComponents[3].trim();
							String suffixObserved = lineComponents[4].trim();
							LexGeneralRule adjRule = new LexGeneralRule(suffixToAdd, suffixToDelete, clas, morphAnalysis, suffixObserved);
							if(adjRuleHash.containsKey(suffixToDelete)){
								Vector<LexGeneralRule> adjRules = adjRuleHash.get(suffixToDelete);
								adjRules.add(adjRule);
								adjRuleHash.put(suffixToDelete, adjRules);
							}
							else{
								Vector<LexGeneralRule> adjRules = new Vector<LexGeneralRule>();
								adjRules.add(adjRule);
								adjRuleHash.put(suffixToDelete, adjRules);
							}
							
							if(!suffixes.contains(suffixToDelete)){
								suffixes.add(suffixToDelete);
							}
						}						
					}					
				}
				
				bsrr.close();
				
				bsrr = new BufferedReader(new InputStreamReader(new FileInputStream(rulesForQuantifierIntensifierFileName), "UTF8"));
				line = "";
				
				while (line != null)
				{
					line = bsrr.readLine();
					if(line != null)
					{
						line = line.trim();
						if(line.length()!=0 && !line.startsWith("//"))
						{
							String lineComponents[] = line.split("/");
							String suffixToAdd = lineComponents[0].trim();
							String suffixToDelete = lineComponents[1].trim();
							char clas = lineComponents[2].trim().charAt(0);
							String morphAnalysis = lineComponents[3].trim();
							String suffixObserved = lineComponents[4].trim();
							LexGeneralRule qnfInfRule = new LexGeneralRule(suffixToAdd, suffixToDelete, clas, morphAnalysis, suffixObserved);
							if(QnfInfRuleHash.containsKey(suffixToDelete)){
								Vector<LexGeneralRule> qnfInfRules = QnfInfRuleHash.get(suffixToDelete);
								qnfInfRules.add(qnfInfRule);
								QnfInfRuleHash.put(suffixToDelete, qnfInfRules);
							}
							else{
								Vector<LexGeneralRule> qnfInfRules = new Vector<LexGeneralRule>();
								qnfInfRules.add(qnfInfRule);
								QnfInfRuleHash.put(suffixToDelete, qnfInfRules);
							}
							
							if(!suffixes.contains(suffixToDelete)){
								suffixes.add(suffixToDelete);
							}
						}						
					}					
				}
				
				bsrr.close();
				
				bsrr = new BufferedReader(new InputStreamReader(new FileInputStream(rulesForOrdinalsFileName), "UTF8"));
				line = "";
				
				while (line != null)
				{
					line = bsrr.readLine();
					if(line != null)
					{
						line = line.trim();
						if(line.length()!=0 && !line.startsWith("//"))
						{
							String lineComponents[] = line.split("/");							
							String suffixToDelete = lineComponents[1].trim();
							char clas = lineComponents[2].trim().charAt(0);
							String morphAnalysis = lineComponents[3].trim();
							String suffixObserved = lineComponents[4].trim();
							String[] suffixesToAdd = lineComponents[0].trim().split("or");
							for(int i=0; i<suffixesToAdd.length; i++){
								String suffixToAdd = suffixesToAdd[i].trim();
								LexGeneralRule ordinalRule = new LexGeneralRule(suffixToAdd, suffixToDelete, clas, morphAnalysis, suffixObserved);
								if(OrdinalRuleHash.containsKey(suffixToDelete)){
									Vector<LexGeneralRule> ordinalRules = OrdinalRuleHash.get(suffixToDelete);
									ordinalRules.add(ordinalRule);
									OrdinalRuleHash.put(suffixToDelete, ordinalRules);
								}
								else{
									Vector<LexGeneralRule> ordinalRules = new Vector<LexGeneralRule>();
									ordinalRules.add(ordinalRule);
									OrdinalRuleHash.put(suffixToDelete, ordinalRules);
								}
							}
							
							if(!suffixes.contains(suffixToDelete)){
								suffixes.add(suffixToDelete);
							}
						}						
					}					
				}
				bsrr.close();
				
				bsrr = new BufferedReader(new InputStreamReader(new FileInputStream(rulesForVerbsFileName), "UTF8"));
				line = "";
				
				String typeOfRule = ""; 
				while (line != null)
				{
					line = bsrr.readLine();
					if(line != null)
					{
						line = line.trim();
						if(line.length()!=0 && !line.startsWith("//"))
						{
							if(line.startsWith("Rules For")){
								String [] lineparts = line.split(" ");
								typeOfRule = lineparts[2].trim();
							}
							else{
								hashIt(typeOfRule,line);
							}
							
						}						
					}					
				}
				
			}catch(Exception e)
			{
				System.out.println(e.toString());
				e.printStackTrace();
			}
	}
	
	void hashIt(String typeOfRule, String line){
		if(typeOfRule.equalsIgnoreCase("Readjustment")){
			hashToReadjustment(line);
		}
		else{
			hashDefault(typeOfRule,line);
		}
	}
	
	void hashDefault(String typeOfRule, String line){
		String lineComponents[] = line.split("/");							
		String [] suffixesList = lineComponents[0].trim().split("or");		
		String [] morphs = lineComponents[1].trim().split("or");
		String [] constraints;		
		Vector<String> constraintVector; 
		Vector<String> morphVector = new Vector<String>(Arrays.asList(morphs));
		Vector<MorphResult> mrv = new Vector<MorphResult>();
		for(int i=0; i<morphs.length; i++){
			String[] component = morphs[i].trim().split(",");
			//System.out.println(line + "  +++  " + morphs[i]);
			component[0] = component[0].trim();
			component[5] = component[5].trim();
			component[0] = component[0].replaceAll("^\\[", "");
			component[5] = component[5].replaceAll("\\]$", "");			
			MorphResult mr = new MorphResult(component[0].trim(),component[1].trim(),component[2].trim(),"x",component[3].trim(),component[4].trim(),component[5].trim());
			mrv.add(mr);
		}
		if(lineComponents.length>2){
			constraints = lineComponents[2].trim().split("or");			
			constraintVector = new Vector<String>(Arrays.asList(constraints));
			for(int cv=0; cv<constraintVector.size(); cv++){
				String trimmed = constraintVector.get(cv).trim();
				constraintVector.set(cv, trimmed);
			}
		}
		else{
			/*constraints = new String[1];
			constraints[0] = "Null";*/
			constraints = null;
			constraintVector = null;
		}		
		for(int i=0; i<suffixesList.length; i++){
			String suffix = suffixesList[i].trim();
			suffix = normalizeHindiString(suffix);
			VerbRule verbRule = new VerbRule(suffix, morphVector, mrv, constraintVector);
			if(verbRuleHash.containsKey(typeOfRule)){
				HashMap<String, Vector<VerbRule>> typeHash = verbRuleHash.get(typeOfRule);
				if(typeHash.containsKey(suffix)){
					Vector<VerbRule> verbRules = typeHash.get(suffix);
					verbRules.add(verbRule);
					typeHash.put(suffix, verbRules);
				}
				else{
					Vector<VerbRule> verbRules = new Vector<VerbRule>();
					verbRules.add(verbRule);
					typeHash.put(suffix, verbRules);
				}
			}
			else{
				HashMap<String, Vector<VerbRule>> typeHash = new HashMap<String, Vector<VerbRule>>();
				Vector<VerbRule> verbRules = new Vector<VerbRule>();
				verbRules.add(verbRule);
				typeHash.put(suffix, verbRules);
				verbRuleHash.put(typeOfRule, typeHash);
			}
			/*if(!suffixes.contains(suffix)){
				suffixes.add(suffix);
			}*/
			if(!verbSuffixes.contains(suffix)){
				verbSuffixes.add(suffix);
			}
		}		
		
	}
	
	void hashToReadjustment(String line){
		 String[] lineComponents = line.split("=");
		 String rule = lineComponents[0].trim();
		 String[] ruleComponents = rule.split("/");
		 String suffixToAdd = ruleComponents[0].trim();
		 String[] suffixesToDelete = ruleComponents[1].trim().split("or");
		 String morphAnalysis = "";
		 String perfectiveConstraint = "";
		 String typeConstraint = "";
		 String [] constraints;
		 String type = "others";
		 MorphResult mr = null;
		 Vector<String> constraintVector = new Vector<String>();
		 if(lineComponents.length>1){
				morphAnalysis = lineComponents[1].trim();
				String [] component = morphAnalysis.split(",");
				component[0] = component[0].trim();
				component[5] = component[5].trim();
				component[0] = component[0].replaceAll("^\\[", "");
				component[5] = component[5].replaceAll("\\]$", "");
				mr = new MorphResult(component[0].trim(),component[1].trim(),component[2].trim(),"x",component[3].trim(),component[4].trim(),component[5].trim());
				type = "direct";
			}		 
		if(ruleComponents.length>2){
			String constraintString = ruleComponents[2].trim();
			if(constraintString.startsWith("[")){
				type = "perfective";
				perfectiveConstraint = constraintString;
				perfectiveConstraint = perfectiveConstraint.replaceAll("^\\[+", "");
				perfectiveConstraint = perfectiveConstraint.replaceAll("\\]$", "");			
			}
			else if(constraintString.startsWith("<")){				
				typeConstraint = constraintString;
				typeConstraint = typeConstraint.replaceAll("^<", "");
				typeConstraint = typeConstraint.replaceAll(">$", "");
				if(typeConstraint.equalsIgnoreCase("AGR1")){
					type = "agr1";
				}
				else if(typeConstraint.equalsIgnoreCase("future")){
					type = "future";
				}
				else{
					type = "agr2";
				}
			}
			else{
				constraints = ruleComponents[2].trim().split(" or ");
				for(int cv=0; cv<constraints.length; cv++){
					constraints[cv] = constraints[cv].trim();
				}
				constraintVector = new Vector<String>(Arrays.asList(constraints));
				for(int cv=0; cv<constraintVector.size(); cv++){
					String trimmed = constraintVector.get(cv).trim();
					constraintVector.set(cv, trimmed);
				}
			}
			if(ruleComponents.length>3){
				String agr = ruleComponents[3].trim();
				if(agr.startsWith("<")){
					typeConstraint = agr;
					typeConstraint = typeConstraint.replaceAll("^<", "");
					typeConstraint = typeConstraint.replaceAll(">$", "");					
				}
				if(typeConstraint.equalsIgnoreCase("AGR1")){
					type = "agr1";
				}
				else{
					type = "agr2";
				}
			}
		}
		else{		
			constraints = new String[1];
			constraints[0] = "Null";
		}
		
		for(int i=0; i<suffixesToDelete.length; i++){
			String suffixToDelete = suffixesToDelete[i].trim();
			VerbReadjustmentRule vrr = new VerbReadjustmentRule(suffixToAdd, suffixToDelete, constraintVector, perfectiveConstraint, typeConstraint, morphAnalysis, mr );
			//if(verbReadjustmentRuleHash.containsKey(suffixToDelete)){
			if(verbReadjustmentRuleHash.containsKey(type)){
				//Vector<VerbReadjustmentRule> vrrv = verbReadjustmentRuleHash.get(suffixToDelete);
				Vector<VerbReadjustmentRule> vrrv = verbReadjustmentRuleHash.get(type);
				vrrv.add(vrr);
				//verbReadjustmentRuleHash.put(suffixToDelete, vrrv);
				verbReadjustmentRuleHash.put(type, vrrv);
			}
			else{
				Vector<VerbReadjustmentRule> vrrv = new Vector<VerbReadjustmentRule>();
				vrrv.add(vrr);
				//verbReadjustmentRuleHash.put(suffixToDelete, vrrv);
				verbReadjustmentRuleHash.put(type, vrrv);
			}
		}
	}
	public String normalizeHindiString(String inputStr) {
		
        String outputStr="";
        // First try bigram combinations
       int i;
       for (i=0; i<inputStr.length()-1 && inputStr.length()>0;) {
    	   String biGram=Integer.toHexString(inputStr.charAt(i));
	       if (inputStr.length()>1)
	    	   biGram += Integer.toHexString(inputStr.charAt(i+1));
           String mapping =	normRulesMapping.getProperty(biGram);
	       if (mapping!=null) {
	    	   char map = (char)Integer.parseInt(mapping, 16);
	    	   outputStr += map;
	    	   i+=2;
	       }
	       else {
	    	   outputStr += inputStr.substring(i, i+1);
	    	   i++;
	       }
       }
	   if (i==inputStr.length()-1)
		   outputStr += inputStr.substring(i, i+1);
      return outputStr;
	}
}
