<?php

/**
 * This is the model class for table "storicotable".
 *
 * The followings are the available columns in table 'storicotable':
 * @property string  $ID
 * @property integer $UserID        da mettere a default 1. si può togliere
 * @property string  $EventType     "FILTER","OUT","CHECK","FOLLOW","PASS","IN/OUT","TRAJECTORY","FILTER","BLACKLIST","INTERESTINGEVENTS"
 *                    vedi Gate
 *                    se l'evento ha un transit type definito questo viene inserito nel database.
 *                    altrimenti sia ttiva una ricerca di corrispondenza tra la direzione rilevata dal dispositivo e le direzioni configurate
 *                    nel database nella tabella gatedirections. l'obiettivo è quello di identificare l'evento come ingresso o uscita da un certo varco.
 *                    Se un evento ha direzione con ID=1 e per il varco è configurata una direzione con medesimo ID e verso IN allora l'evento è
 *                    marcato come IN se la direzione è stata rilevata come verso FORWARD o come OUT in caso contrario. se non esiste una direzione
 *                    configurata per il varco, il ragionamento è fatto usando il type del varco stesso.
 *                    se il varco non è IN o OUT, se l'evento non ha una direzione, l'eneto mantiene il type del varco
 * @property string  $EventMode         mettere a default "". contiene la stringa concatenata conseparatore ';' di tutti i tg che identificano il comportamnto del veicolo
 *
 *
 *
 * @property string  $ModifiedBy    nome utente di chi ha effettuato la modifica
 * @property string  $EventValid    "VALID" mettere a default. nel caso di T-EXSPEED è una stringa composta da SN dispositivo_NumeroProgressivoViolazione es 2004_0000000234
 * @property integer $id_validate_user   id dell'utente che ha validato
 * @property string  $ValidatedBy   nome dell'utente che ha validato
 *                    può però assumere anche i segueti valori
 *                    "STANDBY": un evento in standby non può essere validato dall'utente. viene rimosso da standby dopo un periodo configurato
 *                    "YellowFilter": evento con tempo giallo fuori parametri. associato a protocol NO_MULTA
 *                    "PREVALIDATION": non usato
 *                    "AUTOVALIDATION": validato in modo automatco dal sistema.
 *                    "double_gate": associato a NO_MULTA. in una catena di varchi solo il passaggio dal primo viene multato. gli altri diventano NO_MULTA

 *
 * @property string  $ValidationTime    data e ora di validazione
 * @property string  $Protocol      numero di protocollo generato all'esportazione. NO_MULTA se non va esportato l'evento
 * @property integer $NextID        id evento successivo. mettere default a 0
 * @property integer $PreviousID      id evento successivo. mettere default a 0
 * @property integer $TicketID      default 0, numero biglietto per applicazioni parcheggio
 * @property string  $Ticket        default "", stringa identificativo biglietto per applicazioni parcheggio
 *                    per applicazioni T-EXSPEED usato come seriale Unità di elaborazione. meglio aggiungere un campo
 * @property integer $AreaID        id area di appartenenza in areatale
 * @property integer $PositionID      0, non usato
 * @property integer  $Direction      ID Direzione
 * @property double  $Speed       Velocità in Km/H
 * @property string  $Classe        Classe Veicolo
 * @property double  $Height        altezza veicolo in metri
 * @property double  $Width       larghezza veicolo in meri
 * @property double  $Length        lunghezza veicolo in metri
 * @property integer $LaneID        Corsia di appartenenza veicolo, -1 se non definita
 * @property boolean $IsBoxComputed   1 se sono state calcolate la dimensioni del veicolo
 * @property integer $Gate        varco corrispondente
 * @property string  $StartTime     Data/Ora inizio transito
 * @property string  $EndTime     Data/Ora fine transito
 * @property string  $Plate       Targa letta per il veicolo e poi eventualmente corretta a mano
 * @property string  $ExtPlate      Se la targa è stata corretta l'originale è scritto in questo campo
 * @property string  $Nationality   Nazionalità espresso come NNN-xxxxx = NNN->Nazione xxxx->descrizione Layout
 * @property string  $custom_nationality
 * @property string  $NetworkID     Identificativo numerico del tipo di targa
 * @property string  $Image       Binario Immagine
 * @property integer $ImageLength   dimensione binario immagine
 * @property string  $Comments      Commento da parte di chi valida sull'eventuale validazione o sul motivo dello scarto
 * @property string  $ExtraData     Binario con dati aggiuntivi
 * @property integer $ExtraDataLength Dimensione binario dati aggiuntivi
 * @property string  $Signature     binario Firma Elettronica messaggio
 * @property integer $SignatureLength lunhezza binario Firma Elettronica messaggio
 * @property string  $UUID        Identificativo univoco del transito
 * @property integer $ExtraInfoID   Chiave esterna che va si transitextrainfo.ID e su teb_table.EvenID
 * @property double  $MatchMeasure    numero da 0 a 100 che indica l'affidabilità della lettura OCR
 * @property string  $epoch       data inserimento transito
 * @property string  $validation_result
 * @property string  $ext_code
 * @property double  $ocr_quality
  public function actionSuspend($id)
  {
  $event = $this->loadModel($id);


  }
 * @property integer $id_run ID del servizio associato
 * @property string  $GateDescription Descrizione del varco (località)
 * @property string  $TransitComments contiene un commento sull'esito del check di white/black List
 * @property string  $GateType      tipo di dispositivo
 *                    "TRED"  T-RED
 *                    "TID"   T-ID
 *                    "TRS"   T-EXSPEED
 *                    "NONE"  non definito
 * @property string $Kemler       Targa merce pericolosa. "" se non presente
 * @property string $PlateCheck     se 1 indica che quel transito è stato veriicato dal sistema e può essere visionato dall'utente
 *                    se l'utente modifica la targa il transito, quando attiva la verifica di whitelist, PlateCheck deve essere messo a zero perchè
 *                    il sistema lo riprocessi. non può essere quindi validato
 * @property string $BlobFileName   Nome file dell'immagine se è attivo l'export delle immagini da database a disco
 * @property Gate gate
 * @property GateGroup gateGroup
 * @property Service service
 * @property EventBehavior[] eventBehaviors
 * @property EventBehavior[] eventBehaviorsToValidate
 * @property Behavior[] behaviors
 * @property MediaAttachment[] photos
 * @property MediaAttachment[] videos
 * @property VehicleColor colorSet
 * @property EventBehavior[] newEventBehaviors
 * @property EventBehavior[] approvedEventBehaviors
 * @property EventBehavior[] pendingEventBehaviors
 * @property EventBehavior[] voidEventBehaviors
 * @property EventBehavior[] invalidEventBehaviors
 * @property EventBehavior[] toBeManagedEventBehaviors
 * @property Alert alert
 * 
 * SCOPES:
 * @property Event new [scope]
 * @property Event void [scope]
 * @property Event unvoid [scope]
 * @property Event examined [scope]
 * @property Event validated [scope]
 * @property Event exported [scope]
 * @property Event notClosedYet [scope]
 * @property Event examinedNotClosedYet [scope]
 * @property Event pendingNotClosedYet [scope]
 * @property Event notClosedYetNotPending [scope]
 * @property Event examinedNotClosedYetNotPending [scope]
 * @property Event approved [scope]
 * @property Event invalid [scope]
 * @property Event pending [scope]
 * @property Event approvedOrInvalid [scope]
 */
class Event extends ActiveRecord implements IBookmarkObject, IVehicleEvent {

