package ciranda.utils;

import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Set;

import ciranda.classify.ModelFactory;

import edu.cmu.minorthird.classify.Classifier;
import edu.cmu.minorthird.classify.Feature;
import edu.cmu.minorthird.classify.Instance;
import edu.cmu.minorthird.classify.MutableInstance;
import edu.cmu.minorthird.text.BasicTextBase;
import edu.cmu.minorthird.text.BasicTextLabels;
import edu.cmu.minorthird.text.MonotonicTextLabels;
import edu.cmu.minorthird.text.Span;
import edu.cmu.minorthird.text.TextBase;
import edu.cmu.minorthird.text.TextLabels;
import edu.cmu.minorthird.text.learn.SampleFE;
import edu.cmu.minorthird.text.learn.SpanFE;
import edu.cmu.minorthird.text.learn.SpanFeatureExtractor;
import edu.cmu.minorthird.text.learn.SampleFE.AnnotatedSpanFE;
import edu.cmu.minorthird.text.mixup.MixupProgram;
//import edu.cmu.minorthird.text.mixup.MixupProgramTest;
import edu.cmu.minorthird.text.mixup.Mixup.ParseException;
import edu.cmu.minorthird.util.*;

/**
 * @author vitor
 *
 * Utilities for the ciranda package
 */

public class CirandaUtils {
	
	static SpanFE fe_1g = SampleFE.BAG_OF_LC_WORDS;
	static SpanFE fe_2g = new SpanFE(){
		public void extractFeatures(TextLabels labels, Span s){
			from(s).contains("bigram").eq().lc().emit();
		}
	};
	static SpanFE fe_3g = new SpanFE(){
		public void extractFeatures(TextLabels labels, Span s){
			from(s).contains("trigram").eq().lc().emit();
		}
	};
	static SpanFE fe_4g = new SpanFE(){
		public void extractFeatures(TextLabels labels, Span s){
			from(s).contains("fourgram").eq().lc().emit();
		}
	};
	static SpanFE fe_5g = new SpanFE(){
		public void extractFeatures(TextLabels labels, Span s){
			from(s).contains("fivegram").eq().lc().emit();
		}
	};
	
	
//	/**copied from minorthird*/
//	static public String contentsOfResourceFile(String fileName)
//	{
//		try {
////			InputStream s = MixupProgramTest.class.getClassLoader().getResourceAsStream(fileName);
////filename needs to be in classpath
//			InputStream s = ModelFactory.class.getClassLoader().getResourceAsStream(fileName);
//			if (s==null) throw new IllegalStateException("can't find resouce "+fileName);
//			byte[] buf = new byte[s.available()];
//			s.read(buf);
//			s.close();
//			return new String(buf);
//		} catch (IOException ex) {
//			throw new IllegalStateException("couldn't find resouce '"+fileName+"': "+ex);
//		}
//	}
//	
//	/**copied from minorthird*/
//	static public Classifier loadClass(String fileName)
//	{
//		try {
////			InputStream s = MixupProgramTest.class.getClassLoader().getResourceAsStream(fileName);
////filename needs to be in classpath
////			InputStream s = ModelFactory.class.getClassLoader().getResourceAsStream(fileName);
//			Class s = ModelFactory.class.getClassLoader().loadClass(fileName);
//			if (s==null) throw new IllegalStateException("can't find resouce "+fileName);
////			byte[] buf = new byte[s.available()];
////			s.read(buf);
////			s.close();
//			return (Classifier)s;
//		} catch (IOException ex) {
//			throw new IllegalStateException("couldn't find resouce '"+fileName+"': "+ex);
//		}
//	}
	
	/**
	 * Adds one instance to another. 
	 * addingInstances(destination, source);
	 */	
	static public Instance addingInstances(Instance target, Instance source){
		Iterator it = source.featureIterator();
		while(it.hasNext()){
			Feature f = (Feature)it.next();
			((MutableInstance)target).addNumeric(f,source.getWeight(f));
		}		
		return target;
	}
	
	/**
	 * returns only lines of msgs between <body> </body> tags.
	 * remove non-body parts.
	 */
	static public String getBody(String str){
		StringBuffer sb = new StringBuffer();
		String[] line = str.split("\n");
		boolean inbody = false;
		for(int i=0; i< line.length; i++){			
			if(line[i].startsWith("<body>")){
				inbody = true;
				continue;
			}
			else if(line[i].startsWith("<\\/body>")){
				inbody = false;
				break;
			}
			else{
				if(inbody){
					sb.append(line[i]+"\n");
				}				
			}
		}
		return sb.toString();
	}
	
	static public boolean hasBodyTag(String str){
		if(LineProcessingUtil.lineMatcher("<body>",str)){
			return true;
		}
		else return false;
	}
	
	/**
	 * Removes quotes from an email message
	 * TBD: needs to use the trained classifiers
	 * TBD
	 */	
	static public String removeQuotes(String str){
		StringBuffer sb = new StringBuffer();
		String[] line = str.split("\n");
		//TBD: for the moment, a VERY simple one
		for(int i=0;i<line.length;i++){
			if(LineProcessingUtil.lineMatcher("^[\\s]*\\>.*",line[i])){
				continue;
			}
			sb.append(line[i]+"\n");
		}
		return sb.toString();
	}
	
