<?php

include_once "server/class/UnitsManager.php";
include_once "server/lib/mod_util/Util.php";

class logManager {

    private $stops = array();
    private $tracks = array();
    private $posPoints = array();
    private $ignOnPoints = array();
    private $ignOffPoints = array();
    private $alertPoints = array();
    private $maxAllowedSpeed;
    private $firstKm;
    private $lastKm;
    private $firstHr;
    private $lastHr;
    private $elapTime;
    private $maxSpeed;
    private $id;
    private $fm;
    private $to;

    function __construct($id = null, $fm = null, $to = null) {

        $this->id = $id;
        $this->fm = $fm;
        $this->to = $to;
    }

    function getLogXML() {

        $from = $this->fm; //UnitManager::getAdjustedTimestamp($this->fm);
        $to = $this->to; //UnitManager::getAdjustedTimestamp($this->to);
        $this->loadLog($this->id, $from, $to);

        $logXML = sprintf("<?xml version='1.0' encoding='utf-8'?><log unit=\"%s\" fm=\"%s\" to=\"%s\">\n%s\n%s\n%s\n%s\n%s</log>",
                $this->id, $from, $to,
                //UnitManager::getAdjustedTimestamp($this->to),
                $this->getPointsXML(), $this->getStopsXML(),
                $this->getOverSpeedXML(),
                $this->getIgnOnXML(),
                $this->getAlertXML());
        return $logXML;
    }

    function getAlertXML() {

        $alertXMLBody = "";

        try {
            foreach ($this->alertPoints as $i => $alert) {
                $processedAlert = $this->buildAlert($i + 1, $alert['lat'], $alert['lng'], $alert['timestamp'], $alert['total_mileage'], $alert['abstractType'], $alert['description']);
                $alertXMLBody .= $processedAlert['xml'];
            }
        } catch (Exception $e) {
            
        }
        $ignOnXML = sprintf("<alerts count=\"%s\" >\n", count($this->alertPoints));
        $ignOnXML .= $alertXMLBody;
        $ignOnXML .= "</alerts>\n";
        return $ignOnXML;
    }

    function buildAlert($id, $lat, $lng, $inicio, $odo, $type, $descr) {
        $processedAlert['xml'] = sprintf("<alert id=\"%s\" lat=\"%s\" lng= \"%s\" timestamp=\"%s\" ref=\"%s\" odometer=\"%s\" alertType=\"%s\" descr=\"%s\"/>\n", $id, $lat, $lng, Util::getFormatedDate($inicio), GeoUtils::getReferenceText($lat, $lng), $odo, $type, $descr);
        return $processedAlert;
    }

    function getOverspeedXML() {

        $overspeedXMLBody = "";

        $max = -1;
        $accumulatedTime = 0;

        if (is_array($this->tracks) && count($this->tracks)) {

            foreach ($this->tracks as $i => $track) {
                $processedTrack = $this->buildTrack($i, $track);
                $max = ($processedTrack['maxSpeed'] > $max) ? $processedTrack['maxSpeed'] : $max;
                $duration = $processedTrack['duration'];
                $accumulatedTime += $duration;
                $overspeedXMLBody .= $processedTrack['xml'];
            }
        } else {
            
        }
        $overspeedXML = sprintf("<tracks count=\"%s\" maxSpeed=\"%s\" accumulatedTime=\"%s\">\n", count($this->tracks), $max, Util::getFormattedTimeDiff($accumulatedTime));
        $overspeedXML .= $overspeedXMLBody;
        $overspeedXML .= "</tracks>";
        return $overspeedXML;
    }