    const STATUS_NEW = "new";
    const STATUS_EXAMINED = "examined";
    const STATUS_VALIDATED = "validated";
    const STATUS_VOID = "void";
    const VALIDATION_RESULT_APPROVED = "approved";
    const VALIDATION_RESULT_INVALID = "invalid";
    const VALIDATION_RESULT_PENDING = "pending";
    const VALIDATION_RESULT_VOID = "void";
    const VALIDATION_RESULT_NO_VALIDATION = "no_validation";
    const SQL_TO_BE_MANAGED = "validation_result is null or validation_result <> 'no_validation'";
    const SQL_NEW_CONDITION = "ValidatedBy = '' AND data_check = 0 AND (validation_result is null or validation_result <> 'no_validation')";
    const SQL_EXAMINED_CONDITION = "data_check = 1";
    const SQL_VALIDATED_CONDITION = "validation_result <> '' and validation_result <> 'no_validation'";
    const SQL_APPROVED_CONDITION = "validation_result = 'approved'";
    const SQL_INVALID_CONDITION = "validation_result = 'invalid'";
    const SQL_PENDING_CONDITION = "validation_result = 'pending'";
    const SQL_VOID_CONDITION = "validation_result = 'void'";
    const SQL_UNVOID_CONDITION = "validation_result <> 'void'";
    const SQL_VALIDATED_NOT_CONFIRMED = "validation_result <> '' and validation_result <> 'no_validation' and (ext_code IS NULL or ext_code ='')";
    const SQL_QUEUED_FOR_EXPORT_CONDITION = "ext_code IS NOT  NULL and ext_code != ''  and ext_code != '-'";
    const SQL_EXPORTED_CONDITION = "Protocol != '' and Protocol != 'NO_MULTA'";
    const SQL_NOT_CLOSED_YET_CONDITION = "(ext_code IS NULL  or ext_code = '') AND (validation_result is null or validation_result <> 'no_validation')";
    const SQL_EXAMINED_NOT_CLOSED_YET_CONDITION = "data_check = 1 AND  (ext_code  IS NULL OR ext_code = '')";
    const SQL_PENDING_NOT_CLOSED_YET_CONDITION = "validation_result = 'pending' AND (ext_code  IS NULL OR ext_code = '')";
    const SQL_NOT_CLOSED_YET_NOT_PENDING_CONDITION = "ext_code IS NULL AND (validation_result IS NULL OR validation_result != 'pending')";
    const SQL_EXAMINED_NOT_CLOSED_YET_NOT_PENDING_CONDITION = "data_check = 1 AND ext_code IS NULL AND (validation_result IS NULL OR validation_result != 'pending')";
    const SQL_PLATE_CHANGED = "ExtPlate != '' and ExtPlate != Plate";
    const SQL_CLASS_CHANGED = "custom_vehicle_type != '' adn custom_vehicle_type is not null and custom_vehicle_type != Classe";
    const OCR_QUALITY_LABEL_BAD = 'bad';
    const OCR_QUALITY_LABEL_MID = 'mid';
    const OCR_QUALITY_LABEL_GOOD = 'good';

    public $event_date_start;
    public $event_date_end;
    public $kemlerSearchString;
    public $search_speed_start;
    public $search_speed_end;
    public $minStartTime;
    public $maxStartTime;
    // fields for the admin search - BEGIN
    public $searchColor = null;
    public $searchBookmarked = false;
    public $searchByResult = null;

    // fields for the admin search - END

    /**
     *
     * @param string $className          
     * @return Event event's model
     */
    public static function model($className = __CLASS__) {
        return parent::model($className);
    }

    public function tableName() {
        return 'storicotable';
    }

    public function myAttributeLabels() {
        return array(
            'id_run' => Yii::t('app', 'Service'),
            'Plate' => Yii::t('app', 'Lic. Plate'),
            'custom_vehicle_type' => Yii::t('app', 'Class'),
            'custom_nationality' => Yii::t('app', 'Nationality'),
            'Kemler' => Yii::t('app', 'Dangerous goods'),
            'custom_plate_type' => Yii::t('app', 'Lic. plate type'),
            'custom_property_type' => Yii::t('app', 'Sub-class'),
            'kemlerSearchString' => t('Kemler-ONU'),
            'alert' => t('Alert'),
            'Nationality' => t('Country'),
            'LaneID' => t('Lane'),
            'Speed' => t('Km/h'),
            'GateID' => t('Gate'),
            'StartDate' => t('Date'),
            'StartTime' => t('Time'),
            'Kemler-ONU' => t('Kemler-ONU')
        );
    }

    public static function getLastServices($lastN = null) {
        if ($lastN != null && $lastN > 0)
            $reader = queryReader("SELECT DISTINCT id_run FROM storicotable ORDER BY id_run DESC LIMIT {$lastN}");
        else
            $reader = queryReader("SELECT DISTINCT id_run FROM storicotable ORDER BY id_run DESC");
        $services = array();
        foreach ($reader as $row) {
            $service = Service::findById($row ['id_run'], false);
            if ($service != null)
                $services [$service->ID] = $service;
        }
        return $services;
    }

    public function elimina() {
        $basePath = Yii::app()->params ['photoBasePath'];
        // extrainfo record
        $teit = EventInfo::model()->findByPk($this->ExtraInfoID);
        if ($teit != null)
            $teit->delete();
        // color record
        $color = VehicleColor::model()->findByPk($this->id_vehicle_color);
        if ($color != null)
            $color->delete();
        // teb file + record
        $tebs = MediaAttachment::model()->findAll('EventID=:eid', array(
            ':eid' => $this->ExtraInfoID
                ));
        if (count($tebs) > 0)
            foreach ($tebs as $teb)
                if ($teb instanceof MediaAttachment) {
                    $filename = pathCombine($basePath, $teb->BlobFileName);
                    if (fileExists($filename))
                        unlink($filename);
                    $teb->delete();
                }
        // event behaviors
        foreach ($this->eventBehaviors as $eb)
            if ($eb instanceof EventBehavior) {
                // event behavior violation documents
                $vdocs = ViolationDocument::model()->findAll('id_event_behavior=:eb', array(
                    ':eb' => $eb->ID
                        ));
                foreach ($vdocs as $vd)
                    if ($vd instanceof ViolationDocument) {
                        $vddf = pathCombine($basePath, $vd->document_filename);
                        if (fileExists($vddf))
                            unlink($vddf);
                        $vddef = pathCombine($basePath, $vd->document_ext_filename);
                        if (fileExists($vddef))
                            unlink($vddef);
                        $vd->delete();
                    }
            }
        // event reportings
        $evreps = Alert::model()->findAll("event_id=:eid AND event_table_name='storicotable'", array(
            ':eid' => $this->ID
                ));
        foreach ($evreps as $er)
            if ($er instanceof Alert)
                $er->delete();
        $bfn = pathCombine($basePath, $this->BlobFileName);
        if (fileExists($bfn))
            unlink($bfn);
        // storicotable
        $this->delete();
    }

