/*
 *  Copyright (C) 2010-2014 JPEXS, All rights reserved.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3.0 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.
 */
package com.jpexs.decompiler.flash.timeline;

import com.jpexs.decompiler.flash.types.MATRIX;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * NOT WORKING STUB!!! FIXME
 *
 * @author JPEXS
 */
public class TweenDetector {

    public static List<TweenRange> detectRanges(List<MATRIX> matrices) {
        //TODO: make this working :-(
        return new ArrayList<>();
        /*
        
         List<TweenRange> ret = new ArrayList<>();
         double tolerance = 1;
         int min = 3;
         int startpos = 0;
         Double last = null;
         int i = min;
         List<Double> translateX=new ArrayList<>();
         List<Double> translateY=new ArrayList<>();
         List<Double> scaleX=new ArrayList<>();
         List<Double> scaleY=new ArrayList<>();
         List<Double> rotateSkew0=new ArrayList<>();
         List<Double> rotateSkew1=new ArrayList<>();
        
        
         Set<MATRIX> ms=new HashSet<MATRIX>();
         ms.addAll(matrices);
         if(ms.size()==1){
         return new ArrayList<>();
         }
        
        
         for(MATRIX n:matrices){
         //...
         }                       
        
         for (; startpos + i <= matrices.size() + 1; i++) {            
         double errTranslateX = startpos + i > matrices.size() ? Double.MAX_VALUE : getErrorLevel(translateX, startpos, i);
         double errTranslateY = startpos + i > matrices.size() ? Double.MAX_VALUE : getErrorLevel(translateY, startpos, i);
         double errScaleX = startpos + i > matrices.size() ? Double.MAX_VALUE : getErrorLevel(scaleX, startpos, i);
         double errScaleY = startpos + i > matrices.size() ? Double.MAX_VALUE : getErrorLevel(scaleY, startpos, i);
         double errRotateSkew0 = startpos + i > matrices.size() ? Double.MAX_VALUE : getErrorLevel(rotateSkew0, startpos, i);
         double errRotateSkew1 = startpos + i > matrices.size() ? Double.MAX_VALUE : getErrorLevel(rotateSkew1, startpos, i);
         double err = startpos + i > matrices.size()?Double.MAX_VALUE:(errTranslateX/20+errTranslateY/20+0.1*errScaleX+0.1*errScaleY+errRotateSkew0/360+errRotateSkew1/360);
         if (err > tolerance) {
         if (last == null) {
         startpos++;
         i = min - 1;
         continue;
         }
         ret.add(new TweenRange(startpos, startpos+i-1-1));                
         startpos = startpos + i -1;
         i = min - 1;
         last = null;
         continue;
         }
         last = err;
         }
         return ret;*/
    }

    private static double getErrorLevel(List<Double> yValues, int start, int len) {
        double[] ret = calc(yValues, start, len);
        double a = ret[0];
        double b = ret[1];
        double sumdelta = 0;
        double maxdelta = 0;
        for (int i = start; i < start + len; i++) {
            double yorig = yValues.get(i);
            double ynew = a + b * (i - start);
            double ydelta = Math.abs(ynew - yorig);
            sumdelta += ydelta;
            if (ydelta > maxdelta) {
                maxdelta = ydelta;
            }
        }
        return maxdelta; //sumdelta / len;
    }

    private static double[] calc(List<Double> yValues, int start, int len) {
        List<Double> xValues = new ArrayList<>();
        for (int i = 0; i < len; i++) {
            xValues.add((double) i);
        }

        yValues = yValues.subList(start, start + len);

        // get the value of the gradient using the formula b = cov[x,y] / var[x]
        double b = covariance(xValues, yValues) / variance(xValues);
        // get the value of the y-intercept using the formula a = ybar + b * xbar
        double a = mean(yValues) - b * mean(xValues);
        return new double[]{a, b};
    }

    /*
     * Calculate the covariance of two sets of data
     *
     * @param x
     *          The first set of data
     * @param y
     *          The second set of data
     * @return The covariance of x and y
     */
    private static double covariance(List<Double> x, List<Double> y) {
        double xmean = mean(x);
        double ymean = mean(y);

        double result = 0;

        for (int i = 0; i < x.size(); i++) {
            result += (x.get(i) - xmean) * (y.get(i) - ymean);
        }

        result /= x.size() - 1;

        return result;
    }

    /**
     * Calculate the mean of a data set
     *
     * @param data The data set to calculate the mean of
     * @return The mean of the data set
     */
    private static double mean(List<Double> data) {
        double sum = 0;

        for (int i = 0; i < data.size(); i++) {
            sum += data.get(i);
        }

        return sum / data.size();
    }

    /**
     * Calculate the variance of a data set
     *
     * @param data The data set to calculate the variance of
     * @return The variance of the data set
     */
    private static double variance(List<Double> data) {
        // Get the mean of the data set
        double mean = mean(data);

        double sumOfSquaredDeviations = 0;

        // Loop through the data set
        for (int i = 0; i < data.size(); i++) {
            // sum the difference between the data element and the mean squared
            sumOfSquaredDeviations += Math.pow(data.get(i) - mean, 2);
        }

        // Divide the sum by the length of the data set - 1 to get our result
        return sumOfSquaredDeviations / (data.size() - 1);
    }
}
