/**
  * Calculate the field value using the current values
  *
  * @param array $currentValue The current value
  * @param array $fieldData The other known field values
  * @param array $trackData The currently available track data (track id may be empty)
  * @return mixed the new value
  */
 public function calculateFieldValue($currentValue, array $fieldData, array $trackData)
 {
     if ($currentValue || isset($this->_fieldDefinition['gtf_filter_id'])) {
         $agenda = $this->loader->getAgenda();
         if ($this->_lastActiveKey && isset($this->_fieldDefinition['gtf_filter_id'])) {
             $fromDate = false;
             $lastActive = self::$_lastActiveAppointment[$this->_lastActiveKey];
             if ($lastActive instanceof \Gems_Agenda_Appointment && $lastActive->isActive()) {
                 $fromDate = $lastActive->getAdmissionTime();
             }
             if (!$fromDate && isset($trackData['gr2t_start_date']) && $trackData['gr2t_start_date']) {
                 if ($trackData['gr2t_start_date'] instanceof \Zend_Date) {
                     $fromDate = $trackData['gr2t_start_date'];
                 } else {
                     $fromDate = new \MUtil_Date($trackData['gr2t_start_date'], \Gems_Tracker::DB_DATETIME_FORMAT);
                 }
                 // Always use start of the day for start date comparisons
                 $fromDate->setTime('00:00:00');
             }
             if ($fromDate instanceof \MUtil_Date) {
                 $select = $agenda->createAppointmentSelect(array('gap_id_appointment'));
                 $select->onlyActive()->forFilterId($this->_fieldDefinition['gtf_filter_id'])->forRespondent($trackData['gr2t_id_user'], $trackData['gr2t_id_organization']);
                 $minDate = Period::applyPeriod($fromDate, $this->_fieldDefinition['gtf_min_diff_unit'], $this->_fieldDefinition['gtf_min_diff_length']);
                 if ($this->_fieldDefinition['gtf_max_diff_exists']) {
                     $maxDate = Period::applyPeriod($fromDate, $this->_fieldDefinition['gtf_max_diff_unit'], $this->_fieldDefinition['gtf_max_diff_length']);
                 } else {
                     $maxDate = null;
                 }
                 if ($this->_fieldDefinition['gtf_min_diff_length'] > 0) {
                     $select->forPeriod($minDate, $maxDate, true);
                 } else {
                     $select->forPeriod($maxDate, $minDate, false);
                 }
                 if ($this->_fieldDefinition['gtf_uniqueness']) {
                     switch ($this->_fieldDefinition['gtf_uniqueness']) {
                         case 1:
                             // Track instances may link only once to an appointment
                             $select->uniqueInTrackInstance(self::$_lastActiveAppointmentIds[$this->_lastActiveKey]);
                             break;
                         case 2:
                             // Tracks of this type may link only once to an appointment
                             if (isset($trackData['gr2t_id_respondent_track'])) {
                                 $respTrackId = $trackData['gr2t_id_respondent_track'];
                             } else {
                                 $respTrackId = null;
                             }
                             $select->uniqueForTrackId($this->_trackId, $respTrackId, self::$_lastActiveAppointmentIds[$this->_lastActiveKey]);
                             break;
                             // default:
                     }
                 }
                 // Query ready
                 $newValue = $select->fetchOne();
                 if ($newValue) {
                     $currentValue = $newValue;
                 }
             }
         }
         if ($this->_lastActiveKey && $currentValue) {
             $appointment = $agenda->getAppointment($currentValue);
             if ($appointment->isActive()) {
                 self::$_lastActiveAppointment[$this->_lastActiveKey] = $appointment;
                 self::$_lastActiveAppointmentIds[$this->_lastActiveKey][$currentValue] = $currentValue;
             }
         }
     }
     return $currentValue;
 }
 /**
  * Creates the base model.
  *
  * @return \MUtil_Model_SelectModel
  */
 protected function createModel()
 {
     $groupby['period_1'] = new \Zend_Db_Expr("YEAR({$this->dateFrom})");
     $date = new \MUtil_Date();
     switch ($this->dateType) {
         case 'D':
             $keyCount = 1;
             $groupby['period_1'] = new \Zend_Db_Expr("CONVERT({$this->dateFrom}, DATE)");
             $date->setTime(0);
             $date->addDay($this->dateFactor - $this->dateRange);
             $start = $date->getIso();
             for ($i = -$this->dateRange; $i <= $this->dateRange; $i++) {
                 if (0 == $i) {
                     $this->dateCurrentStart = clone $date;
                     $this->dateCurrentEnd = clone $date;
                     $this->dateCurrentEnd->setTimeToDayEnd();
                 }
                 $values = array();
                 $values['period_1'] = $date->get('yyyy-MM-dd');
                 $values['range'] = $i;
                 $requiredRows[$i] = $values;
                 $date->addDay(1);
             }
             $date->subSecond(1);
             $end = $date->getIso();
             break;
         case 'W':
             $keyCount = 2;
             // Use MONDAY as start of week
             $groupby['period_1'] = new \Zend_Db_Expr("substr(YEARWEEK(gto_valid_from, 3),1,4)");
             //$groupby['period_1'] = new \Zend_Db_Expr("YEAR($this->dateFrom) - CASE WHEN WEEK($this->dateFrom, 1) = 0 THEN 1 ELSE 0 END");
             $groupby['period_2'] = new \Zend_Db_Expr("WEEK({$this->dateFrom}, 3)");
             $date->setWeekday(1);
             $date->setTime(0);
             $date->addWeek($this->dateFactor - $this->dateRange);
             $start = $date->getIso();
             for ($i = -$this->dateRange; $i <= $this->dateRange; $i++) {
                 if (0 == $i) {
                     $this->dateCurrentStart = clone $date;
                     $this->dateCurrentEnd = clone $date;
                     $this->dateCurrentEnd->addWeek(1)->subSecond(1);
                 }
                 $values = array();
                 $values['period_1'] = $date->get(\Zend_Date::YEAR);
                 $values['period_2'] = $date->get(\Zend_Date::WEEK);
                 // When monday is in the previous year, add one to the year
                 if ($date->get(\Zend_Date::DAY_OF_YEAR) > 14 && $date->get(\Zend_Date::WEEK) == 1) {
                     $values['period_1'] = $values['period_1'] + 1;
                 }
                 $values['range'] = $i;
                 $requiredRows[$i] = $values;
                 $date->addWeek(1);
             }
             $date->subSecond(1);
             $end = $date->getIso();
             break;
         case 'M':
             $keyCount = 2;
             $groupby['period_2'] = new \Zend_Db_Expr("MONTH({$this->dateFrom})");
             $date->setDay(1);
             $date->setTime(0);
             $date->addMonth($this->dateFactor - $this->dateRange);
             $start = $date->getIso();
             for ($i = -$this->dateRange; $i <= $this->dateRange; $i++) {
                 if (0 == $i) {
                     $this->dateCurrentStart = clone $date;
                     $this->dateCurrentEnd = clone $date;
                     $this->dateCurrentEnd->addMonth(1)->subSecond(1);
                 }
                 $values = array();
                 $values['period_1'] = $date->get(\Zend_Date::YEAR);
                 $values['period_2'] = $date->get(\Zend_Date::MONTH);
                 $values['range'] = $i;
                 $requiredRows[$i] = $values;
                 $date->addMonth(1);
             }
             $date->subSecond(1);
             $end = $date->getIso();
             break;
         case 'Y':
             $keyCount = 1;
             $date->setDay(1);
             $date->setMonth(1);
             $date->setTime(0);
             $date->addYear($this->dateFactor - $this->dateRange);
             $start = $date->getIso();
             for ($i = -$this->dateRange; $i <= $this->dateRange; $i++) {
                 if (0 == $i) {
                     $this->dateCurrentStart = clone $date;
                     $this->dateCurrentEnd = clone $date;
                     $this->dateCurrentEnd->addYear(1)->subSecond(1);
                 }
                 $values = array();
                 $values['period_1'] = $date->get(\Zend_Date::YEAR);
                 $values['range'] = $i;
                 $requiredRows[$i] = $values;
                 $date->addYear(1);
             }
             $date->subSecond(1);
             $end = $date->getIso();
             break;
         default:
             throw new \Gems_Exception_Coding('Incorrect date_type value: ' . $this->dateType);
     }
     $where = "{$this->dateFrom} BETWEEN '{$start}' AND '{$end}'";
     for ($i = -$this->dateRange; $i <= $this->dateRange; $i++) {
         $requiredRows[$i]['date_factor'] = $this->dateFactor + $i;
         $requiredRows[$i]['df_link'] = null;
         $requiredRows[$i]['df_label'] = null;
     }
     if ($this->dateRange > 0) {
         $requiredRows[-$this->dateRange]['df_link'] = $this->dateFactor - $this->dateRange * 2;
         $requiredRows[-$this->dateRange]['df_label'] = $this->_('<<');
         $requiredRows[$this->dateRange]['df_link'] = $this->dateFactor + $this->dateRange * 2;
         $requiredRows[$this->dateRange]['df_label'] = $this->_('>>');
         if ($this->dateRange > 1) {
             $i = intval($this->dateRange / 2);
             $requiredRows[-$i]['df_link'] = $this->dateFactor - 1;
             $requiredRows[-$i]['df_label'] = $this->_('<');
             $requiredRows[$i]['df_link'] = $this->dateFactor + 1;
             $requiredRows[$i]['df_label'] = $this->_('>');
         }
         $requiredRows[0]['df_link'] = $this->dateFactor ? '0' : null;
         $requiredRows[0]['df_label'] = $this->_('Now!');
     }
     if ($this->dateFactor) {
         $today = new \MUtil_Date();
         $this->dateFactorChanges['D'] = $this->dateCurrentStart->diffDays($today);
         $this->dateFactorChanges['W'] = $this->dateCurrentStart->diffWeeks($today);
         $this->dateFactorChanges['M'] = $this->dateCurrentStart->diffMonths($today);
         $this->dateFactorChanges['Y'] = $this->dateCurrentStart->diffYears($today);
     } else {
         $this->dateFactorChanges = array_fill_keys(array('D', 'W', 'M', 'Y'), 0);
     }
     // \MUtil_Echo::track($requiredRows);
     // \MUtil_Echo::rs($start, $end, $where);
     $select = new \Zend_Db_Select($this->db);
     $select->from($this->dataTableName, $groupby + $this->getDbFields());
     $select->where($where);
     $select->group($groupby);
     $this->processSelect($select);
     // \MUtil_Echo::r((string) $select);
     $model = new \MUtil_Model_SelectModel($select, $this->dataTableName);
     // Display by column cannot use formatFunction as it is a simple repeater
     // $model->set('duration_avg', 'formatFunction', $this->util->getLocalized()->formatNumber);
     $transformer = new \MUtil_Model_Transform_RequiredRowsTransformer();
     $transformer->setDefaultRow($this->getDefaultRow());
     $transformer->setRequiredRows($requiredRows);
     $transformer->setKeyItemCount($keyCount);
     $model->addTransformer($transformer);
     return $model;
 }