    function buildTrack($i, $track) {
        $trackXML = "";
        if (is_array($track) && count($track)) {
            $startTimestamp = $track[0]['timestamp'];
            $endTimestamp = $track[count($track) - 1]['timestamp'];
            $startOdometer = $track[0]['mileage'];
            $endOdometer = $track[count($track) - 1]['mileage'];

            $elapTime = ($endTimestamp - $startTimestamp);
            $miles = ($endOdometer - $startOdometer);
            $avgSpd = ($elapTime > 0) ? number_format(3600 * ($miles / $elapTime ), 0) : "-";

            $trackXML .= sprintf("\t<track id=\"%d\" startTime=\"%s\" endTime=\"%s\" startMileage=\"%s\" endMileage=\"%s\" fTime=\"%s\" avgSpd=\"%s\" maxSpd=\"<MAX>\" >\n", $i, Util::getFormatedDate($startTimestamp), Util::getFormatedDate($endTimestamp), $startOdometer, $endOdometer, Util::getFormattedTimeDiff(($endTimestamp - $startTimestamp)), $avgSpd);

            $maxSpd = 0;
            $startTimestamp = null;
            $endTimestamp = null;
            foreach ($track as $j => $point) {
                $startTimestamp = (is_null($startTimestamp)) ? $point['timestamp'] : $startTimestamp;
                $trackXML .= sprintf("\t\t<point lat=\"%s\" lng=\"%s\" timestamp=\"%s\" speed=\"%s\" mileage=\"%s\" />", $point['lat'], $point['lng'], date("d/m H:i", ($point['timestamp']) + (SYS_TIMEZONE * 3600)), $point['speed'], $point['mileage']);
                if ($point['speed'] > $maxSpd)
                    $maxSpd = $point['speed'];
                $endTimestamp = $point['timestamp'];
            }
            $trackXML = str_replace("<MAX>", $maxSpd, $trackXML);
            $trackXML .= "</track>";
        }
        $processedTrack['xml'] = $trackXML;
        $processedTrack['maxSpeed'] = $maxSpd;
        $processedTrack['duration'] = ($endTimestamp - $startTimestamp);
        return $processedTrack;
    }

    function getIgnOnXML() {

        $ignOnXMLBody = "";

        try {
            foreach ($this->ignOnPoints as $i => $ignOn) {
                $processedIgnOn = $this->buildIgnOn($i + 1, $ignOn['lat'], $ignOn['lng'], $ignOn['timestamp'], $ignOn['total_mileage']);
                $ignOnXMLBody .= $processedIgnOn['xml'];
            }
        } catch (Exception $e) {
            
        }
        $ignOnXML = sprintf("<ignOns count=\"%s\" >\n", count($this->ignOnPoints));
        $ignOnXML .= $ignOnXMLBody;
        $ignOnXML .= "</ignOns>\n";
        return $ignOnXML;
    }

    function buildIgnOn($id, $lat, $lng, $inicio, $odo) {
        $processedignOn['xml'] = sprintf("<ignOn id=\"%s\" lat=\"%s\" lng= \"%s\" timestamp=\"%s\" ref=\"%s\" odometer=\"%s\"/>\n", $id, $lat, $lng, Util::getFormatedDate($inicio), GeoUtils::getReferenceText($lat, $lng), $odo);
        return $processedignOn;
    }

    function getStopsXML() {

        $stopsXMLBody = "";
        $accumulatedTime = 0;

        try {
            foreach ($this->stops as $i => $stop) {
                $processedStop = $this->buildStop($i + 1, $stop['lat'], $stop['lng'], $stop['start'], $stop['end'], $stop['mileage']);
                $stopsXMLBody .= $processedStop['xml'];
                $accumulatedTime += $processedStop['duration'];
            }
        } catch (Exception $e) {
            
        }
        $stopsXML = sprintf("<stops count=\"%s\" accumulatedTime=\"%s\">\n", count($this->stops), Util::getFormattedTimeDiff($accumulatedTime));
        $stopsXML .= $stopsXMLBody;
        $stopsXML .= "</stops>";
        return $stopsXML;
    }

    function buildStop($id, $lat, $lng, $inicio, $fin, $odo) {
        $processedStop['xml'] = sprintf("<stop id=\"%s\" lat=\"%s\" lng= \"%s\" start=\"%s\" end=\"%s\" duration=\"%s\" ref=\"%s\" odometer=\"%s\"/>\n", $id, $lat, $lng, Util::getFormatedDate($inicio), Util::getFormatedDate($fin), Util::getFormattedTimeDiff($fin - $inicio), GeoUtils::getReferenceText($lat, $lng), $odo);
        $processedStop['duration'] = $fin - $inicio;
        return $processedStop;
    }

    function getLapse() {
        $seconds = $this->to - $this->fm;
        return $seconds;
    }

    function getTasaUso() {
        $segundosUso = ($this->lastHr - $this->firstHr) * 3600;
        return number_format(($segundosUso / ($this->getLapse())) * 100, 2);
    }

    function getPointsXML() {
        $pointsXML = sprintf("<markers maxAllowedSpeed=\"%s\" count=\"%s\" startKm=\"%s\" endKm=\"%s\" startHr=\"%s\" endHr=\"%s\" totalHr=\"%s\" tasaUso=\"%s\" maxSpd=\"%s\">\n", $this->maxAllowedSpeed, count($this->posPoints), $this->firstKm, $this->lastKm, $this->firstHr, $this->lastHr, number_format($this->getLapse() / 3600, 1), $this->getTasaUso(), $this->maxSpeed);
        try {
            foreach ($this->posPoints as $i => $point) {
                $pointsXML .= $this->getPointXML($point);
            }
        } catch (Exception $e) {
            
        }
        $pointsXML .= "</markers>";
        return $pointsXML;
    }