    public function rules() {
        $rules = array(
            array(
                'Plate, custom_vehicle_type',
                'requiredIfBehaviorsAreNotInvalid'
            ),
            array(
                'Plate, ExtPlate, Kemler',
                'default',
                'value' => ''
            ),
            array(
                'Plate, LaneID, Gate, StartTime, Nationality, Classe, custom_nationality, custom_vehicle_type, Kemler, custom_plate_type, custom_property_type, event_date_start, event_date_end, kemlerSearchString, search_speed_start, search_speed_end',
                'safe'
            ),
            array(
                'Plate, LaneID, Gate, StartTime, Nationality, Classe, custom_nationality, custom_vehicle_type, Kemler, custom_plate_type, custom_property_type, event_date_start, event_date_end, kemlerSearchString, search_speed_start, search_speed_end',
                'safe',
                'on' => 'search'
            )
        );
        if (paramdeep('events', 'nationality', 'required'))
            $rules [] = array(
                'custom_nationality',
                'requiredIfBehaviorsAreNotInvalid'
            );
        return $rules;
    }

    public function requiredIfBehaviorsAreNotInvalid($attribute, $params) {
        if (($this->validation_result != self::VALIDATION_RESULT_INVALID) && ($this->$attribute == ''))
            $this->addError($attribute, Yii::t('yii', '{attribute} cannot be blank.', array(
                        '{attribute}' => $this->getAttributeLabel($attribute)
            )));
    }

    public function scopes() {

        return array(
            'new' => array(
                'condition' => self::SQL_NEW_CONDITION
            ),
            'void' => array(
                'condition' => self::SQL_VOID_CONDITION
            ),
            'unvoid' => array(
                'condition' => self::SQL_UNVOID_CONDITION
            ),
            'examined' => array(
                'condition' => self::SQL_EXAMINED_CONDITION
            ),
            'validated' => array(
                'condition' => self::SQL_VALIDATED_CONDITION
            ),
            'exported' => array(
                'condition' => self::SQL_EXPORTED_CONDITION
            ),
            'notClosedYet' => array(
                'condition' => self::SQL_NOT_CLOSED_YET_CONDITION
            ),
            'examinedNotClosedYet' => array(
                'condition' => self::SQL_EXAMINED_NOT_CLOSED_YET_CONDITION
            ),
            'pendingNotClosedYet' => array(
                'condition' => self::SQL_PENDING_NOT_CLOSED_YET_CONDITION
            ),
            'notClosedYetNotPending' => array(
                'condition' => self::SQL_NOT_CLOSED_YET_NOT_PENDING_CONDITION
            ),
            'examinedNotClosedYetNotPending' => array(
                'condition' => self::SQL_EXAMINED_NOT_CLOSED_YET_NOT_PENDING_CONDITION
            ),
            'approved' => array(
                'condition' => 'validation_result = :result',
                'params' => array(
                    ':result' => self::VALIDATION_RESULT_APPROVED
                )
            ),
            'invalid' => array(
                'condition' => 'validation_result = :result',
                'params' => array(
                    ':result' => self::VALIDATION_RESULT_INVALID
                )
            ),
            'pending' => array(
                'condition' => 'validation_result = :result',
                'params' => array(
                    ':result' => self::VALIDATION_RESULT_PENDING
                )
            ),
            'approvedOrInvalid' => array(
                'condition' => 'validation_result = :resultApp or validation_result = :resultInv',
                'params' => array(
                    ':resultApp' => self::VALIDATION_RESULT_APPROVED,
                    ':resultInv' => self::VALIDATION_RESULT_INVALID
                )
            ),
            'withPlateModified' => array('condition' => self::SQL_PLATE_CHANGED),
            'withClassModified' => array('condition' => self::SQL_CLASS_CHANGED)
        );
    }

    public function getBookmarkData() {
        $a = $this->alert;
        $e = $this;
        $v = null;

        $bd = new CArray ();

        $bd->has_alert = $a != null;
        if ($a != null) {
            $v = $a->vehicleTrace;
            $bd->alert_id = $a->id;
            $bd->alert_book = Bookmark::model()->find("id_user=:usr AND id_reference=:ref AND type=:typ", array(
                ':usr' => user()->id,
                ':ref' => $bd->alert_id,
                ':typ' => Bookmark::TYPE_ALERT
                    ));
        }

        $bd->has_event = $e != null;
        if ($e != null) {
            $bd->event_id = $e->ID;
            $bd->event_book = Bookmark::model()->find("id_user=:usr AND id_reference=:ref AND type=:typ", array(
                ':usr' => user()->id,
                ':ref' => $bd->event_id,
                ':typ' => Bookmark::TYPE_EVENT
                    ));
        }

        $bd->has_trace = $v != null;
        if ($v != null) {
            $bd->trace_id = $v->ID;
            $bd->trace_book = Bookmark::model()->find("id_user=:usr AND id_reference=:ref AND type=:typ", array(
                ':usr' => user()->id,
                ':ref' => $bd->trace_id,
                ':typ' => Bookmark::TYPE_VEHICLE_TRACE
                    ));
        }

        $bd->self_id = $this->ID;
        $bd->self_type = Bookmark::TYPE_EVENT;
        $bd->self_book = $bd->event_book;

        return $bd;
    }

    /**
     *
     * @param DateTime $begin          
     * @param DateTime $end          
     * @return Event
     */
    public function examinedBetween($begin, $end) {
        $begin = new DateTimeEx($begin);
        $end = new DateTimeEx($end);

        $interval = new CDbCriteria ();
        $interval->addBetweenCondition('data_check_time', $begin->toString(), $end->toString());
        $this->getDbCriteria()
                ->mergeWith($interval);
        return $this;
    }

    /**
     *
     * @param DateTime $begin          
     * @param DateTime $end          
     * @return Event
     */
    public function validatedBetween($begin, $end) {
        $begin = new DateTimeEx($begin);
        $end = new DateTimeEx($end);

        $interval = new CDbCriteria ();
        $interval->addBetweenCondition('ValidationTime', $begin->toString(), $end->toString());
        $this->getDbCriteria()
                ->mergeWith($interval);
        return $this;
    }

    public function validatedAfter($dateTime) {
        $this->getDbCriteria()
                ->mergeWith(array(
                    'condition' => 'ValidationTime >= :startDateTime',
                    'params' => array(
                        ':startDateTime' => DateHelper::formatISO9075DateTime($dateTime)
                    )
                        )
        );
        return $this;
    }

    public function validatedBefore($dateTime) {
        $this->getDbCriteria()
                ->mergeWith(array(
                    'condition' => 'ValidationTime <= :endDateTime',
                    'params' => array(
                        ':endDateTime' => DateHelper::formatISO9075DateTime($dateTime)
                    )
                        )
        );
        return $this;
    }

    public function withBookmark(CDbCriteria $criteria = null) {
        if ($criteria == null)
            $criteria = $this->getDbCriteria();

        $criteria->with [] = 'bookmark';

        return $this;
    }

    public function byExaminer($user) {
        $this->getDbCriteria()
                ->mergeWith(array(
                    'condition' => 'id_data_check_user = :user_id',
                    'params' => array(
                        ':user_id' => $user->id
                    )
                ));
        return $this;
    }

    public function byValidator($user) {
        $this->getDbCriteria()
                ->mergeWith(array(
                    'condition' => 'id_validate_user = :user_id',
                    'params' => array(
                        ':user_id' => $user->id
                    )
                ));
        return $this;
    }

    public function byService($serviceId) {
        $this->getDbCriteria()
                ->mergeWith(array(
                    'condition' => 'id_run = :run_id',
                    'params' => array(
                        ':run_id' => $serviceId
                    )
                ));
        return $this;
    }

    public function bySpeedRange($minSpeed, $maxSpeed) {
        $this->getDbCriteria()
                ->mergeWith(array(
                    'condition' => 'Speed >= :min_speed and Speed <= :max_speed',
                    'params' => array(
                        ':min_speed' => $minSpeed,
                        ':max_speed' => $maxSpeed,
                    )
                ));

        return $this;
    }

