package ch.hevs.isi;

import ch.hevs.isi.core.BooleanDataPoint;
import ch.hevs.isi.core.DataPoint;
import ch.hevs.isi.core.FloatDataPoint;

public class SmartControl {
    private static final float GRID_VOLTAGE_MIN = 750f;
    private static final float GRID_VOLTAGE_MAX = 875f;
    private static final float GRID_VOLTAGE_TOLERANCE = 25f;
    public static final long TIME_BETWEEN_UPDATES = 100;
    private float spCoal = 0;
    private float spFactory = 0;



    // Useful data points
    private FloatDataPoint clock;
    private FloatDataPoint battChrg;
    private FloatDataPoint battPwrIn;
    private FloatDataPoint remoteCoalSp;
    private FloatDataPoint remoteFactorySp;
    private FloatDataPoint coalAmount;


    // Emergency data points
    private FloatDataPoint gridVoltage;

    // Ideal goal points variables
    private float igpBatteryLevel = 0f;

    // Time variables
    private int day = 1;
    private boolean dayChanged = false;
    private float previousCoalAmount = 0f;
    final float kpiFactory = 0.1f;
    final float kpiCoal = 0.1f;

    private void defineDataPoints(){
        do {
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clock = (FloatDataPoint) DataPoint.getDataPointOnListFromLabel("CLOCK_FLOAT");
            battChrg = (FloatDataPoint) DataPoint.getDataPointOnListFromLabel("BATT_CHRG_FLOAT");
            battPwrIn = (FloatDataPoint) DataPoint.getDataPointOnListFromLabel("BATT_P_FLOAT");
            remoteCoalSp = (FloatDataPoint) DataPoint.getDataPointOnListFromLabel("REMOTE_COAL_SP");
            remoteFactorySp = (FloatDataPoint) DataPoint.getDataPointOnListFromLabel("REMOTE_FACTORY_SP");
            coalAmount = (FloatDataPoint) DataPoint.getDataPointOnListFromLabel("COAL_AMOUNT");
            gridVoltage = (FloatDataPoint) DataPoint.getDataPointOnListFromLabel("GRID_U_FLOAT");
        } while (!testIfDataPointsAreDefined());
        System.out.println("Data points defined");
    }

    private boolean testIfDataPointsAreDefined(){
        if(clock == null) return false;
        if(battChrg == null) return false;
        if(battPwrIn == null) return false;
        if(remoteCoalSp == null) return false;
        if(remoteFactorySp == null) return false;
        if(coalAmount == null) return false;
        if(gridVoltage == null) return false;
        return true;
    }

    private float getTimeOfTheDay(){
        float timeOfTheDay = clock.getValue();
        timeOfTheDay %= 1;
        timeOfTheDay *= 24;
        return timeOfTheDay;
    }

    private float getUnregProducerPower(){
        float producerPower = 0f;
        FloatDataPoint solar = (FloatDataPoint) DataPoint.getDataPointOnListFromLabel("SOLAR_P_FLOAT");
        FloatDataPoint wind = (FloatDataPoint) DataPoint.getDataPointOnListFromLabel("WIND_P_FLOAT");

        producerPower += solar.getValue();
        producerPower += wind.getValue();

        return producerPower;
    }

    private float getUnregConsumerPower(){
        float consumerPower = 0f;
        FloatDataPoint home = (FloatDataPoint) DataPoint.getDataPointOnListFromLabel("HOME_P_FLOAT");
        FloatDataPoint factory = (FloatDataPoint) DataPoint.getDataPointOnListFromLabel("FACTORY_P_FLOAT");
        FloatDataPoint bunker = (FloatDataPoint) DataPoint.getDataPointOnListFromLabel("BUNKER_P_FLOAT");

        consumerPower += home.getValue();
        consumerPower += factory.getValue();
        consumerPower += bunker.getValue();
        return consumerPower;
    }

