<?php
class StatsQuery
{

  /**
   * @param array $params
   * @return CActiveDataProvider
   */
  public function getStatsData(array $params)
  {
    $model = VehiclesFrequencyByType::model();
    $model->byVehicleClass($params['vehiclesClass']);
    $model->byGate($params['gates']);
    $model = $this->setDateTimeBoundaries($model, $params);
    
    if(isset($params['splitByGate']))
    {
    	$model->groupByGate();
    	$model->withGates(isset($params['useJoin']));
    }
    
    if(isset($params['splitByClass']))
    	$model->groupByVehicleClass();
    
    $model = $this->setDateTimeBoundaries($model, $params);
    
    $query = $model->getDbCriteria();

    $query = $this->setSpeedLimits($query, $params);
    $query = $this->setGranularity($query, $params);
    $query = $this->setSelectColumns($query, $params);
    $query = $this->setOrder($query, $params);

    
    $dataProvider = new CActiveDataProvider('VehiclesFrequencyByType',
      array('pagination'=>false)
    );

    $dataProvider->criteria = $query;
    return $dataProvider;
  }

  private function setOrder($query, $params)
  {
  	if(isset($params['splitByGate']))
  		$orderColumns[] = 't.Gate ASC';

		$orderColumns[] = 'StartDateTime ASC';
  	 
  	if(isset($params['splitByClass']))
  		$orderColumns[] = 'Classe ASC';
  	
  	$order = implode(",", $orderColumns);
  	
    $query->mergeWith(array('order' => $order));
    
    return $query;
  }

  private function setSelectColumns($query, $params)
  {
  	if(isset($params['splitByGate']))
  	{
  		$selectColumns[] = 't.Gate';
  		$selectColumns[] = 'Descrizione';
  	}
  	
		$selectColumns[] = "MIN(StartDateTime) as StartDateTime";
		$selectColumns[] =  "DATE_SUB(MAX(EndDateTime), INTERVAL 1 SECOND) as EndDateTime";
    
    if(isset($params['splitByClass']))
    	$selectColumns[] = 'Classe';
    
    
    if ($this->isSpeedRangeRequired($params))
      $selectColumns[] = "SUM(speeds.Counter)  as Counter";
    else
      $selectColumns[] = "SUM(Counter) as Counter";

    $query->mergeWith(array('select' => $selectColumns));

    return $query;
  }

  private function setDateTimeBoundaries(VehiclesFrequencyByType $model, $params)
  {
    if (isset($params['startTimestamp']))
    {
      $startDateTime = new DateTime();
      $startDateTime->setTimestamp($params['startTimestamp']);
      $model->startingFrom($startDateTime);
    }

    if (isset($params['endTimestamp']))
    {
      $endDateTime = new DateTime();
      $endDateTime->setTimestamp($params['endTimestamp']);
      $model->endingAt($endDateTime);
    }
    
    if (isset($params['startTime']))
    {
      $startTime = $theStartTime = DateTime::createFromFormat(Yii::app()->params['timeselect_format'][Yii::app()->language]['php'], $params['startTime']);
      $model->startingFromTime($startTime);
    }
    
    if (isset($params['endTime']))
    {
      $endTime = $theStartTime = DateTime::createFromFormat(Yii::app()->params['timeselect_format'][Yii::app()->language]['php'], $params['endTime']);
      $model->endingAtTime($endTime);
    }
    
    return $model;
  }

  private function setSpeedLimits($query, $params)
  {
    if ($this->isSpeedRangeRequired($params))
    {
      $speeds = VehiclesFrequencyBySpeed::model();

      if (isset($params['minSpeed']))
        $speeds->speedFrom($params['minSpeed']);

      if (isset($params['maxSpeed']))
        $speeds->speedTo($params['maxSpeed']);

      $crit = new CDbCriteria();
      
      if (isset($params['useJoin']))
      	$crit->join = 'LEFT JOIN StatsValuesTable as speeds ON StatID = t.id';
      else
      	$crit->with = 'speeds';
      
      $query->mergeWith($speeds->getDbCriteria());
      $query->mergeWith($crit);
    }

    return $query;
  }

  private function setGranularity($query, $params)
  {
    if (!isset($params['granularity']))
      throw new CHttpException(400, t('Granularity must be set.'));

    $dateTimeField = 'StartDateTime';

    $granularity = $params['granularity'];
    switch(true) {
    case ($granularity > 0 && $granularity < 3600):
      $query = SQLGroupByMinutes::group($query, $dateTimeField, $granularity / 60); 
      break;
    case ($granularity >= 3600 && $granularity < 86400):
      $query = SQLGroupByHours::group($query, $dateTimeField, $granularity / 3600);
      break;
    case ($granularity == 86400):
      $query = SQLGroupByDays::group($query, $dateTimeField);
      break;
    case ($granularity == 604800):
      $query = SQLGroupByWeeks::group($query, $dateTimeField);
      break;
    case ($granularity == 2592000):
      $query = SQLGroupByMonths::group($query, $dateTimeField);
      break;
    default:
      throw new CHttpException(400, t('Granularity {gran} is not available.', array('{gran}' => $granularity)));
    }

    return $query;
  }

  private function isSpeedRangeRequired($params)
  {
    return (
      (isset($params['minSpeed']) && $params['minSpeed']>0) ||
      (isset($params['maxSpeed']) && $params['maxSpeed']>0)
    );
  }

}