    function getPointXML($point) {

        return sprintf("\t%s\n", sprintf('<point logId="%s" unit="%s" time= "%s" lat="%s" lng="%s" spd="%s" hdg="%s" motion="%s" mileage="%s" hours="%s"
				 in1="%s" in2="%s" in3="%s" in4="%s" in5="%s" ad1="%s" ad2="%s" ad3="%s" ign="%s"
				 messageType="%s" originalType="%s" reportId="%s" reportType="%s"
				 abstractType="%s" partialOdom="%s" rumbo="%s" />', $point['log_id'], $point['unit_id'],
                        $point['timestamp'], $point['lat'], $point['lng'], $point['speed'],
                        $point['heading'], $point['motion_status'], $point['total_mileage'], $point['total_hours'],
                        $point['in1'], $point['in2'], $point['in3'], $point['in4'], $point['in5'],
                        $point['ad1'], $point['ad2'], $point['ad3'], $point['ignition'],
                        $point['message_type'], $point['original_type'], $point['report_id'], $point['report_type'],
                        $this->getAbstractType($point), $point['current_hours'], GeoUtils::getRumbo($point['heading'])));
    }

    function loadLog($id, $fm, $to) {


        $this->maxAllowedSpeed = MachineManager::getMaxAllowedSpeed($id);

        $maxSpeed = 0;

        $unitConstraint = MachineManager::buildUnitConstraint($id);
        $timeConstraint = sprintf("(timestamp BETWEEN %s AND %s)", $fm, $to);
        $query = sprintf("SELECT p.*,from_unixtime(timestamp) as fecha FROM log_position p WHERE %s AND %s ORDER BY timestamp,log_id", $unitConstraint, $timeConstraint);
        $dao = new dbObject();

        $res = $dao->fetchQuery($query);


        if (is_array($res) && count($res)) {

            // Detecci�n de paradas
            $stops = Array();
            $lastQuietTimestamp = $res[0]['timestamp'];
            $lastQuietLat = $res[0]['lat'];
            $lastQuietLng = $res[0]['lng'];
            $lastQuietMileage = $res[0]['total_mileage'];
            $currentlyQuiet = false;

            // Detecci�n de excesos de velocidad
            $tracks = array();
            $trackOpen = false;


            $maxSpeed = $this->maxAllowedSpeed;

            $this->firstKm = null;
            $this->firstHr = null;
            $this->maxSpeed = null;

            $kmAcumulados = 0;

            foreach ($res as $i => $point) {

                if (is_null($this->firstHr))
                    $this->firstHr = $point['total_hours'];
                if (is_null($this->firstKm)) {
                    $this->firstKm = $point['total_mileage'];
                    $lastKm = $point['total_mileage'];
                }
                if ($lastKm < $point['total_mileage']) {
                    $kmAcumulados += ($point['total_mileage'] - $lastKm < 1) ? $point['total_mileage'] - $lastKm : 0;
                }



                // Chequear detenci�n
                $currentLat = $point['lat'];
                $currentLng = $point['lng'];
                $currentTimestamp = $point['timestamp'];
                $currentMileage = $point['total_mileage'];

                if (GeoUtils::getTheDistance($lastQuietLat, $lastQuietLng, $currentLat, $currentLng) < QUIET_RADIUS) {
                    if ((($currentTimestamp - $lastQuietTimestamp) > QUIET_THRESHOLD) && !$currentlyQuiet) {
                        $currentlyQuiet = true;
                    }
                } else {
                    if ($currentlyQuiet) {
                        $stop['lat'] = $lastQuietLat;
                        $stop['lng'] = $lastQuietLng;
                        $stop['start'] = $lastQuietTimestamp;
                        $stop['end'] = $currentTimestamp;
                        $stop['mileage'] = $lastQuietMileage;
                        $this->stops[] = $stop;
                    }
                    $lastQuietLat = $currentLat;
                    $lastQuietLng = $currentLng;
                    $lastQuietTimestamp = $currentTimestamp;
                    $lastQuietMileage = $currentMileage;
                    $currentlyQuiet = false;
                }

                //Chequear si se super� la m�xima registrada.
                $this->maxSpeed = ($point['speed'] > $this->maxSpeed) ? $point['speed'] : $this->maxSpeed;

                //Chequear excesos de velocidad
                if ($point['speed'] > $maxSpeed) {

                    if (isset($newPoint['lat']) && isset($newPoint['lng']) && isset($newPoint['speed']) && isset($newPoint['timestamp'])) {

                        if (!(($newPoint['lat'] == $point['lat']) && ($newPoint['lng'] == $point['lng']) && ($newPoint['speed'] == $point['speed']) && ($newPoint['timestamp'] == $point['timestamp']))) {
                            $newPoint['lat'] = $point['lat'];
                            $newPoint['lng'] = $point['lng'];
                            $newPoint['speed'] = $point['speed'];
                            $newPoint['timestamp'] = $point['timestamp'];
                            $newPoint['mileage'] = $point['total_mileage'];
                            $track[] = $newPoint;
                        }
                    } else {
                        $newPoint['lat'] = $point['lat'];
                        $newPoint['lng'] = $point['lng'];
                        $newPoint['speed'] = $point['speed'];
                        $newPoint['timestamp'] = $point['timestamp'];
                        $newPoint['mileage'] = $point['total_mileage'];
                        $track[] = $newPoint;
                    }

                    $trackOpen = true;
                } else {
                    if ($trackOpen) {
                        $trackOpen = false;
                        $this->tracks[] = $track;
                        unset($track);
                    }
                }

                $abstractType = $this->getAbstractType($point);


                switch ($abstractType) {

                    case "COR":
                    case "POS":
                        $this->posPoints[] = $point;
                        // Espec�ficamente cuando son puntos de posici�n o giro...

                        break;

                    case "IGN":
                        $this->ignOnPoints[] = $point;
                        break;

                    case "IGF":
                        $this->ignOffPoints[] = $point;
                        break;

                    case "ALM":
                        $point['description'] = "Conexion a alimentacion";
                        $point['abstractType'] = $abstractType;
                        $this->alertPoints[] = $point;
                        break;
                    case "POF":
                        $point['description'] = "Se apaga GPS";
                        $point['abstractType'] = $abstractType;
                        $this->alertPoints[] = $point;
                        break;
                    case "BDD":
                        $point['description'] = "Bateria interna descargada";
                        $point['abstractType'] = $abstractType;
                        $this->alertPoints[] = $point;
                        break;
                    case "GSS":
                        $point['description'] = "Cambio estado GPS";
                        $point['abstractType'] = $abstractType;
                        $this->alertPoints[] = $point;
                        break;

                    default:
                        $point['description'] = "GL Point";
                        $point['abstractType'] = "POS";
                        $point['message_type'] = "+RSP";
                        $point['original_type'] = 7;
                        $this->posPoints[] = $point;
                        break;
                }
            }
            $this->lastKm = abs($point['total_mileage']);
            //$this->lastKm = $this->firstKm + $kmAcumulados; //$point['total_mileage'];
            $this->lastHr = $point['total_hours'];
        }
    }