    private boolean checkIfGridIsFine(){
        boolean gridIsFine = true;

        // Grid voltage is too high
        if(gridVoltage.getValue() > (GRID_VOLTAGE_MAX-GRID_VOLTAGE_TOLERANCE)) {
            gridIsFine = false;
            new BooleanDataPoint("SOLAR_CONNECT_ST", true).setValue(false);
            new BooleanDataPoint("WIND_CONNECT_ST", true).setValue(false);
            remoteCoalSp.setValue(0f);
            if(gridVoltage.getValue() > GRID_VOLTAGE_MAX) {
                remoteFactorySp.setValue(1f);
            }
        }

        // Grid voltage is too low
        if(gridVoltage.getValue() < (GRID_VOLTAGE_MIN+GRID_VOLTAGE_TOLERANCE)) {
            gridIsFine = false;
            new BooleanDataPoint("SOLAR_CONNECT_ST", true).setValue(true);
            new BooleanDataPoint("WIND_CONNECT_ST", true).setValue(true);
            remoteCoalSp.setValue(1f);
            if(gridVoltage.getValue() < GRID_VOLTAGE_MIN) {
                remoteFactorySp.setValue(0f);
            }
        }

        return gridIsFine;
    }

    private int getPeriodOfDay(){
        float timeOfTheDay = getTimeOfTheDay();

        // 0 = Night, 1 = Morning, 2 = Afternoon
        int periodOfDay = 0;
        if(timeOfTheDay >= 0 && timeOfTheDay < 6) periodOfDay = 1; // Night
        if(timeOfTheDay >= 6 && timeOfTheDay < 12) periodOfDay = 2; // Morning
        if(timeOfTheDay >= 12 && timeOfTheDay < 18) periodOfDay = 3; // Afternoon
        if(timeOfTheDay >= 18 && timeOfTheDay < 24) periodOfDay = 4; // Evening

        return periodOfDay;
    }


    public SmartControl() {

        // start the solar and wind power plants
        new BooleanDataPoint("REMOTE_SOLAR_SW", true).setValue(true);
        new BooleanDataPoint("REMOTE_WIND_SW", true).setValue(true);
        new FloatDataPoint("REMOTE_COAL_SP", true).setValue(0f);
        new FloatDataPoint("REMOTE_FACTORY_SP", true).setValue(0f);

        defineDataPoints();

    }

    public boolean run() {

        if ((getTimeOfTheDay() < 0.5f) && !dayChanged) {
            dayChanged = true;
            day++;
        }
        if (getTimeOfTheDay() > 23f) dayChanged = false;
        if(coalAmount.getValue() > previousCoalAmount) {
            previousCoalAmount = coalAmount.getValue();
            day = 1;
        }

        String debug = "Day " + day + " - ";

        if(battChrg.getValue()<0.45f){
            igpBatteryLevel = 0.45f;
            spCoal = -(battChrg.getValue()-0.45f)*5 + 0.2f;
            debug += "BattChrg < 0.45f - ";
        } else {
            if (getUnregProducerPower() < 500f) {
                spCoal = 0.2f;
            }
        }

        if(battChrg.getValue()>0.55f){
            igpBatteryLevel = 0.55f;
            if(battChrg.getValue()>0.6f) spCoal -= (battChrg.getValue()-0.55f)*kpiCoal;
            debug += "BattChrg > 0.55f";
            spFactory = (battChrg.getValue()-0.55f)*5;
        }

        if(battChrg.getValue()<0.55f){
            igpBatteryLevel = 0.55f;
            spFactory += (battChrg.getValue()-0.55f)*kpiFactory;
            debug += "BattChrg < 0.55f";
        }

        new FloatDataPoint("IGP_BATTERY_LEVEL", true).setValue(igpBatteryLevel);

        if (spFactory > 1f) spFactory = 1f;
        if (spFactory < 0f) spFactory = 0f;
        if (spCoal > 1f) spCoal = 1f;
        if (spCoal < 0f) spCoal = 0f;

        new FloatDataPoint("REMOTE_FACTORY_SP", true).setValue(spFactory);
        new FloatDataPoint("REMOTE_COAL_SP", true).setValue(spCoal);

        System.out.println(debug);

        return checkIfGridIsFine();
    }
}
