package fabrik.simulator.pic16f84;

import fabrik.simulator.pic16f84.interfaces.ExecutionTimeObserver;
import fabrik.simulator.pic16f84.interfaces.TimerInterface;

public class Timer extends PICComponent implements TimerInterface, ExecutionTimeObserver {
    private final int TIMERREG = 0x1;
    private final int T0SE = 0x4;
    private final int T0CS = 0x5;
    private final int OPTION = 0x81;

    private int oldpin = 0;
    
    public Timer (){
    }

    public void cycles(int cycles){
        if (dataRegister.getDirectBit(OPTION, T0CS) == 0){
            if (preScaler.isPrescalerOnTimer()){
                for (int i = 0; i < cycles; i++){
                    preScaler.decrement(false);
                }
            } else {
                increment(false);
            }
        }
    }


    public void incrementFromPin (int register){
        if ((dataRegister.getDirectBit(OPTION, T0CS) == 1) && !ExecutionState.isSleeping()){
            int newpin = (register >> 4) & 1;
            if (newpin != oldpin) {
                if (dataRegister.getDirectBit(OPTION, T0SE) == 0) {
                    // Low to high
                    if (newpin == 1 && oldpin == 0) {
                        if (preScaler.isPrescalerOnTimer())
                            preScaler.decrement(true);
                        else
                            increment(true);
                    }
                } else {
                    // High to low
                    if (newpin == 0 && oldpin == 1) {
                        if (preScaler.isPrescalerOnTimer())
                            preScaler.decrement(true);
                        else
                            increment(true);
                    }
                }
                oldpin = newpin;
            }
        }
    }

    public void increment(boolean manual) {
        int timer = dataRegister.getDirectRegister(TIMERREG);
        timer++;
        if (timer > 0xFF){
            interrupts.triggerTMR0(manual);
            dataRegister.setDirectRegister(TIMERREG, 0);
        } else {
            dataRegister.setDirectRegister(1, timer);
        }
    }

    @Override
    public void initialize(PICComponentLocator locator) {
        super.initialize(locator);
        executionTime.registerObserver(this);
    }

    @Override
    public void executionTimeChanged() {
        cycles((int) executionTime.getTotalExecutionTime());
    }
}