    function getAbstractType($point) {

        $abstractType = "";

        if ($point['message_type'] == null) {
            $abstractType = "PES";
        }

        if (($point['message_type'] == "+RSP") || ($point['message_type'] == "+BSP")) {
            switch ($point['original_type']) {

                //GTFRI
                case 7:
                    switch ($point["report_type"]) {

                        case 1:
                        case 3:
                            $abstractType = "COR";
                            break;

                        default:
                            $abstractType = "POS";
                            break;
                    }
                    break;
            }
        }

        if (($point['message_type'] == "+EVT") || ($point['message_type'] == "+BVT")) {
            switch ($point['original_type']) {

                //PARA
                case 24:
                    $abstractType = "STP";
                    break;

                //ARRANCA
                case 23:
                    $abstractType = "STA";
                    break;

                //SE ENCIENDE
                case 13:
                    $abstractType = "IGN";
                    break;

                //SE APAGA
                case 14:
                    $abstractType = "IGF";
                    break;

                //SE ALIMENTA
                case 3:
                    $abstractType = "ALM";
                    break;

                //SE TERMINA DE CARGAR LA BAT INT
                case 4:
                    $abstractType = "BOK";
                    break;

                //LA BAT INT ESTA DESCARGADA
                case 6:
                    $abstractType = "BDD";
                    break;

                //POWER OFF
                case 2:
                    $abstractType = "POF";
                    break;

                case 12:
                    // HACER EL MENSAJE MIERDA.
                    break;

                case 21:
                    // Estado de GPS
                    $abstractType = "GSS";
                    break;

                default:
                    $abstractType = "EVT";
                    break;
            }
        }
        return $abstractType;
    }

}
