import org.apache.commons.math3.stat.regression.OLSMultipleLinearRegression;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.ArrayList;

/**
 * Created by shumailovr on 22.04.15.
 */

@Entity
@Table(name = "regression_parameters")
public class RegressorParameterModel {

    private String regressor;
    private double parameter;

    public RegressorParameterModel() {
    }

    public RegressorParameterModel(String regressor, double parameter) {
        this.regressor = regressor;
        this.parameter = parameter;
    }

    @Id
    @Column(name = "regressor")
    public String getRegressor() {
        return regressor;
    }

    public void setRegressor(String regressor) {
        this.regressor = regressor;
    }

    @Column(name = "parameter")
    public double getParameter() {
        return parameter;
    }

    public void setParameter(double parameter) {
        this.parameter = parameter;
    }

    /**
     * Calculates regression parameters
     */
    public static void calculateAndSaveRegressionParameters() {
        PersistenceManager persistenceManager = new PersistenceManager();

        int euclDistancesCount = (int)persistenceManager.countEuclideanDistances();
        //
        System.out.println(euclDistancesCount);

        //n-vector regressand
        double[] y = new double[euclDistancesCount];

        //[n,k] regressors matrix
        double[][] x = new double[euclDistancesCount][12];

        ArrayList<TrainingEuclideanDistanceModel> euclDistances = persistenceManager.getTrainingEuclideanDistances();

        for (int i = 0; i < euclDistancesCount; i++) {

            //Get current distance
            TrainingEuclideanDistanceModel euclDistance = euclDistances.get(i);

            //Add regressand
            y[i] = euclDistance.getDistance();

            //Calc corresponding regressors from taken book pair, for that take both books parameters and for every
            //parameter pair find their euclidean distance
            BXBookModel book1 = persistenceManager.getBXBookByIsbn(euclDistance.getTrainingEuclideanDistanceId().getIsbn1());
            BXBookModel book2 = persistenceManager.getBXBookByIsbn(euclDistance.getTrainingEuclideanDistanceId().getIsbn2());

            AnalyzedBookModel analyzedBook1 = persistenceManager.getAnalyzedBookByTitleAndAuthor(book1.getTitle(), book1.getAuthor());
            AnalyzedBookModel analyzedBook2 = persistenceManager.getAnalyzedBookByTitleAndAuthor(book2.getTitle(), book2.getAuthor());

            //Form new regressors vector for this book pair
//            System.out.println("FIND REGRESSORS");
            double averSentenceLength = Math.abs(analyzedBook1.getAverSentenceLength() - analyzedBook2.getAverSentenceLength());
//            System.out.println(averSentenceLength);
            double averWordLength = Math.abs(analyzedBook1.getAverWordLength() - analyzedBook2.getAverWordLength());
//            System.out.println(averWordLength);
            double charSum = Math.abs(analyzedBook1.getCharactersNum() - analyzedBook2.getCharactersNum());
//            System.out.println(charSum);
            double datesSum = Math.abs(analyzedBook1.getDates() - analyzedBook2.getDates());
//            System.out.println(datesSum);
            double locationsSum = Math.abs(analyzedBook1.getLocations() - analyzedBook2.getLocations());
//            System.out.println(locationsSum);
            double namesSum = Math.abs(analyzedBook1.getNames() - analyzedBook2.getNames());
//            System.out.println(namesSum);
            double wordsSum = Math.abs(analyzedBook1.getWordsNum() - analyzedBook2.getWordsNum());
//            System.out.println(wordsSum);
            double relAdjNum = Math.abs(analyzedBook1.getRelAdjectives() - analyzedBook2.getRelAdjectives());
//            System.out.println(relAdjNum);
            double relNounsNum = Math.abs(analyzedBook1.getRelNouns() - analyzedBook2.getRelNouns());
//            System.out.println(relNounsNum);
            double relVerbsNum = Math.abs(analyzedBook1.getRelVerbs() - analyzedBook2.getRelVerbs());
//            System.out.println(relVerbsNum);
            double sentencesSum = Math.abs(analyzedBook1.getSentencesNum() - analyzedBook2.getSentencesNum());
//            System.out.println(sentencesSum);
            double positiveness = Math.abs(analyzedBook1.getPositiveness() - analyzedBook2.getPositiveness());
//            System.out.println(positiveness);
//            System.out.println("FINISH FIND REGRESSORS");

            //Form the vector
            double[] regressorsVector = new double[]{
                    averSentenceLength, averWordLength, charSum, datesSum,
                    locationsSum, namesSum, wordsSum, relAdjNum,
                    relNounsNum, relVerbsNum, sentencesSum, positiveness
            };

            //Add regressors vector according to the regressand between those two books
            x[i] = regressorsVector;
        }

        //Init Ordinary Least Squares Multiple Linear Regression
        OLSMultipleLinearRegression multipleLinearRegression = new OLSMultipleLinearRegression();
        //Init regression
        multipleLinearRegression.newSampleData(y, x);

        //Find the coefficients
        double[] parameters = multipleLinearRegression.estimateRegressionParameters();

        for (double d : parameters) {
            System.out.println("D: " + d);
        }

        //Save the parameters in the database
        persistenceManager.saveParameter(new RegressorParameterModel("intercept", parameters[0]));
        persistenceManager.saveParameter(new RegressorParameterModel("averSentenceLength", parameters[1]));
        persistenceManager.saveParameter(new RegressorParameterModel("averWordLength", parameters[2]));
        persistenceManager.saveParameter(new RegressorParameterModel("characters", parameters[3]));
        persistenceManager.saveParameter(new RegressorParameterModel("dates", parameters[4]));
        persistenceManager.saveParameter(new RegressorParameterModel("locations", parameters[5]));
        persistenceManager.saveParameter(new RegressorParameterModel("names", parameters[6]));
        persistenceManager.saveParameter(new RegressorParameterModel("words", parameters[7]));
        persistenceManager.saveParameter(new RegressorParameterModel("relAdjectives", parameters[8]));
        persistenceManager.saveParameter(new RegressorParameterModel("relNouns", parameters[9]));
        persistenceManager.saveParameter(new RegressorParameterModel("relVerbs", parameters[10]));
        persistenceManager.saveParameter(new RegressorParameterModel("sentences", parameters[11]));
        persistenceManager.saveParameter(new RegressorParameterModel("positiveness", parameters[12]));
    }
}