    /**
     *
     * @param integer $seconds          
     * @param string $datetimeField
     *          default='StartTime'
     * @return Event
     */
    public function recently($seconds, $datetimeField = 'StartTime') {
        if (isEmpty($datetimeField) || !$this->hasAttribute($datetimeField))
            $datetimeField = 'StartTime';

        $interval = new DateInterval("PT{$seconds}S");
        $past = new DateTime ();
        $past->sub($interval);

        $this->getDbCriteria()
                ->mergeWith(array(
                    'condition' => "$datetimeField >= :pasteDateTime",
                    'params' => array(
                        ':pasteDateTime' => DateHelper::formatISO9075DateTime($past)
                    )
                ));
        return $this;
    }

    public function byGate($gate) {
        $this->getDbCriteria()
                ->mergeWith(array(
                    'condition' => 'Gate = :gate_id',
                    'params' => array(
                        ':gate_id' => $gate->Gate
                    )
                ));
        return $this;
    }

    public function byStatus($status) {
        $this->getDbCriteria()
                ->mergeWith(array(
                    'condition' => 'Gate = :gate_id',
                    'params' => array(
                        ':gate_id' => $gate->Gate
                    )
                ));
        return $this;
    }

    public function byPlate($plate) {
        $this->getDbCriteria()
                ->mergeWith(array(
                    'condition' => "MATCH(Plate) AGAINST('*" . $plate . "*' IN BOOLEAN MODE)"
                        )
        );
        return $this;
    }

    public function withNationalityChanged() {
        $this->getDbCriteria()->addCondition("custom_nationality != '' and custom_nationality is not null and iso_code != custom_nationality");

        return $this;
    }

    public function byGates($gates) {
        $alias = $this->getTableAlias(false, false);

        if (!is_array($gates))
            $gates = array($gates);

        $this->getDbCriteria()->addInCondition($alias . '.Gate', $gates);

        return $this;
    }

    public function byGatesId($gatesId) {

        if (!is_array($gatesId))
            $gatesId = array($gatesId);

        $gates = Gate::model()->findAllByPk($gatesId);

        $gateNumbers = array();
        foreach ($gates as $gate) {
            $gateNumbers[] = $gate->Gate;
        }

        $this->byGates($gateNumbers);

        return $this;
    }

    public function byVehicleClass($vehiclesClass) {
        if (!is_array($vehiclesClass))
            $vehiclesClass = array($vehiclesClass);



        $tags = array();


        $cNats = new CDbCriteria;

        foreach ($vehiclesClass as $class) {
            $cNat = new CDbCriteria;
            $cNat->addCondition("t.custom_vehicle_type = '" . $class . "'");

            $cNat2 = new CDbCriteria;
            $cNat2->addCondition("t.custom_vehicle_type = '' or t.custom_vehicle_type is null");

            $cNat2->addCondition("t.Classe = '" . $class . "'");


            $cNat->addCondition($cNat2->condition, 'OR');
            $cNat->params += $cNat2->params;

            $cNats->addCondition($cNat->condition, 'OR');
            $cNats->params += $cNat->params;
        }


        $this->getDbCriteria()->addCondition($cNats->condition);
        $this->getDbCriteria()->params += $cNats->params;



        return $this;
    }

    function byDateTimeBoundaries($startTimestamp, $startTime, $endTimestamp, $endTime) {
        if (isset($startTimestamp)) {
            $startDateTime = new DateTime();
            $startDateTime->setTimestamp($startTimestamp);


            if (isset($startTime)) {
                $startTime = $theStartTime = DateTime::createFromFormat(Yii::app()->params['timeselect_format'][Yii::app()->language]['php'], $startTime);


                $startDateTime->setTime(intval($startTime->format('H')), intval($startTime->format('i')));
            }

            $startDT = DateHelper::formatISO9075DateTime($startDateTime);
            //echo "<$startDT>";

            $this->getDbCriteria()->addCondition("t.StartTime >= '$startDT'");
        }

        if (isset($endTimestamp)) {
            $endDateTime = new DateTime();
            $endDateTime->setTimestamp($endTimestamp);
            //echo DateHelper::formatISO9075DateTime ( $endDateTime );;

            if (isset($endTime)) {
                $endTime = $theStartTime = DateTime::createFromFormat(Yii::app()->params['timeselect_format'][Yii::app()->language]['php'], $endTime);
                $endDateTime->setTime(intval($endTime->format('H')), intval($endTime->format('i')));
            }
        }

        $endDT = DateHelper::formatISO9075DateTime($endDateTime);
        //echo "<$endDT>";
        $this->getDbCriteria()->addCondition("t.StartTime <= '$endDT'");


        return $this;
    }

    public function startDateAfter($dateTime) {
        $this->getDbCriteria()
                ->mergeWith(array(
                    'condition' => 'StartTime >= :startDateTime',
                    'params' => array(
                        ':startDateTime' => DateHelper::formatISO9075DateTime($dateTime)
                    )
                        )
        );
        return $this;
    }

    public function startDateBefore($dateTime) {
        $this->getDbCriteria()
                ->mergeWith(array(
                    'condition' => 'StartTime <= :endDateTime',
                    'params' => array(
                        ':endDateTime' => DateHelper::formatISO9075DateTime($dateTime)
                    )
                        )
        );
        return $this;
    }

    public function startTimeAfter($time) {
        $this->getDbCriteria()
                ->mergeWith(array(
                    'condition' => 'TIME(StartTime) >= :startTimeSlot',
                    'params' => array(
                        ':startTimeSlot' => DateHelper::formatISO9075Time($time)
                    )
                        )
        );
        return $this;
    }

    public function startTimeBefore($time) {
        $this->getDbCriteria()
                ->mergeWith(array(
                    'condition' => 'TIME(StartTime) <= :endTimeSlot',
                    'params' => array(
                        ':endTimeSlot' => DateHelper::formatISO9075Time($time)
                    )
                        )
        );
        return $this;
    }

    public function byNationalities($nationalities) {
        if (!is_array($nationalities))
            $nationalities = array($nationalities);

        $tags = array();


        $cNats = new CDbCriteria;

        foreach ($nationalities as $nat) {
            $cNat = new CDbCriteria;
            $cNat->addCondition("t.custom_nationality = '" . strtoupper($nat) . "'");

            $cNat2 = new CDbCriteria;
            $cNat2->addCondition("t.custom_nationality = '' or t.custom_nationality is null");

            $cNat2->addInCondition('t.Nationality', PlateCountry::getPossibleTag($nat));


            $cNat->addCondition($cNat2->condition, 'OR');
            $cNat->params += $cNat2->params;

            $cNats->addCondition($cNat->condition, 'OR');
            $cNats->params += $cNat->params;
        }


        $this->getDbCriteria()->addCondition($cNats->condition);
        $this->getDbCriteria()->params += $cNats->params;



        return $this;
    }

    public function defaultScope() {
        $alias = $this->getTableAlias(false, false);

        return array(
            'order' => "$alias.StartTime DESC"
        );
    }

    /**
     *
     * @param string $orderBy          
     * @return Event
     */
    public function setOrderBy($orderBy) {
        $this->getDbCriteria()
                ->mergeWith(array(
                    'order' => $orderBy
                ));
        return $this;
    }

