package de.hems.trafficsim;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;

import java.util.Observable;
import java.util.Observer;

public class MainActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener {
    public static final int defaultNoOfVehicles = 25;
    public static final int defaultTrackLength = 100;
    public static final float defaultBrakeProb = 0.3f;
    public static final float defaultMaxVelocity = 5.0f;
    public static final int defaultDelay = 0;
    public static final int defaultHistoryLength = 50;
    public static final int defaultFrameskip = 0;
    protected Track track;
    protected TimeRecordView trackView;
    protected Worker worker;
    protected Renderer renderer;
    protected LinearLayout viewStack;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.track = new Track(defaultNoOfVehicles, defaultTrackLength, defaultBrakeProb,
                defaultMaxVelocity, defaultDelay, defaultHistoryLength);
        this.viewStack = (LinearLayout) findViewById(R.id.trackViewStack);
        this.trackView = new TimeRecordView(this, track);

        viewStack.addView(this.trackView);
        this.renderer = new Renderer(track, this.trackView.getHolder());

        SeekBar trackLengthSeekBar = (SeekBar) findViewById(R.id.trackLengthSeekBar);
        trackLengthSeekBar.setOnSeekBarChangeListener(this);
        trackLengthSeekBar.setProgress(defaultTrackLength);
        ((TextView)(findViewById(R.id.trackLengthTextView))).setText(String.valueOf(defaultTrackLength));

        SeekBar maxVelocitySeekBar = (SeekBar) findViewById(R.id.maxVelocitySeekBar);
        maxVelocitySeekBar.setOnSeekBarChangeListener(this);
        maxVelocitySeekBar.setProgress((int)defaultMaxVelocity);
        ((TextView)(findViewById(R.id.maxVeloTextView))).setText(String.valueOf((int)defaultMaxVelocity));

        SeekBar noOfVehiclesSeekBar = (SeekBar) findViewById(R.id.noOfVehiclesSeekBar);
        noOfVehiclesSeekBar.setOnSeekBarChangeListener(this);
        noOfVehiclesSeekBar.setProgress(defaultNoOfVehicles);
        ((TextView)(findViewById(R.id.noOfVehiclesTextView))).setText(String.valueOf(defaultNoOfVehicles));

        SeekBar brakeProbabilitySeekBar = (SeekBar) findViewById(R.id.brakeProbabilitySeekBar);
        brakeProbabilitySeekBar.setOnSeekBarChangeListener(this);
        brakeProbabilitySeekBar.setProgress((int)(defaultBrakeProb*20));
        ((TextView)(findViewById(R.id.brakeProbTextView))).setText(String.valueOf(defaultBrakeProb));

        SeekBar delaySeekBar = (SeekBar)(findViewById(R.id.simDelaySeekBar));
        delaySeekBar.setOnSeekBarChangeListener(this);
        delaySeekBar.setProgress(defaultDelay);
        ((TextView)(findViewById(R.id.simDelayTextView))).setText(String.valueOf(defaultDelay));

        SeekBar frameskipSeekBar = (SeekBar)(findViewById(R.id.frameskipSeekBar));
        frameskipSeekBar.setOnSeekBarChangeListener(this);
        frameskipSeekBar.setProgress(defaultFrameskip);
        ((TextView)(findViewById(R.id.frameSkipTextView))).setText(String.valueOf(defaultFrameskip));

