package cz.hsrs.track;

import java.sql.SQLException;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

import cz.hsrs.db.model.NoItemFoundException;
import cz.hsrs.db.model.Observation;
import cz.hsrs.db.model.TrackData;
import cz.hsrs.db.model.UnitPosition;
import cz.hsrs.db.util.Util;

public class TrackIgnitionSolver {

    private static final Logger logger = Logger.getLogger(TrackIgnitionSolver.class.getSimpleName());

    private final Util util;
    private final int timeConst;
    public static final int IGNITION_SENSOR_ID = 330040000;

    private final Observation observation;
    private UnitPosition position;
    private UnitPosition positionBefore;
    private Observation observationBefore;


    public TrackIgnitionSolver(Observation obs) throws SQLException {
        observation = obs;
        util = new Util();
        try {
            timeConst = util.getUnitConfTimeById(observation.getUnitId());
        } catch (NoItemFoundException e) {
            throw new SQLException(e);
        }

        try {
            this.position = util.getExactObservationPosition(observation.getTimeStamp(), observation.getUnitId());
        } catch (NoItemFoundException e1) {
            throw new SQLException(e1);
        }
    }

    private boolean initPositionBefore(Date timestamp, long unit_id) throws SQLException {
        try {
            positionBefore = util.getExactObservationPosition(timestamp, unit_id);
            return true;
        } catch (NoItemFoundException e) {
            return false;
        }
    }

    private boolean initObservationBefore() throws SQLException {
        try {
            observationBefore = util.getObservationBefore(position, IGNITION_SENSOR_ID);
            return true;
        } catch (NoItemFoundException e) {
            return false;
        }
    }

    public void solve() throws SQLException {
        if (!initObservationBefore()) {
            /* neexistuje predesla observace -> pokud je nastartovano zaloz track */
            if (observation.getObservedValue() == 1) {
                util.startTrack(position);
            }
            logger.log(Level.INFO, "Zakladam track - neni predchozi observace,"+ position.getUnit_id());
            return;
        }
        
        if (!initPositionBefore(observationBefore.getTimeStamp(),observationBefore.getUnitId() )) {
            solveMissingPreviousPosition();
            return;
        } 
        
        switch (observation.getObservedValue().intValue()) {
            case 1: solveEngineOn();  break;
            case 0: solveEngineOff(); break;
        }
    }

    /** Pripad kdy neexistuje predesla observace s pozici */
    private void solveMissingPreviousPosition() throws SQLException {
        if (observation.getObservedValue()==1){
            switch (observationBefore.getObservedValue().intValue()) {
                case 1: solveEngineWasOn();  break;
                case 0: solveEngineWasOff(); break;
            }
        }
    }
    
    private void solveEngineWasOn() throws SQLException {
        try {
            TrackData td = getOlderTrack(position.getUnit_id(), position.internalGetTimestamp());
            if (!util.wasEngineOn(position.getUnit_id(), td.getEnd(), observationBefore.getTimeStamp())){
                util.startTrack(position);
            } else {
                solveInsertToTrack();
            }
        } catch (NoItemFoundException e) {
            util.startTrack(position);
        }
    }
    
    private void solveEngineWasOff() throws SQLException {
        util.startTrack(position);
    }
    
    private void solveEngineOn() throws SQLException {
        switch (observationBefore.getObservedValue().intValue()) {
        case 1:
            solveInsertToTrack();
                // System.out.println("k posledni observaci je stara pozice");
                // pokud bylo v mezicase chcipnuto zaloz novej
                
                // pokud nebylo v mezicase chcipnuto zaloz pokracuj ve starym
                // tady se musi dodelat jestli mezi pozicema nebylo chipnuto!!!
            break;
        case 0:
            solveStartTrack();
            break;
        }
    }

    private void solveEngineOff() throws SQLException {
        switch (observationBefore.getObservedValue().intValue()) {
            case 1: solveFinishTrack(); break;
            case 0: solveOff(); break;
        }
    }

    private void solveOff() throws SQLException {
        try {
            TrackData track = util.getTrack(observation.getUnitId(), observation.getTimeStamp());
            util.splitTrack(position, track);
        } catch (NoItemFoundException e1) {
            e1.printStackTrace();
        }
    }

    /** Insert to old or running track */
    private void solveInsertToTrack() throws SQLException {
        TrackData track;
        try {
            track = getProperTrack(observation.getUnitId(), observation.getTimeStamp());
            util.addToTrack(track, position);
        } catch (NoItemFoundException e) {
            util.startTrack(position);
            logger.log(Level.INFO, "Zakladam track - starej track nenalezen "+ position.getUnit_id());
        }
    }

    private void solveStartTrack() throws SQLException {
        util.startTrack(positionBefore, position);
    }

    private void solveFinishTrack() throws SQLException {
        try {
            TrackData track = getOlderTrack(observation.getUnitId(), observation.getTimeStamp());
            util.addToTrack(track, position);
        } catch (NoItemFoundException e) {
            try {
                TrackData track = util.getTrack(observation.getUnitId(), observation.getTimeStamp());
                util.splitTrack(position, track);
            } catch (NoItemFoundException e1) {
                throw new SQLException(e1);
            }
        }
    }

    private TrackData getOlderTrack(long unit_id, Date time) throws SQLException, NoItemFoundException {
        return util.getOlderTrack(unit_id, time);
    }

    private TrackData getProperTrack(long unit_id, Date time) throws SQLException, NoItemFoundException {
        TrackData track;
        try {
            try {
                /* try to insert in middle */
                track = util.getTrack(unit_id, time);
            } catch (NoItemFoundException e) {
                /* insert to end */
                track = util.getOlderTrack(unit_id, time);
            }
        } catch (NoItemFoundException e) {
            throw new SQLException(e);
        }
        return track;
    }
}