/**
 * Copyright (C) 2005-2012 XELOG AG
 */
package ch.spherIC.recurvebowsight.logic;

import android.os.AsyncTask;


/**
 * @author  FC Smilari
 */
public class CalculationTask extends AsyncTask<TrajectoryCalculator, Void, TrajectoryCalculator> {

    private static final Double PHI = 1.0;


    @Override
    protected TrajectoryCalculator doInBackground(final TrajectoryCalculator... params) {

        TrajectoryCalculator calculator = params[0];
        boolean exitLoop = false;
        Double angleX = 0.0;
        Double angleHigh = 0.0;
        Double angleLow = calculator.getStartAngle() + PHI;
        Double[][] results;
        Double frictionCoefficient = calculator.calculateFrictionCoeficient();


        // Startwerte für angleLow und angleHigh berechnen
        do {
            angleLow -= PHI;
            results = calculator.calculateTrajectory(angleLow, frictionCoefficient);
        } while (results[results.length - 1][TrajectoryCalculator.IDX_Y] - calculator.getDeltaHeight() > 0);

        angleHigh = angleLow;

        do {
            angleHigh += PHI;
            results = calculator.calculateTrajectory(angleHigh, frictionCoefficient);
        } while (results[results.length - 1][TrajectoryCalculator.IDX_Y] - calculator.getDeltaHeight() < 0);


        // Winkel suchen mit Hilfe der Regula Falsi und Flugbahnberechnungsiterationen
        do {

            angleX = (angleHigh + angleLow) / 2;
            results = calculator.calculateTrajectory(angleX, frictionCoefficient);

            if (Math.abs(calculator.getDeltaHeight() - results[results.length - 1][TrajectoryCalculator.IDX_Y])
                > calculator.getCalculationPrecision()) {

                if (results[results.length - 1][TrajectoryCalculator.IDX_Y] - calculator.getDeltaHeight() < 0) {
                    angleLow = angleX;
                } else {
                    angleHigh = angleX;
                }

            } else {
                exitLoop = true;
            }

        } while (!exitLoop);

        calculator.setStartAngle(angleX);
        calculator.setFlightCurve(results);
        calculator.setMaxHCurve(calculateMaxHeight(results));

        return calculator;
    }


    public static Double[] calculateMaxHeight(final Double[][] flightCurve) {
        Double[] maxHCurve = new Double[] { 0d, 0d };
        Double maxH = 0.0;

        for (int i = 0; i < flightCurve.length; i++) {
            if (flightCurve[i][TrajectoryCalculator.IDX_Y] > maxH) {
                maxH = flightCurve[i][TrajectoryCalculator.IDX_Y];
                maxHCurve[0] = maxH;
                maxHCurve[1] = flightCurve[i][TrajectoryCalculator.IDX_T];
            }
        }

        return maxHCurve;
    }


    @Override
    protected void onPostExecute(final TrajectoryCalculator calculator) {
        super.onPostExecute(calculator);
        calculator.getListener().onCalculationDone(calculator.getFlightCurve(), calculator.getStartAngle(), calculator.getMaxHCurve());
    }
}