        this.updateStats();
    }

    public static float round(float number, int digits) {
        float div = (float) Math.pow(10.0f, digits);
        return Math.round(number*div)/div;
    }

    public void updateStats() {
        final Track trackRef = this.track;
        final TextView lastAvgView = (TextView) findViewById(R.id.avgVeloLastView);
        final TextView overallAvgView = (TextView) findViewById(R.id.avgVeloOverallView);
        final TextView delayedAvgView = (TextView) findViewById(R.id.delayedAvgTextView);
        final TextView stepsView = (TextView) findViewById(R.id.stepsTextView);
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                lastAvgView.setText(String.valueOf(round(trackRef.getLastAvg(), 2)));
                overallAvgView.setText(String.valueOf(round(trackRef.getOverallAvg(), 2)));
                stepsView.setText(String.valueOf(trackRef.getSteps()));
                delayedAvgView.setText(String.valueOf(round(trackRef.getDelayedAvg(), 2)));
            }
        });
    }

    public void onStepButtonClick(View view) {
        this.track.timeElapse();
        this.updateStats();
        this.renderer.draw();
    }

    public void onPlayButtonClick(View view) {
        Button playButton = (Button) findViewById(R.id.playButton);
        playButton.setEnabled(false);
        Button stepButton = (Button) findViewById(R.id.stepButton);
        stepButton.setEnabled(false);
        Button stopButton = (Button) findViewById(R.id.stopButton);
        stopButton.setEnabled(true);
        Button clearButton = (Button) findViewById(R.id.clearButton);
        clearButton.setEnabled(false);

        int frameskip = ((SeekBar)(findViewById(R.id.frameskipSeekBar))).getProgress();
        this.worker = new Worker(track, this, renderer, frameskip);
        this.worker.start();
    }

    public void onStopButtonClick(View view) {
        Button playButton = (Button) findViewById(R.id.playButton);
        playButton.setEnabled(true);
        Button stepButton = (Button) findViewById(R.id.stepButton);
        stepButton.setEnabled(true);
        Button stopButton = (Button) findViewById(R.id.stopButton);
        stopButton.setEnabled(false);
        Button clearButton = (Button) findViewById(R.id.clearButton);
        clearButton.setEnabled(true);

        this.worker.setStop(true);
        try {
            this.worker.join();
        } catch (InterruptedException ex) {

        }
        this.worker = null;
    }

    protected void stopWorker() {
        this.worker.setStop(true);
        try {
            this.worker.join();
        } catch (InterruptedException ex) {
        }
        this.worker = null;
    }

    public void onClearButtonClick(View view) {
        if (this.worker != null) { // There was a simulation running
            this.stopWorker();
        }
        Button playButton = (Button) findViewById(R.id.playButton);
        playButton.setEnabled(true);
        Button stepButton = (Button) findViewById(R.id.stepButton);
        stepButton.setEnabled(true);
        Button stopButton = (Button) findViewById(R.id.stopButton);
        stopButton.setEnabled(false);
        this.updateTrack();
        this.updateStats();
        this.renderer.draw();

    }

    protected void updateTrack() {
        int newTrackLength = ((SeekBar)(findViewById(R.id.trackLengthSeekBar))).getProgress();
        SeekBar noOfVehiclesSeekBar = (SeekBar)(findViewById(R.id.noOfVehiclesSeekBar));
        int newNoOfVehicles = noOfVehiclesSeekBar.getProgress();
        if (newTrackLength < newNoOfVehicles) { // Dont allow values greater than track length!
            newNoOfVehicles = (int) newTrackLength;
            noOfVehiclesSeekBar.setProgress(newNoOfVehicles);

        }
        TextView noOfVehiclesTextView = (TextView)(findViewById(R.id.noOfVehiclesTextView));
        noOfVehiclesTextView.setText(String.valueOf(newNoOfVehicles));

        TextView trackLengthTextView = (TextView)(findViewById(R.id.trackLengthTextView));
        trackLengthTextView.setText(String.valueOf(newTrackLength));

        float newMaxVelocity = ((SeekBar) findViewById(R.id.maxVelocitySeekBar)).getProgress();
        SeekBar brakeProbabilitySeekBar = (SeekBar) findViewById(R.id.brakeProbabilitySeekBar);
        float newBrakeProb = (float)brakeProbabilitySeekBar.getProgress()
                / (float)brakeProbabilitySeekBar.getMax();

        int newDelay = ((SeekBar)(findViewById(R.id.simDelaySeekBar))).getProgress();
        int newFrameskip = ((SeekBar)(findViewById(R.id.frameskipSeekBar))).getProgress();

        boolean wasRunning = this.worker != null;
        if (wasRunning) {
            this.worker.setStop(true);
            try {
                this.worker.join();
            } catch (InterruptedException ex) { }
        }

        this.track = new Track(newNoOfVehicles, newTrackLength, newBrakeProb, newMaxVelocity,
                newDelay, defaultHistoryLength);
        this.renderer.setTrack(this.track);

        if (wasRunning) {
            this.worker = new Worker(track, this, renderer, newFrameskip);
            this.worker.start();
        }
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        if (seekBar == (SeekBar)(findViewById(R.id.noOfVehiclesSeekBar))) {
            this.updateTrack();
        } else if (seekBar == (SeekBar)(findViewById(R.id.brakeProbabilitySeekBar))) {
            float newBrakeProb = (float)seekBar.getProgress() / (float)seekBar.getMax();
            this.track.setBrakeProb(newBrakeProb);
            TextView newBrakeProbTextView = (TextView)(findViewById(R.id.brakeProbTextView));
            newBrakeProbTextView.setText(String.valueOf((newBrakeProb)));
        } else if (seekBar == (SeekBar)(findViewById(R.id.maxVelocitySeekBar))) {
            this.track.setMaxVelocity(seekBar.getProgress());
            TextView tv = (TextView)(findViewById(R.id.maxVeloTextView));
            tv.setText(String.valueOf(progress));
        } else if (seekBar == (SeekBar)(findViewById(R.id.trackLengthSeekBar))) {
            this.updateTrack();
        } else if (seekBar == (SeekBar)(findViewById(R.id.simDelaySeekBar))) {
            TextView tv = (TextView)(findViewById(R.id.simDelayTextView));
            tv.setText(String.valueOf(seekBar.getProgress()));
            this.track.setWaitTime(seekBar.getProgress());
        } else if (seekBar == (SeekBar)(findViewById(R.id.frameskipSeekBar))) {
            TextView tv = (TextView)(findViewById(R.id.frameSkipTextView));
            tv.setText(String.valueOf(seekBar.getProgress()));
            if (this.worker != null) {
                this.worker.setFrameskip(seekBar.getProgress());
            }
        }
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {

    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {

    }
}