/*
 * Copyright (C) 2022 - Florindo Smilari (spherIC)
 */
package ch.spherIC.recurvebowsight.ui.calcsight;

import android.os.Bundle;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.TabStopSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import org.achartengine.GraphicalView;
import org.achartengine.model.XYSeries;

import java.text.DecimalFormat;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import ch.spherIC.recurvebowsight.R;
import ch.spherIC.recurvebowsight.components.FlightCurveChart;
import ch.spherIC.recurvebowsight.components.XTextView;
import ch.spherIC.recurvebowsight.databinding.FragmentCalcsightTrajectoryBinding;
import ch.spherIC.recurvebowsight.logic.BallisticResults;
import ch.spherIC.recurvebowsight.logic.TrajectoryCalculator;
import ch.spherIC.recurvebowsight.utilities.UnitConverter;

public class CalculateSightTrajectoryFragment extends Fragment {

    public static final DecimalFormat DF_FC = new DecimalFormat("0.000");

    private FragmentCalcsightTrajectoryBinding binding;
    private FlightCurveChart flightCurveChart;
    private XTextView flightCurveTxtFld;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        this.binding = FragmentCalcsightTrajectoryBinding.inflate(inflater, container, false);
        View root = this.binding.getRoot();
        this.flightCurveTxtFld = (XTextView) root.findViewById(R.id.flightCurveTxtFld);

        GraphicalView flightCurveChartView;
        LinearLayout layout;
        this.flightCurveChart = new FlightCurveChart();
        flightCurveChartView = this.flightCurveChart.getView(root.getContext());
        layout = (LinearLayout) root.findViewById(R.id.ballisticResults);
        layout.addView(flightCurveChartView, 0, new LinearLayout.LayoutParams(ViewGroup.MarginLayoutParams.MATCH_PARENT, 0, 1f));

        getParentFragmentManager().setFragmentResultListener("ballisticResults", this, (requestKey, bundle) -> {
            if (requestKey.equals("ballisticResults")) {
                BallisticResults ballisticResults = bundle.getParcelable("ballisticResults");
                updateFlightCurveChart(ballisticResults.getFlightCurve());
                updateTrajectoryTxtFld(ballisticResults);
            }
        });

        return root;
    }


    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }

    /**
     * Updates the graph.
     *
     * @param flightCurve values to draw the flight curve
     */
    private void updateFlightCurveChart(final Double[][] flightCurve) {

        XYSeries series = new XYSeries(this.binding.getRoot().getResources().getString(R.string.fcChart_TitleLable));

        for (Double[] doubles : flightCurve) {
            series.add(doubles[TrajectoryCalculator.IDX_X], doubles[TrajectoryCalculator.IDX_Y]);
        }

        this.flightCurveChart.getDataSet().removeSeries(0);
        this.flightCurveChart.getDataSet().addSeries(0, series);
        this.flightCurveChart.updateRendererAfterCalculation(flightCurve[flightCurve.length - 1][TrajectoryCalculator.IDX_X], flightCurve);
    }

    private void updateTrajectoryTxtFld(BallisticResults ballisticResults) {
        updateTrajectoryTxtFld(0, ballisticResults.getFlightCurve()[0], ballisticResults.getStartAngle(), ballisticResults.getMaxHCurve(), ballisticResults.getFlightDuration());
        Double[][] flightCurve = ballisticResults.getFlightCurve();
        for (Double[] doubles : flightCurve) {
            updateTrajectoryTxtFld(1, doubles, null, null, null);
        }
    }


    /**
     * Updates the text table field.
     *
     * @param flightCurveRow values to text one flight curve row
     * @param startAngle the start angle to display
     * @param maxHCurve max values of the flight curve
     */
    private void updateTrajectoryTxtFld(final Integer step, final Double[] flightCurveRow, final Double startAngle, final Double[] maxHCurve, final Double flightDuration) {
        int width = getParentFragment().getView().findViewById(R.id.fragment_calcsight_parameters).getMeasuredWidth() - UnitConverter.dpToPxH(2 * 8);

        switch (step) {
            case 0:
                TextView arrowNockHeightTxtFld = (TextView) getParentFragment().getView().findViewById(R.id.arrowNockHeightTxt);
                this.flightCurveTxtFld.setText("");
                this.flightCurveTxtFld.append(getResources().getString(R.string.fcChart_StartAngle) + DF_FC.format(startAngle) + " °\n\n");
                this.flightCurveTxtFld.append(getResources().getString(R.string.fcChart_MaxHeight) + DF_FC.format(maxHCurve[0])
                                                      + " m / "
                                                      + DF_FC.format(maxHCurve[0] + Double.parseDouble(arrowNockHeightTxtFld.getText().toString().trim()))
                                                      + " m,  [t = " + DF_FC.format(maxHCurve[1]) + " s]\n\n");
                this.flightCurveTxtFld.append(getResources().getString(R.string.fcChart_FlightDuration)
                                                      + DF_FC.format(flightDuration)
                                                      + " sec\n\n");


                SpannableString line = new SpannableString("t [sec]\tVx [m/s]\tVy [m/s]\tx [m]\ty [m]\n\n");
                line.setSpan(new TabStopSpan.Standard(width / 5), 0, line.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                line.setSpan(new TabStopSpan.Standard(width / 5 * 2), 0, line.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                line.setSpan(new TabStopSpan.Standard(width / 5 * 3), 0, line.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                line.setSpan(new TabStopSpan.Standard(width / 5 * 4), 0, line.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                this.flightCurveTxtFld.append(line);
                break;

            case 1:
                line = new SpannableString(DF_FC.format(flightCurveRow[TrajectoryCalculator.IDX_T]) + '\t'
                                                   + DF_FC.format(flightCurveRow[TrajectoryCalculator.IDX_VX]) + '\t'
                                                   + DF_FC.format(flightCurveRow[TrajectoryCalculator.IDX_VY]) + '\t'
                                                   + DF_FC.format(flightCurveRow[TrajectoryCalculator.IDX_X]) + '\t'
                                                   + DF_FC.format(flightCurveRow[TrajectoryCalculator.IDX_Y]) + "\n");
                line.setSpan(new TabStopSpan.Standard(width / 5), 0, line.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                line.setSpan(new TabStopSpan.Standard(width / 5 * 2), 0, line.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                line.setSpan(new TabStopSpan.Standard(width / 5 * 3), 0, line.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                line.setSpan(new TabStopSpan.Standard(width / 5 * 4), 0, line.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                this.flightCurveTxtFld.append(line);
                break;

            default:
                break;
        }
    }
}