    public function relations() {

        $t = $this->getTableAlias(false);

        return array(
            'gate' => array(
                self::BELONGS_TO,
                'Gate',
                array(
                    'Gate' => 'Gate'
                )
            ),
            'gateGroup' => array(
                self::HAS_ONE,
                'GateGroup',
                array(
                    'id_group' => 'ID'
                ),
                'through' => 'gate'
            ),
            'service' => array(
                self::BELONGS_TO,
                'Service',
                'id_run'
            ),
            'eventBehaviors' => array(
                self::HAS_MANY,
                'EventBehavior',
                'id_event'
            ),
            'eventBehaviorsToValidate' => array(
                self::HAS_MANY,
                'EventBehavior',
                'id_event',
                'scopes' => array(
                    'toValidate'
                )
            ),
            'behaviors' => array(
                self::HAS_MANY,
                'Behavior',
                array(
                    'id_behavior' => 'ID'
                ),
                'through' => 'eventBehaviors'
            ),
            'photos' => array(
                self::HAS_MANY,
                'MediaAttachment',
                array(
                    'EventID' => 'ExtraInfoID'
                ),
                'scopes' => array(
                    'photo'
                )
            ),
            'photosAll' => array(
                self::HAS_MANY,
                'MediaAttachment',
                array('EventID' => 'ExtraInfoID'),
                'scopes' => array('resetScope')
            ),
            'video_bw' => array(
                self::HAS_ONE,
                'MediaAttachment',
                array(
                    'EventID' => 'ExtraInfoID'
                ),
                'scopes' => array(
                    'video_bw'
                )
            ),
            'video_col' => array(
                self::HAS_ONE,
                'MediaAttachment',
                array(
                    'EventID' => 'ExtraInfoID'
                ),
                'scopes' => array(
                    'video_col'
                )
            ),
            'videos' => array(
                self::HAS_MANY,
                'MediaAttachment',
                array(
                    'EventID' => 'ExtraInfoID'
                ),
                'scopes' => array(
                    'video'
                )
            ),
            'colorSet' => array(
                self::BELONGS_TO,
                'VehicleColor',
                'id_vehicle_color'
            ),
            'newEventBehaviors' => array(
                self::HAS_MANY,
                'EventBehavior',
                'id_event',
                'condition' => 'validation_result = "" or validation_result IS NULL'
            ),
            'approvedEventBehaviors' => array(
                self::HAS_MANY,
                'EventBehavior',
                'id_event',
                'condition' => "validation_result = :result",
                'params' => array(
                    ':result' => EventBehavior::STATUS_APPROVED
                )
            ),
            'pendingEventBehaviors' => array(
                self::HAS_MANY,
                'EventBehavior',
                'id_event',
                'condition' => 'validation_result = :result',
                'params' => array(
                    ':result' => EventBehavior::STATUS_PENDING
                )
            ),
            'voidEventBehaviors' => array(
                self::HAS_MANY,
                'EventBehavior',
                'id_event',
                'condition' => 'validation_result = :result',
                'params' => array(
                    ':result' => EventBehavior::STATUS_VOID
                )
            ),
            'invalidEventBehaviors' => array(
                self::HAS_MANY,
                'EventBehavior',
                'id_event',
                'condition' => 'validation_result = :result',
                'params' => array(
                    ':result' => EventBehavior::STATUS_INVALID
                )
            ),
            'toBeManagedEventBehaviors' => array(
                self::HAS_MANY,
                'EventBehavior',
                'id_event',
                'condition' => 'validation_result != :result',
                'params' => array(
                    ':result' => EventBehavior::STATUS_NO_VALIDATION
                )
            ),
            'alert' => array(
                self::BELONGS_TO,
                'Alert',
                array(
                    'UUID' => 'event_uuid'
                )
            ),
            'bookmark' => array(
                self::HAS_ONE,
                'Bookmark',
                'id_reference',
                'condition' => "bookmark.type='event' AND id_user=" . user()->id
            ),
            'recognized_nation' => array(
                self::HAS_ONE,
                'PlateCountry',
                array('label' => 'Nationality')
            ),
            'vehicle' => array(
                self::HAS_ONE,
                'Vehicle',
                array('source' => 'UUID')
            )
        );
    }

    public function behaviors() {
        return array(
            'edatetimebehavior' => array(
                'class' => 'ext.EDateTimeBehavior'
            )
        );
    }

    public function search(array $params = null) {
        $criteria = new CDbCriteria ();
        // $criteria->compare('Plate', $params['query'], true);

        if (Yii::app()->user->checkAccess('license_plate_visibility'))
            $criteria->addCondition("MATCH(Plate) AGAINST('*" . $params ['query'] . "*' IN BOOLEAN MODE)");
        $criteria->compare('ext_code', $params ['query'], true, 'OR');

        if (in_array('ext_code_only', $params))
            $criteria->addCondition("ext_code<>''");

        $criteria->addBetweenCondition('StartTime', $params ['start']->format("Y-m-d H:i:s"), $params ['end']->format("Y-m-d H:i:s"));
        if (count($params ['gates']) > 0)
            $criteria->addInCondition('Gate', $params ['gates']);
        $count = $this->count($criteria);

        $pagination = new CPagination($count);
        $pagination->pageSize = 10;
        $pagination->applyLimit($criteria);

        $dataProvider = new CActiveDataProvider('Event');
        $dataProvider->criteria = $criteria;
        $dataProvider->pagination = $pagination;

        return $dataProvider;
    }

    public function isNew() {
        return (isset($this->ValidatedBy) && ($this->ValidatedBy == '') && !$this->isExamined());
    }

    public function isExamined() {
        return (isset($this->data_check) && $this->data_check == 1);
    }

    public function isValidated() {
        return ($this->isApproved() || $this->isInvalid() || $this->isPending());
    }

    public function hasCorrectedPlate() {
        return (!empty($this->ExtPlate) && $this->Plate != $this->ExtPlate);
    }

    /**
     * say if Plate has []?
     *
     * @return boolean
     */
    public function hasWildcardPlate() {
        return containsStr($this->Plate, "[") || containsStr($this->Plate, "]") || containsStr($this->Plate, "?");
    }

    /**
     * say if ExtPlate has []?
     *
     * @return boolean
     */
    public function hasWildcardExtPlate() {
        return containsStr($this->ExtPlate, "[") || containsStr($this->ExtPlate, "]") || containsStr($this->ExtPlate, "?");
    }

    /**
     *
     * @return CArray with fields exists,levenshtein,btlfsa,similar_text
     */
    public function getPlateCorrectionError() {
        $error = plate_error_calc($this->Plate, $this->ExtPlate);
        return $error;
    }

    public function isApproved() {
        return ($this->validation_result == self::VALIDATION_RESULT_APPROVED);
    }

    public function isVoid() {
        return ($this->validation_result == self::VALIDATION_RESULT_VOID);
    }

    public function getIsRed() {
        foreach ($this->behaviors as $beh)
            if ($beh->isRed)
                return true;
        return false;
    }

    public function isInvalid() {
        return ($this->validation_result == self::VALIDATION_RESULT_INVALID);
    }

    public function isPending() {
        return ($this->validation_result == self::VALIDATION_RESULT_PENDING);
    }

    public function isQueuedForExport() {
        return (isset($this->ext_code) && $this->ext_code != '');
    }

    public function isExported() {
        return (isset($this->Protocol) && $this->Protocol != '' && $this->Protocol != 'NO_MULTA' && $this->Protocol != '-');
    }