	/**
	 * Extracts all unigrams from String
	 * TBD
	 */	
	static public MutableInstance extractUnigrams(String str){
		BasicTextBase tb = new BasicTextBase();
		tb.loadDocument("cirandinha",str);
		TextLabels labels = new BasicTextLabels(tb);
		Span span = tb.documentSpan("cirandinha");
		Instance ins = CirandaUtils.fe_1g.extractInstance(labels,span);
		return (MutableInstance)ins;
	}
	 public static class unigramFE extends SampleFE.AnnotatedSpanFE
	  {
	    public void extractFeatures(TextLabels labels, Span s){
	      from(s).contains("reply").tokens().emit();
	    }
	  }
	
	/**
	 * Extracts all Bigrams from String
	 * TBD
	 */	
	static public MutableInstance extractBigrams(String str){
		BasicTextBase tb = new BasicTextBase();
		tb.loadDocument("cirandinha",str);
		TextLabels labels = new BasicTextLabels(tb);
		
		MixupProgram p;
		try {
			p = new MixupProgram(new String[] {"defSpanType bigram =: ... [any any] ... "});
			p.eval((MonotonicTextLabels)labels,labels.getTextBase());
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		Span span = tb.documentSpan("cirandinha");
		Instance ins = CirandaUtils.fe_2g.extractInstance(labels,span);
		return (MutableInstance)ins;	 
	}
	
	/**
	 * Extracts all Trigrams from String
	 * TBD
	 */	
	static public MutableInstance extractTrigrams(String str){
		BasicTextBase tb = new BasicTextBase();
		tb.loadDocument("cirandinha",str);
		TextLabels labels = new BasicTextLabels(tb);
		
		MixupProgram p;
		try {
			p = new MixupProgram(new String[] {"defSpanType trigram =: ... [any any any] ... "});
			p.eval((MonotonicTextLabels)labels,labels.getTextBase());
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		Span span = tb.documentSpan("cirandinha");
		Instance ins = CirandaUtils.fe_3g.extractInstance(labels,span);
		return (MutableInstance)ins;
	}
	
	/**
	 * Extracts all Fourgrams from String
	 */	
	static public MutableInstance extractFourgrams(String str){
		BasicTextBase tb = new BasicTextBase();
		tb.loadDocument("cirandinha",str);
		TextLabels labels = new BasicTextLabels(tb);
		
		MixupProgram p;
		try {
			p = new MixupProgram(new String[] {"defSpanType fourgram =: ... [any any any any] ... "});
			p.eval((MonotonicTextLabels)labels,labels.getTextBase());
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		Span span = tb.documentSpan("cirandinha");
		Instance ins = CirandaUtils.fe_4g.extractInstance(labels,span);
		return (MutableInstance)ins;
	}
	
	/**
	 * Extracts all Fivegrams from String
	 */	
	static public MutableInstance extractFivegrams(String str){
		BasicTextBase tb = new BasicTextBase();
		tb.loadDocument("cirandinha",str);
		TextLabels labels = new BasicTextLabels(tb);
		
		MixupProgram p;
		try {
			p = new MixupProgram(new String[] {"defSpanType fourgram =: ... [any any any any any] ... "});
			p.eval((MonotonicTextLabels)labels,labels.getTextBase());
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		Span span = tb.documentSpan("cirandinha");
		Instance ins = CirandaUtils.fe_5g.extractInstance(labels,span);
		return (MutableInstance)ins;
	}
	
	  /* Renames all feature names in an instance, by adding a prefix.
	   * For instance: from "calamari" to "parent_calamari"
	   * keeps the original feature weights
	   * */
	  static public MutableInstance renameFeatures(MutableInstance src, String prefix) {
	      MutableInstance out_ins = new MutableInstance();
	      for(Iterator tre = src.featureIterator(); tre.hasNext();){
	        Feature f = (Feature)tre.next();
	        String[] f_name = f.getName();
	        String newname = prefix+f_name[f_name.length-1];
	        out_ins.addNumeric(new Feature(newname), src.getWeight(f));
	      }
	      return out_ins;
	  }
	  
		//TBD: for the moment, delete everything after a fwd indication
	 static public String removeFWDparts(String str){
		StringBuffer sb = new StringBuffer();
		String[] line = str.split("\n");
		//TBD: for the moment, a VERY simple one
		for(int i=0;i<line.length;i++){
			if(LineProcessingUtil.lineMatcher("^---------- Forwarded message begins here ---.*",line[i])){
				sb.append(line[i]+"\n");
//				System.out.println("Found FWD line");
				break;
			}
			sb.append(line[i]+"\n");
		}
		return sb.toString();
	 }
	 
	 static public Instance extract1g2g3g4g5g(String str, boolean uni, boolean bi, boolean tri, boolean four, boolean five) {
		MutableInstance ins = new MutableInstance();
		if(uni){
			MutableInstance ins_1g = CirandaUtils.extractUnigrams(str);
			CirandaUtils.addingInstances(ins, ins_1g);
		}
		if(bi){
			MutableInstance ins_2g = CirandaUtils.extractBigrams(str);
			CirandaUtils.addingInstances(ins, ins_2g);
		}
		if(tri){
			MutableInstance ins_3g = CirandaUtils.extractTrigrams(str);
			CirandaUtils.addingInstances(ins, ins_3g);
		}
		if(four){
			MutableInstance ins_4g = CirandaUtils.extractFourgrams(str);
			CirandaUtils.addingInstances(ins, ins_4g);
		}
		if(five){
			MutableInstance ins_5g = CirandaUtils.extractFivegrams(str);
			CirandaUtils.addingInstances(ins, ins_5g);
		}
		return ins;
	}

	public static void main(String[] args) {
//		String as = " hey boy, what's wrong with you?\n"+
//		"<body>\n"
			
	}
}
