// Path: Hadoop_Summit_Pig_for_Data_Science/src/main/java/com/caseystella/ds/nlp/rollup/Sentence.java
// public class Sentence {
//     private EnumMap<SentimentClass, Double> sentimentProbabilities;
//     private String sentence;
//     private SentimentClass sentimentClass;
// 
//     public Sentence( double[] sentimentProbabilities
//                    , String sentence
//                    , SentimentClass sentimentClass
//                    )
//     {
//         this.sentence = sentence;
//         this.sentimentClass = sentimentClass;
//         this.sentimentProbabilities = new EnumMap<SentimentClass, Double>(SentimentClass.class);
//         for(int i = 0;i < sentimentProbabilities.length;++i)
//         {
//             this.sentimentProbabilities.put(SentimentClass.values()[i], sentimentProbabilities[i]);
//         }
//     }
// 
//     public String getSentence() { return sentence;}
//     public EnumMap<SentimentClass, Double> getSentimentProbabilities() { return sentimentProbabilities;}
//     public SentimentClass getSentiment() { return sentimentClass;}
// }
// 
// Path: Hadoop_Summit_Pig_for_Data_Science/src/main/java/com/caseystella/ds/nlp/rollup/SentimentRollup.java
// public enum SentimentRollup implements ISentimentRollup {
//      SIMPLE_VOTE(new SimpleVoteRollup())
//     ,AVERAGE_PROBABILITIES(new AverageProbabilitiesRollup())
//     , LAST_SENTENCE_WINS(new LastSentenceWins())
//     , LONGEST_SENTENCE_WINS(new LongestSentenceWins())
//     , WILSON_SCORE(new WilsonScore())
//     ;
// 
//     private ISentimentRollup proxy;
//     SentimentRollup(ISentimentRollup proxy) { this.proxy = proxy;}
// 
//     @Override
//     public SentimentClass apply(List<Sentence> input) {
//         return proxy.apply(input);
//     }
// }


import com.caseystella.ds.nlp.rollup.Sentence;
import com.caseystella.ds.nlp.rollup.SentimentRollup;
import com.google.common.base.Function;
import edu.stanford.nlp.ie.machinereading.structure.AnnotationUtils;
import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.neural.rnn.RNNCoreAnnotations;
import edu.stanford.nlp.pipeline.Annotation;
import edu.stanford.nlp.pipeline.StanfordCoreNLP;
import edu.stanford.nlp.sentiment.SentimentCoreAnnotations;
import edu.stanford.nlp.trees.Tree;
import edu.stanford.nlp.util.CoreMap;
import edu.stanford.nlp.util.logging.RedwoodConfiguration;
import org.ejml.simple.SimpleMatrix;
import java.util.*;
package com.caseystella.ds.nlp;



/**
 * Created by cstella on 3/21/14.
 */
public enum SentimentAnalyzer implements Function<String, SentimentClass> {
    INSTANCE;

