package pythagoras.featureExtractorUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
import org.apache.uima.fit.descriptor.ConfigurationParameter;
import org.apache.uima.fit.util.JCasUtil;
import org.apache.uima.jcas.JCas;
import org.apache.uima.resource.ResourceInitializationException;

import pythagoras.annotations.TranscribedText;
import pythagoras.featureExtractors.tripleWord.ChunkTripleFeatureExtractor;
import pythagoras.featureExtractors.tripleWord.T_ChunkTripleFeatureExtractor;
import de.tudarmstadt.ukp.dkpro.core.api.resources.ResourceUtils;
import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Lemma;
import de.tudarmstadt.ukp.dkpro.core.api.syntax.type.chunk.Chunk;
import de.tudarmstadt.ukp.dkpro.core.api.syntax.type.chunk.NC;
import de.tudarmstadt.ukp.dkpro.core.api.syntax.type.chunk.VC;

public class T_ChunkTripleMetaCollector
    extends FreqDistBasedMetaCollector
{
    public static final String CHUNK_TRIPLE_FD_KEY = "T_chunkTriple.ser";

    @ConfigurationParameter(name = T_ChunkTripleFeatureExtractor.PARAM_CHUNK_TRIPLE_FD_FILE, mandatory = true)
    private File teacherChunkTripleFdFile;

    @ConfigurationParameter(name = T_ChunkTripleFeatureExtractor.PARAM_CHUNK_TRIPLE_LOWER_CASE, mandatory = false, defaultValue = "true")
    private boolean chunkTripleLowerCase;

    @ConfigurationParameter(name = T_ChunkTripleFeatureExtractor.PARAM_CHUNK_TRIPLE_STOPWORDS_FILE, mandatory = false)
    protected String chunkTripleStopwordsFile;
    
    protected Set<String> stopwords;
    
    @Override
    public void process(JCas jcas)
        throws AnalysisEngineProcessException
    {
Set<String> triples = new HashSet<String>();
    	
    	try {
			stopwords = getStopwords();
		} catch (ResourceInitializationException e) {
			e.printStackTrace();
		}
    	
    	if	(!stopwords.isEmpty())	{
        	triples = getTriples(jcas, chunkTripleLowerCase, stopwords);
        }
        else	{
        	triples = getTriples(jcas, chunkTripleLowerCase);
        }
    	fd.incAll(triples);
    }

    public static Set<String> getTriples(JCas jcas, boolean lowerCase)
    {
        Set<String> triples = new HashSet<String>();

        for	(TranscribedText tt : JCasUtil.select(jcas, TranscribedText.class))	{
        	if	(tt.getSpeaker().contains("T"))	{
        		for (Chunk vc : JCasUtil.selectCovered(jcas, VC.class, tt)) {
                    String triple = getTriple(jcas, vc);
                    if (lowerCase) {
                        triple = triple.toLowerCase();
                    }
                    triples.add(triple);
                }	
        	}
        }
        return triples;
    }
    
    public static Set<String> getTriples(JCas jcas, boolean lowerCase, Set<String> stopwords)
    {
        Set<String> triples = new HashSet<String>();

        for	(TranscribedText tt : JCasUtil.select(jcas, TranscribedText.class))	{
        	if	(tt.getSpeaker().contains("T"))	{
        		for (Chunk vc : JCasUtil.selectCovered(jcas, VC.class, tt)) {
                    String triple = getTriple(jcas, vc, stopwords);
                    if (lowerCase) {
                        triple = triple.toLowerCase();
                    }           
                    triples.add(triple);
                }	
        	}
        }
        return triples;
    }

    private static String getTriple(JCas jcas, Chunk vc)
    {
        List<NC> ncListLeft = JCasUtil.selectPreceding(jcas, NC.class, vc, 1);
        List<NC> ncListRight = JCasUtil.selectFollowing(jcas, NC.class, vc, 1);

        String ncStringLeft = getChunkString(jcas, ncListLeft);
        String ncStringRight = getChunkString(jcas, ncListRight);

        String vcString = getChunkString(jcas, Arrays.asList(vc));

        String tripleString;
        if (ncStringLeft.length() > 0 && ncStringRight.length() > 0) {
            // tripleString = ncStringLeft + "_" + ncStringRight;
            tripleString = ncStringLeft + "_" + vcString + "_" + ncStringRight;
        }
        else {
            tripleString = "";
        }

        return tripleString;
    }
    
    private static String getTriple(JCas jcas, Chunk vc, Set<String> stopwords)
    {
        List<NC> ncListLeft = JCasUtil.selectPreceding(jcas, NC.class, vc, 2);
        List<NC> ncListRight = JCasUtil.selectFollowing(jcas, NC.class, vc, 2);

        String ncStringLeft = "";
        String ncStringRight = "";
        
        if (ncListLeft.size()>0) { ncStringLeft = getChunkString(jcas, ncListLeft.subList(0, 1)); } else ncStringLeft = getChunkString(jcas, ncListLeft);
        if (ncListRight.size()>0) { ncStringRight = getChunkString(jcas, ncListRight.subList(0, 1)); } else ncStringRight = getChunkString(jcas, ncListRight);

        String vcString = getChunkString(jcas, Arrays.asList(vc));
        String tripleString = "";
        
        if (ncStringLeft.length() > 0 && ncStringRight.length() > 0 && vcString.length() > 0 && !stopwords.contains(vcString.toLowerCase())) {
            // tripleString = ncStringLeft + "_" + ncStringRight;
            if (stopwords.contains(ncStringLeft.toLowerCase()) && (ncListLeft.size()>1)) {
                ncStringLeft = getChunkString(jcas, ncListLeft.subList(1, 2));
            }
            if (stopwords.contains(ncStringRight.toLowerCase()) &&  (ncListRight.size()>1)) {
                ncStringRight = getChunkString(jcas, ncListRight.subList(1, 2));
            }
            if (!stopwords.contains(ncStringRight.toLowerCase()) && !stopwords.contains(ncStringLeft.toLowerCase())) {
                tripleString = ncStringLeft + "_" + vcString + "_" + ncStringRight;
                System.out.println("triple: "+tripleString);
            }
        }

        return tripleString;
    }

    private static String getChunkString(JCas jcas, List<? extends Chunk> chunkList)
    {
        String chunkString = "";
        if (chunkList.size() > 0) {
            Chunk chunk = chunkList.get(0);

            // get rightmost lemma in chunk
            List<Lemma> lemmas = JCasUtil.selectCovered(jcas, Lemma.class, chunk);

            Set<String> lemmaStrings = new HashSet<String>();
            for (Lemma lemma : lemmas) {
                lemmaStrings.add(lemma.getValue());
            }
            chunkString = StringUtils.join(lemmaStrings, "_");

            // if (lemmas.size() > 0) {
            // chunkString = lemmas.get(lemmas.size()-1).getCoveredText();
            // }
        }
        return chunkString;
    }

    private Set<String> getStopwords()
            throws ResourceInitializationException
    {
        Set<String> stopwords = new HashSet<String>();
        try {
            if (chunkTripleStopwordsFile != null && !chunkTripleStopwordsFile.isEmpty()) {
                    // each line of the file contains one stopword
                    URL stopUrl = ResourceUtils.resolveLocation(chunkTripleStopwordsFile, null);
                    InputStream is = stopUrl.openStream();
                    stopwords.addAll(IOUtils.readLines(is, "UTF-8"));
            }
        }
        catch (IOException e) {
            throw new ResourceInitializationException(e);
        }
        return stopwords;
    }
    
    @Override
    public Map<String, String> getParameterKeyPairs()
    {
        Map<String, String> mapping = new HashMap<String, String>();
        mapping.put(T_ChunkTripleFeatureExtractor.PARAM_CHUNK_TRIPLE_FD_FILE, CHUNK_TRIPLE_FD_KEY);
        return mapping;
    }

    @Override
    protected File getFreqDistFile()
    {
        return teacherChunkTripleFdFile;
    }
}