    public function updateStatus() {
        if (count($this->newEventBehaviors) > 0)
            $result = '';

        else if (count($this->pendingEventBehaviors) > 0)
            $result = self::VALIDATION_RESULT_PENDING;

        else if (count($this->approvedEventBehaviors) > 0)
            $result = self::VALIDATION_RESULT_APPROVED;

        else if (count($this->invalidEventBehaviors) == count($this->toBeManagedEventBehaviors))
            $result = self::VALIDATION_RESULT_INVALID;

        $this->validation_result = $result;
        $this->Protocol = '';
        $this->ext_code = '';

        return $this->save();
    }

    /**
     *
     * @param AuthWebUser $webUser          
     * @return boolean
     */
    public function assignUser(AuthWebUser $webUser) {
        $now = new DateTime ();

        $this->assignValidator($webUser, $now);
        $this->assignExaminer($webUser, $now);
        return $this->save();
    }

    public function getKemler() {
        $Kem = $this->getAttribute('Kemler');
        if (strlen($Kem) <= 0)
            return '';

        $pos = strrpos($Kem, ";");
        if ($pos === false) {
            $pos = strrpos($Kem, "-");
            if ($pos === false) {
                $offset = strlen($Kem) - 4;
                $part1 = substr($Kem, 0, $offset);
                $part2 = substr($Kem, $offset);

                $part1 = $part1 . "-";
                $whole = $part1 . $part2;

                return $whole;
            }
        }

        return str_replace(';', '-', $Kem);
    }

    public function getCustom_nationality() {
        $custom_nationality = $this->getAttribute('custom_nationality');
        if (isset($custom_nationality) && $custom_nationality != '')
            return $custom_nationality;
        else {
            $kriaPlate = PlateCountry::model()->findByAttributes(array(
                'label' => $this->Nationality
                    ));
            if (isset($kriaPlate))
                return $kriaPlate->iso_code;
        }
    }

    public function getNationalityCode() {
        return $this->custom_nationality;
    }

    public function getCustom_plate_type() {
        $custom_plate_type = $this->getAttribute('custom_plate_type');
        if (isset($custom_plate_type) && $custom_plate_type != '')
            return $custom_plate_type;
        else {
            $plateType = CustomPlateType::model()->findByAttributes(array(
                'is_default' => 1
                    ));
            if (isset($plateType))
                return $plateType->type;
        }
    }

    public function getCustom_property_type() {
        $custom_property_type = $this->getAttribute('custom_property_type');
        if (isset($custom_property_type) && $custom_property_type != '')
            return $custom_property_type;
        else {
            $propertyType = CustomPropertyType::model()->findByAttributes(array(
                'is_default' => 1
                    ));
            if (isset($propertyType))
                return $propertyType->type;
        }
    }

    public function getCustom_vehicle_type() {
        $custom_vehicle_type = $this->getAttribute('custom_vehicle_type');
        $kria_vehicle_type = $this->getAttribute('Classe');
        if (isset($custom_vehicle_type) && $custom_vehicle_type != '')
            return $custom_vehicle_type;
        else
            return VehicleTypes::getFromDeviceClass($kria_vehicle_type);
        // return $kria_vehicle_type;
    }

    public function getVehicleClass() {
        return $this->custom_vehicle_type;
    }

    public function getEventDateTime() {
        return $this->StartTime;
    }

    public function setPlate($newPlate) {
        $newPlate = strtoupper($newPlate);

        if ($this->ExtPlate == '' && $newPlate != $this->getAttribute('Plate'))
            $this->ExtPlate = $this->getAttribute('Plate');
        $this->setAttribute('Plate', $newPlate);
    }

    public function tagged() {
        return isset($this->ext_code) && strlen($this->ext_code) > 0;
    }

    public function tag($code, $datetime) {
        $this->ext_code = $code;
        $this->ext_code_time = $datetime; 
        return $this->save();
    }

    public function last($numOfItems) {

        $this->getDbCriteria()->limit = $numOfItems;
        $this->getDbCriteria()->order = 'StartTime DESC';

        return $this;
    }

    public function first($numOfItems) {

        $this->getDbCriteria()->limit = $numOfItems;
        $this->getDbCriteria()->order = 'StartTime ASC';


        return $this;
    }

    public function getViolationCodes() {
        return array_map(function ($eb) {
            return $eb->violation_code;
        }, $this->eventBehaviors);
    }

    public function suspend() {
        foreach ($this->eventBehaviors as $eventBehavior)
            $eventBehavior->suspend();

        $this->validation_result = self::VALIDATION_RESULT_PENDING;
        return $this->save();
    }

    /**
     *
     * @param AuthWebUser $user          
     * @return boolean
     */
    public function approve(AuthWebUser $user) {
        foreach ($this->eventBehaviors as $eventBehavior)
            $eventBehavior->approve();

        $this->assignUser($user);

        $this->ValidatedBy = $user->name;
        $this->validation_result = self::VALIDATION_RESULT_APPROVED;

        if (empty($this->custom_nationality))
            $this->custom_nationality = "IT";

        if (!$this->save()) {
            return false;
        }

        return true;
    }

    public function howMany() {
        return Event::model()->count($this->getDbCriteria());
    }

    /**
     *
     * @return MediaAttachment
     */
    public function getPreviewPhoto() {
        if (!Yii::app()->user->checkAccess('media_view_photo'))
            return null;
        $media = MediaAttachment::model();
        if ($this->Direction == - 1)
            $media->setSignificantPhotoBlobIdBw(1001);

        if ($this->getGateType() == Gate::GT_T_RED)
            $media->setSignificantPhotoColumn('BlobIDSelected');



        $media->byEventIds($this->ExtraInfoID);
        $media->photo();
        $media->preview();
        return $media->find();
    }

    /**
     *
     * @return string
     */
    public function getPreviewPhotoUrl() {
        if (!Yii::app()->user->checkAccess('media_view_photo'))
            return access_denied_png_url();
        $photo = $this->getPreviewPhoto();
        if (isset($photo))
            return $photo->url;
        return null;
    }

    /**
     *
     * @return MediaAttachment
     */
    public function getPreviewColorPhoto() {
        if (!Yii::app()->user->checkAccess('media_view_photo'))
            return null;
        $media = MediaAttachment::model();
        if ($this->Direction == - 1)
            $media->setSignificantPhotoBlobIdCol(3001);
        if ($this->getGateType() == Gate::GT_T_RED)
            $media->setSignificantPhotoColumn('BlobIDSelected');
        $media->byEventIds($this->ExtraInfoID);
        $media->previewColor();
        return $media->find();
    }

    /**
     *
     * @return string
     */
    public function getPreviewColorPhotoUrl() {
        if (!Yii::app()->user->checkAccess('media_view_photo'))
            return access_denied_png_url();
        $photo = $this->getPreviewColorPhoto();
        if (isset($photo))
            return $photo->url;
        return null;
    }

    public function getPreviewExtraCameraPhoto() {
        if (!Yii::app()->user->checkAccess('media_view_photo'))
            return null;

        $media = MediaAttachment::model();

        $media->byEventIds($this->ExtraInfoID);
        $media->extraCameraPhotos();
        return $media->findAll();
    }

    /**
     *
     * @param AuthWebUser $webUser          
     * @param DateTime $time          
     */
    private function assignValidator(AuthWebUser $webUser, DateTime $time) {
        if ($webUser->checkAccess('edit_event_behaviors')) {
            $this->id_validate_user = $webUser->id;
            $this->ValidationTime = $time->format(DateHelper::ISO9075_DATETIME);
        }
    }