    @Override
    public SentimentClass apply(String document)
    {
        // shut off the annoying intialization messages
        Properties props = new Properties();
        //specify the annotators that we want to use to annotate the text.  We need a tokenized sentence with POS tags to extract sentiment.
        //this forms our pipeline
        props.setProperty("annotators", "tokenize, ssplit, parse, sentiment");
        StanfordCoreNLP pipeline = new StanfordCoreNLP(props);
        Annotation annotation = pipeline.process(document);
        List<Sentence> sentences = new ArrayList<Sentence>();
        /*
         * We're going to iterate over all of the sentences and extract the sentiment.  We'll adopt a majority rule policy
         */
        for( CoreMap sentence : annotation.get(CoreAnnotations.SentencesAnnotation.class))
        {
            //for each sentence, we get the sentiment that CoreNLP thinks this sentence indicates.
            Tree sentimentTree = sentence.get(SentimentCoreAnnotations.AnnotatedTree.class);
            int sentimentClassIdx = RNNCoreAnnotations.getPredictedClass(sentimentTree);
            SentimentClass sentimentClass = SentimentClass.getSpecific(sentimentClassIdx);

            /*
             * Each possible sentiment has an associated probability, so let's pull the entire
             * set of probabilities across all sentiment classes.
             */
            double[] probs = new double[SentimentClass.values().length];
            {
                SimpleMatrix mat = RNNCoreAnnotations.getPredictions(sentimentTree);
                for(int i = 0;i < SentimentClass.values().length;++i)
                {
                    probs[i] = mat.get(i);
                }
            }
            /*
             * Add the sentence and the associated probabilities to our list.
             */
            String sentenceStr = AnnotationUtils.sentenceToString(sentence).replace("\n", "");
            sentences.add(new Sentence(probs, sentenceStr, sentimentClass));
        }

        /*
         * Finally, rollup the score of the entire document given the list of sentiments
         * for each sentence.
         *
         * I have found that this is a surprisingly difficult thing.  We're going to use the fact that
         * we are mapping these documents onto Positive, Negative to use a technique that people use
         * to figure out overall product ratings from individual star ratings, the Wilson Score.
         * See http://www.evanmiller.org/how-not-to-sort-by-average-rating.html.
         *
         * For your convenience, I have implemented a number of other approaches, including:
         *  * Basic majority-rule voting
         *  * Max probability across all sentiments for all sentences
         *  * Last sentence wins
         *  * Longest sentence wins
         *
         */
// Path: Hadoop_Summit_Pig_for_Data_Science/src/main/java/com/caseystella/ds/nlp/rollup/Sentence.java
// public class Sentence {
//     private EnumMap<SentimentClass, Double> sentimentProbabilities;
//     private String sentence;
//     private SentimentClass sentimentClass;
// 
//     public Sentence( double[] sentimentProbabilities
//                    , String sentence
//                    , SentimentClass sentimentClass
//                    )
//     {
//         this.sentence = sentence;
//         this.sentimentClass = sentimentClass;
//         this.sentimentProbabilities = new EnumMap<SentimentClass, Double>(SentimentClass.class);
//         for(int i = 0;i < sentimentProbabilities.length;++i)
//         {
//             this.sentimentProbabilities.put(SentimentClass.values()[i], sentimentProbabilities[i]);
//         }
//     }
// 
//     public String getSentence() { return sentence;}
//     public EnumMap<SentimentClass, Double> getSentimentProbabilities() { return sentimentProbabilities;}
//     public SentimentClass getSentiment() { return sentimentClass;}
// }
// 
// Path: Hadoop_Summit_Pig_for_Data_Science/src/main/java/com/caseystella/ds/nlp/rollup/SentimentRollup.java
// public enum SentimentRollup implements ISentimentRollup {
//      SIMPLE_VOTE(new SimpleVoteRollup())
//     ,AVERAGE_PROBABILITIES(new AverageProbabilitiesRollup())
//     , LAST_SENTENCE_WINS(new LastSentenceWins())
//     , LONGEST_SENTENCE_WINS(new LongestSentenceWins())
//     , WILSON_SCORE(new WilsonScore())
//     ;
// 
//     private ISentimentRollup proxy;
//     SentimentRollup(ISentimentRollup proxy) { this.proxy = proxy;}
// 
//     @Override
//     public SentimentClass apply(List<Sentence> input) {
//         return proxy.apply(input);
//     }
// }


// Path: Hadoop_Summit_Pig_for_Data_Science/src/main/java/com/caseystella/ds/nlp/SentimentAnalyzer.java
import com.caseystella.ds.nlp.rollup.Sentence;
import com.caseystella.ds.nlp.rollup.SentimentRollup;
import com.google.common.base.Function;
import edu.stanford.nlp.ie.machinereading.structure.AnnotationUtils;
import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.neural.rnn.RNNCoreAnnotations;
import edu.stanford.nlp.pipeline.Annotation;
import edu.stanford.nlp.pipeline.StanfordCoreNLP;
import edu.stanford.nlp.sentiment.SentimentCoreAnnotations;
import edu.stanford.nlp.trees.Tree;
import edu.stanford.nlp.util.CoreMap;
import edu.stanford.nlp.util.logging.RedwoodConfiguration;
import org.ejml.simple.SimpleMatrix;
import java.util.*;

package com.caseystella.ds.nlp;



/**
 * Created by cstella on 3/21/14.
 */
public enum SentimentAnalyzer implements Function<String, SentimentClass> {
    INSTANCE;

    @Override
    public SentimentClass apply(String document)
    {
        // shut off the annoying intialization messages
        Properties props = new Properties();
        //specify the annotators that we want to use to annotate the text.  We need a tokenized sentence with POS tags to extract sentiment.
        //this forms our pipeline
        props.setProperty("annotators", "tokenize, ssplit, parse, sentiment");
        StanfordCoreNLP pipeline = new StanfordCoreNLP(props);
        Annotation annotation = pipeline.process(document);
        List<Sentence> sentences = new ArrayList<Sentence>();
        /*
         * We're going to iterate over all of the sentences and extract the sentiment.  We'll adopt a majority rule policy
         */
        for( CoreMap sentence : annotation.get(CoreAnnotations.SentencesAnnotation.class))
        {
            //for each sentence, we get the sentiment that CoreNLP thinks this sentence indicates.
            Tree sentimentTree = sentence.get(SentimentCoreAnnotations.AnnotatedTree.class);
            int sentimentClassIdx = RNNCoreAnnotations.getPredictedClass(sentimentTree);
            SentimentClass sentimentClass = SentimentClass.getSpecific(sentimentClassIdx);

            /*
             * Each possible sentiment has an associated probability, so let's pull the entire
             * set of probabilities across all sentiment classes.
             */
            double[] probs = new double[SentimentClass.values().length];
            {
                SimpleMatrix mat = RNNCoreAnnotations.getPredictions(sentimentTree);
                for(int i = 0;i < SentimentClass.values().length;++i)
                {
                    probs[i] = mat.get(i);
                }
            }
            /*
             * Add the sentence and the associated probabilities to our list.
             */
            String sentenceStr = AnnotationUtils.sentenceToString(sentence).replace("\n", "");
            sentences.add(new Sentence(probs, sentenceStr, sentimentClass));
        }

        /*
         * Finally, rollup the score of the entire document given the list of sentiments
         * for each sentence.
         *
         * I have found that this is a surprisingly difficult thing.  We're going to use the fact that
         * we are mapping these documents onto Positive, Negative to use a technique that people use
         * to figure out overall product ratings from individual star ratings, the Wilson Score.
         * See http://www.evanmiller.org/how-not-to-sort-by-average-rating.html.
         *
         * For your convenience, I have implemented a number of other approaches, including:
         *  * Basic majority-rule voting
         *  * Max probability across all sentiments for all sentences
         *  * Last sentence wins
         *  * Longest sentence wins
         *
         */
        return SentimentRollup.WILSON_SCORE.apply(sentences);