    /**
     *
     * @param AuthWebUser $webUser          
     * @param DateTime $time          
     */
    private function assignExaminer(AuthWebUser $webUser, DateTime $time) {
        if ($this->id_data_check_user == null || $this->id_data_check_user == 0) {
            $this->id_data_check_user = $webUser->id;
            $this->data_check_time = $time->format(DateHelper::ISO9075_DATETIME);
            $this->ValidatedBy = $webUser->id;
            $this->data_check = 1;
        }
    }

    public function getGateType() {
        return $this->gate->GateType;
    }

    public function getGateLabel() {
        return $this->gate->Descrizione;
    }

    public function getGateShortLabel() {
        return $this->gate->short_name;
    }

    public function getVehicleSpeed() {

        if ($this->measured_speed > 0)
            return $this->measured_speed;

        if ($this->Speed > 0)
            return $this->Speed;

        return - 1;
    }

    public function getSpeedLimitSignList() {
        if (is_null($this->speed_limit_signs) or strlen($this->speed_limit_signs) <= 0)
            return null;

        $signs = explode(';', $this->speed_limit_signs);

        sort($signs, SORT_NUMERIC);

        return $signs;
    }

    public function getYellowBarType() {
        return null;
    }

    /**
     *
     * @param boolean $searchForCsv
     *          default=false
     * @return CActiveDataProvider
     */
    public function searchAll($searchForCsv = false) {
        // Warning: Please modify the following code to remove attributes that
        // should not be searched.
        $criteria = new CDbCriteria ();

        if (!empty($this->Plate))
            $criteria->addCondition("MATCH(t.Plate) AGAINST('*" . $this->Plate . "*' IN BOOLEAN MODE)");

        if (!empty($this->Classe)) {
            $conditionVClass = "t.custom_vehicle_type = '" . $this->Classe . "' OR (t.custom_vehicle_type is null AND t.Classe = '" . $this->Classe . "')";
            $criteria->addCondition($conditionVClass);
        }

        $criteria->compare('t.Gate', $this->Gate);

        // kemler
        $kemlerStr = $this->kemlerSearchString;
        if (!empty($kemlerStr))
            if ($kemlerStr == "*") {
                $criteria->addCondition("(t.Kemler is not null AND t.Kemler != '')");
            } else {
                $kemlerStr = str_replace("-", "", $kemlerStr);
                $criteria->addCondition("MATCH(t.Kemler) AGAINST('*" . $kemlerStr . "*' IN BOOLEAN MODE)");
            }

        if ($this->searchBookmarked) {
            $this->withBookmark($criteria);
        }

        $criteria->compare('t.LaneID', $this->LaneID);

        if (!empty($this->id_run))
            $criteria->addCondition("t.id_run={$this->id_run}");

        if (!empty($this->searchByResult))
            $criteria->addCondition("t.validation_result='{$this->searchByResult}'");

        if (!empty($this->ValidatedBy))
            $criteria->addCondition("t.ValidatedBy={$this->ValidatedBy}");

        if (!empty($this->Nationality))
            $criteria->addInCondition('t.Nationality', PlateCountry::getPossibleTag($this->Nationality));

        if (!empty($this->event_date_start)) {
            $theStartTime = DateTime::createFromFormat(Yii::app()->params ['datetimeselect_format'] [Yii::app()->language] ['php'], $this->event_date_start);
            $startDT = DateHelper::formatISO9075DateTime($theStartTime);

            $criteria->addCondition("t.StartTime >= '$startDT'");
        }

        if (!empty($this->event_date_end)) {
            $theEndTime = DateTime::createFromFormat(Yii::app()->params ['datetimeselect_format'] [Yii::app()->language] ['php'], $this->event_date_end);
            $endDT = DateHelper::formatISO9075DateTime($theEndTime);

            $criteria->addCondition("t.StartTime <= '$endDT'"); // date is database date column field
        }

        if (!empty($this->search_speed_start) && empty($this->search_speed_end)) {
            $criteria->addCondition("t.Speed >= '$this->search_speed_start'"); // date is database date column field
        } elseif (!empty($this->search_speed_end) && empty($this->search_speed_start)) {
            $criteria->addCondition("t.Speed <= '$this->search_speed_end'");
        } elseif (!empty($this->search_speed_end) && !empty($this->search_speed_start)) {
            $criteria->addCondition("t.Speed  >= '$this->search_speed_start' and t.Speed <= '$this->search_speed_end'");
        }

        if (!empty($this->searchColor) && is_string($this->searchColor) && startsWith($this->searchColor, '#')) {
            if ($criteria->with == null)
                $criteria->with = array();
            $criteria->with [] = 'colorSet';
            $rgb = ColorHelper::HTMLToRGBArray($this->searchColor);
            $sensitivity = paramdeep('search', 'advanced', 'colorSensitivity');
            $criteria->addCondition("
            kria_color_distance_perc(colorSet.c01,$rgb[r],$rgb[g],$rgb[b])>=$sensitivity
            OR
            kria_color_distance_perc(colorSet.c02,$rgb[r],$rgb[g],$rgb[b])>=$sensitivity
            OR
            kria_color_distance_perc(colorSet.c03,$rgb[r],$rgb[g],$rgb[b])>=$sensitivity
            ");
        }

        if ($searchForCsv) {
            access_denied_check('export_events');

            $criteria->join = "LEFT JOIN event_reporting e ON t.uuid=e.event_uuid";

            $criteria->select = array(
                Yii::app()->user->checkAccess('license_plate_visibility') ? 't.Plate as Plate' : "'#######' as Plate",
                't.StartTime as Date',
                't.Gate as Gate',
                't.Speed as Speed',
                't.LaneID+1 as LaneID',
                't.Classe as Class',
                't.Nationality as Nationality',
                't.Kemler as Kemler',
                'e.description as Description'
            );

            return new CActiveDataProvider($this, array(
                'criteria' => $criteria
                    ));
        }

        $dataProv = new CActiveDataProvider($this, array(
            'criteria' => $criteria,
            'pagination' => array(
                'pageSize' => paramdeep('search', 'advanced', 'pagination')
            )
                ));

        // $dataProv->setTotalItemCount(1000000000); //non va bene!

        return $dataProv;
    }

    static public function getNationCodesList() {
        $vTrace = Event::model()->resetScope()
                ->findAll(array(
            'select' => 'Nationality',
            'distinct' => true
                ));
        if (is_null($vTrace))
            return null;

        $arr = array();
        if (!is_array($vTrace))
            $vTrace = array(
                $vTrace
            );

        $labels = array();

        foreach ($vTrace as $vT)
            $labels [] = $vT->Nationality;

        return PlateCountry::getNationListFromLabels($labels);
    }

    /**
     *
     * @param mixed $services
     *          array of ids or id from table 'run'
     * @return CArray[]
     */
    public static function getServicesCounters($services) {
        if (is_array($services))
            $services = implode(',', $services);
        $counters = query("SELECT id_run AS id_run ,COUNT(*) AS count_total ,sum(case when (validation_result is null or validation_result <> 'no_validation') then 1 else 0 end) as eventsCount ,sum(case when (ValidatedBy = '' AND data_check = 0 AND (validation_result is null or validation_result <> 'no_validation')) then 1 else 0 end) as eventsNewCount ,sum(case when (data_check = 1) then 1 else 0 end) as eventsExaminedCount ,sum(case when (validation_result = 'pending') then 1 else 0 end) as eventsPendingCount ,sum(case when (validation_result <> '' and validation_result <> 'no_validation') then 1 else 0 end) as eventsValidatedCount ,sum(case when (ext_code IS NULL and ext_code != '') then 1 else 0 end) as eventsQueuedForExportCount ,sum(case when (Protocol != '' and Protocol != 'NO_MULTA') then 1 else 0 end) as eventsExportedCount FROM storicotable WHERE id_run IN ($services) GROUP BY id_run");
        $result = array();
        foreach ($counters as $cnt)
            $result [$cnt->id_run] = $cnt;
        return $result;
    }

    /**
     *
     * @return SimpleXMLElement
     */
    public function getXml() {
        $xml = $this->ExtraData;
        if (!empty($xml) && is_string($xml) && startsWith($xml, "<?xml")) {
            return new SimpleXMLElement($xml);
        }
        return null;
    }

    public function getOcrReliability() {
        $xml = $this->getXml();
        if ($xml != null)
            return (double) $xml->OCRLicensePlateReliability;
        else
            return - 1.0;
    }

    public function getWhitelistData() {
        $whitelistData = array();

        $xml = $this->getXml();
        if ($xml != null) {
            $whitelistData['ocr'] = (double) $xml->OCRLicensePlateReliability;

            $idReference = (int) $xml->images_Ids->WhiteListViolation->ReferenceLineID;
        }

        $whitelistData['reference_bw'] = null;
        $whitelistData['reference_col'] = null;

        foreach ($this->photos as $photo) {
            $id = (int) $photo->BlobID;

            // black/white
            if ($id == $idReference + 1000) {
                $whitelistData['reference_bw'] = $photo;
            }

            // color
            if ($id == $idReference + 3000) {
                $whitelistData['reference_col'] = $photo;
            }
        }

        return $whitelistData;
    }

    public function getRedData() {
        $redData = array();

        $xml = $this->getXml();
        if ($xml != null) {
            /*
             * T-RedSpeedReport\OCRLicensePlateReliability double
             *
             * T-RedSpeedReport\TrafficLightInfo\YellowTime 15:51:42:0378 - 19/10/2014
             * T-RedSpeedReport\TrafficLightInfo\YellowTimeINT64 long
             * T-RedSpeedReport\TrafficLightInfo\RedTime
             * T-RedSpeedReport\TrafficLightInfo\RedTimeINT64
             * T-RedSpeedReport\TrafficLightInfo\stopped_before_intersection 0=comma3 1=comma2
             *
             * T-RedSpeedReport\images_Ids\RedViolation\BeforeStopLineID
             * T-RedSpeedReport\images_Ids\RedViolation\OverStopLineID
             * T-RedSpeedReport\images_Ids\RedViolation\AfterIntersectionID
             * T-RedSpeedReport\images_Ids\RedViolation\AfterAfterIntersectionID
             */

            $redData ['ocr'] = (double) $xml->OCRLicensePlateReliability;
            $redData ['yellow'] = DateHelper::parseEx((string) $xml->TrafficLightInfo->YellowTime, DateHelper::KRIA_DATETIME);
            $redData ['red'] = DateHelper::parseEx((string) $xml->TrafficLightInfo->RedTime, DateHelper::KRIA_DATETIME);
            $redData ['stopped'] = (bool) ($xml->TrafficLightInfo->stopped_before_intersection == '1');
            $redData ['yellow_int64'] = $xml->TrafficLightInfo->YellowTimeINT64;
            $redData ['red_int64'] = $xml->TrafficLightInfo->RedTimeINT64;

            $redData ['yellow_timegap'] = (floatval($redData ['red_int64']) - floatval($redData ['yellow_int64'])) / 10000000.0;

            $idBefore = (int) $xml->images_Ids->RedViolation->BeforeStopLineID;
            $idOver = (int) $xml->images_Ids->RedViolation->OverStopLineID;
            $idAfter = (int) $xml->images_Ids->RedViolation->AfterIntersectionID;
            $idAfterAfter = (int) $xml->images_Ids->RedViolation->AfterAfterIntersectionID;
        }

        $redData ['before_bw'] = null;
        $redData ['over_bw'] = null;
        $redData ['after_bw'] = null;
        $redData ['afterafter_bw'] = null;

        $redData ['before_col'] = null;
        $redData ['over_col'] = null;
        $redData ['after_col'] = null;
        $redData ['afterafter_col'] = null;

        foreach ($this->photos as $photo) {
            $id = (int) $photo->BlobID;

            // black/white
            if ($id == $idBefore + 1000) {
                $redData ['before_bw'] = $photo;
            }
            if ($id == $idOver + 1000) {
                $redData ['over_bw'] = $photo;
            }
            if ($id == $idAfter + 1000) {
                $redData ['after_bw'] = $photo;
            }
            if ($id == $idAfterAfter + 1000) {
                $redData ['afterafter_bw'] = $photo;
            }

            // color
            if ($id == $idBefore + 3000) {
                $redData ['before_col'] = $photo;
            }
            if ($id == $idOver + 3000) {
                $redData ['over_col'] = $photo;
            }
            if ($id == $idAfter + 3000) {
                $redData ['after_col'] = $photo;
            }
            if ($id == $idAfterAfter + 3000) {
                $redData ['afterafter_col'] = $photo;
            }
        }

        return $redData;
    }

    /**
     *
     * @return MediaAttachment[]
     */
    public function getSpotSpeedData() {
        return $this->getPhotoBy("BlobID", array(
                    'bw1' => '1000',
                    'bw2' => '1001',
                    'col1' => '3000',
                    'col2' => '3001'
                ));
    }

    /**
     *
     * @return MediaAttachment[]
     */
    public function getMeanSpeedData() {
        return $this->getPhotoBy("Description", array(
                    'start_bw' => 'MeanSpeedStartRefImage',
                    'end_bw' => 'MeanSpeedEndRefImage'
                ));
    }

    /**
     *
     * @param string $field          
     * @param mixed $values          
     * @return MediaAttachment[]
     */
    public function getPhotoBy($field, $values) {
        if (!is_array($values))
            $values = array(
                $values
            );

        $photos = array();

        foreach ($this->photos as $photo) {
            foreach ($values as $key => $value) {
                if ($photo->$field == $value) {
                    $photos [$key] = $photo;
                }
            }
        }

        return $photos;
    }

    public function lastExported() {
        
    }

    public function getOcrQuality() {
        $ocrQuality = null;

        if ($this->ocr_quality >= 0) {
            $ocrQuality = $this->ocr_quality;
        }

        return $ocrQuality;
    }

    public function getOcrQualityClass() {
        $qualityLabel = "";

        $qualityRate = $this->ocrQuality;
        if (!$qualityRate) {
            return null;
        }

        if ($qualityRate <= paramdeep('ocr', 'quality_threshold_bad')) {
            $qualityLabel = self::OCR_QUALITY_LABEL_BAD;
        } elseif ($qualityRate > paramdeep('ocr', 'quality_threshold_bad') && $qualityRate < paramdeep('ocr', 'quality_threshold_good')) {
            $qualityLabel = self::OCR_QUALITY_LABEL_MID;
        } else {
            $qualityLabel = self::OCR_QUALITY_LABEL_GOOD;
        }

        return $qualityLabel;
    }

    public function resetValidation() {
        if ($this->isQueuedForExport())
            return false;

        if ($this->isExported())
            return false;

        $this->ValidatedBy = '';
        $this->validation_result = '';
        $this->id_validate_user = 0;
        return $this->save();
    }

}
