/**
  * Checks for broken counters.
  * Expirity counter is broken if it is < 0, or if it is more than tasks count in list of expired tasks
  * Other counters is broken if it is < 0, or if it is != tasks count in list of respective tasks
  *
  * Method is called inside CTask::GetList() to perform recounting of broken counters.
  * 
  * @param $arFilter Filter was used in GetList() call
  * @param $tasksCountInList Number of records returned by GetList() call
  */
 public static function onTaskGetList($arFilter, $tasksCountInList)
 {
     if (!CTaskCountersProcessorInstaller::isInstallComplete()) {
         return;
     }
     // Is there our marker?
     if (!(array_key_exists('::MARKERS', $arFilter) && array_key_exists(self::MARKER_ID, $arFilter['::MARKERS']) && $tasksCountInList !== null)) {
         return;
     }
     $tasksCountInList = (int) $tasksCountInList;
     $counterOwnerUserId = $arFilter['::MARKERS'][self::MARKER_ID]['userId'];
     $counterId = $arFilter['::MARKERS'][self::MARKER_ID]['counterId'];
     $counterValue = (int) CUserCounter::GetValue($counterOwnerUserId, $counterId, $site_id = '**');
     if (in_array($counterId, array(CTaskCountersProcessor::COUNTER_TASKS_MY_EXPIRED, CTaskCountersProcessor::COUNTER_TASKS_ACCOMPLICE_EXPIRED, CTaskCountersProcessor::COUNTER_TASKS_AUDITOR_EXPIRED, CTaskCountersProcessor::COUNTER_TASKS_ORIGINATOR_EXPIRED, CTaskCountersProcessor::COUNTER_TASKS_MY_EXPIRED_CANDIDATES, CTaskCountersProcessor::COUNTER_TASKS_ACCOMPLICE_EXPIRED_CANDIDATES), true)) {
         $isExpirityCounter = true;
     } else {
         $isExpirityCounter = false;
     }
     $isCounterBrokeDetected = false;
     $realTasksCount = null;
     // Is checksum correct?
     $filterCheksum = $arFilter['::MARKERS'][self::MARKER_ID]['filterCheksum'];
     $realCheksum = self::calcFilterChecksum($arFilter);
     // break detection part
     if ($filterCheksum === $realCheksum) {
         $realTasksCount = $tasksCountInList;
         if ($counterValue < 0 || $tasksCountInList != $counterValue) {
             $isCounterBrokeDetected = true;
         }
     } else {
         if (isset($arFilter['SAME_GROUP_PARENT'], $arFilter['ONLY_ROOT_TASKS']) && $arFilter['SAME_GROUP_PARENT'] === 'Y' && $arFilter['ONLY_ROOT_TASKS'] === 'Y') {
             // unset the corresponding fields and try to compare checksums again
             unset($arFilter['SAME_GROUP_PARENT']);
             unset($arFilter['ONLY_ROOT_TASKS']);
             $realCheksum = self::calcFilterChecksum($arFilter);
             if ($filterCheksum === $realCheksum) {
                 // tasks count in list shouldn't be more than registered in counter
                 // and counter shouldn't be less than zero
                 if ($counterValue < 0 || $tasksCountInList > $counterValue) {
                     $isCounterBrokeDetected = true;
                 } else {
                     if (static::getCountersRecheckForSubTasksNeed()) {
                         $rsTasksCount = CTasks::getCount($arFilter, array('bIgnoreDbErrors' => true, 'bSkipUserFields' => true, 'bSkipExtraTables' => true));
                         if ($rsTasksCount && ($arTasksCount = $rsTasksCount->fetch()) && isset($arTasksCount['CNT'])) {
                             $realTasksCount = (int) $arTasksCount['CNT'];
                             if ($realTasksCount != $counterValue) {
                                 // and finally check
                                 $isCounterBrokeDetected = true;
                             }
                         }
                     }
                 }
             }
         }
     }
     /*
     if ( ! $isCounterBrokeDetected )
     {
     	if ($counterValue < 0)
     	{
     		$isCounterBrokeDetected = true;
     	}
     	else if ($realTasksCount !== null)
     	{
     		if ($isExpirityCounter)
     		{
     			if ($realTasksCount < $counterValue)
     				$isCounterBrokeDetected = true;
     		}
     		else
     		{
     			if ($realTasksCount !== $counterValue)
     				$isCounterBrokeDetected = true;
     		}
     	}
     }
     */
     if ($isCounterBrokeDetected) {
         ob_start();
         // a special way for correction of 'deadline expired' counters
         if ($isExpirityCounter) {
             // pend counters reinstalling (agent is used)
             self::pendCountersRecalculation();
         } else {
             if ($realTasksCount !== null) {
                 $delta = $realTasksCount - $counterValue;
                 CTaskCountersQueue::push($counterId, CTaskCountersQueue::OP_INCREMENT, array($counterOwnerUserId), $delta);
                 CTaskCountersQueue::execute();
             } else {
                 CTaskAssert::logError('[0x97e63b37] counter "' . $counterId . '" was mistimed for user ' . $counterOwnerUserId . '. But no correct data available for recount.');
             }
         }
         ob_end_clean();
     }
 }
 /**
  * Actualize expirity counters on time change, depends on current task status
  */
 private function actualizeExpirityCounters($deadline, $deadlineCounted, $status, $responsibleId, $originatorId, $arAuditors, $arAccomplices)
 {
     if ($this->isDeadlineExpiredSoon($deadline) && !$this->isCompletedStatus($status) && $deadlineCounted != self::DEADLINE_COUNTED_AS_EXPIRED_CANDIDATE) {
         // Counted as expired? Decrements this counters
         if ($deadlineCounted == self::DEADLINE_COUNTED_AS_EXPIRED) {
             CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_MY_EXPIRED, CTaskCountersQueue::OP_DECREMENT, array($responsibleId));
             if ($originatorId != $responsibleId) {
                 CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_ORIGINATOR_EXPIRED, CTaskCountersQueue::OP_DECREMENT, array($originatorId));
             }
             if (is_array($arAccomplices)) {
                 CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_ACCOMPLICE_EXPIRED, CTaskCountersQueue::OP_DECREMENT, $arAccomplices);
             }
             if (is_array($arAuditors)) {
                 CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_AUDITOR_EXPIRED, CTaskCountersQueue::OP_DECREMENT, $arAuditors);
             }
         }
         if ($this->isCompletedStatus($status)) {
             $deadlineCounted = self::DEADLINE_NOT_COUNTED;
         } else {
             // Count as expired soon
             CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_MY_EXPIRED_CANDIDATES, CTaskCountersQueue::OP_INCREMENT, array($responsibleId));
             // don't count expired soon tasks for originator
             // if ($originatorId != $responsibleId)
             // {
             // 	CTaskCountersQueue::push(
             // 		CTaskCountersProcessor::COUNTER_TASKS_ORIGINATOR_EXPIRED_CANDIDATES,
             // 		CTaskCountersQueue::OP_INCREMENT,
             // 		array($originatorId)
             // 	);
             // }
             if (is_array($arAccomplices)) {
                 CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_ACCOMPLICE_EXPIRED_CANDIDATES, CTaskCountersQueue::OP_INCREMENT, $arAccomplices);
             }
             // don't count expired soon tasks for auditors
             // if (is_array($arAuditors))
             // {
             // 	CTaskCountersQueue::push(
             // 		CTaskCountersProcessor::COUNTER_TASKS_AUDITOR_EXPIRED_CANDIDATES,
             // 		CTaskCountersQueue::OP_INCREMENT,
             // 		$arAuditors
             // 	);
             // }
             $deadlineCounted = self::DEADLINE_COUNTED_AS_EXPIRED_CANDIDATE;
         }
     } elseif ($this->isDeadlineExpired($deadline) && !$this->isCompletedStatus($status) && $deadlineCounted != self::DEADLINE_COUNTED_AS_EXPIRED) {
         // Counted as expired soon? Decrements this counters
         if ($deadlineCounted == self::DEADLINE_COUNTED_AS_EXPIRED_CANDIDATE) {
             CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_MY_EXPIRED_CANDIDATES, CTaskCountersQueue::OP_DECREMENT, array($responsibleId));
             // don't count expired soon tasks for originator
             // if ($originatorId != $responsibleId)
             // {
             // 	CTaskCountersQueue::push(
             // 		CTaskCountersProcessor::COUNTER_TASKS_ORIGINATOR_EXPIRED_CANDIDATES,
             // 		CTaskCountersQueue::OP_DECREMENT,
             // 		array($originatorId)
             // 	);
             // }
             if (is_array($arAccomplices)) {
                 CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_ACCOMPLICE_EXPIRED_CANDIDATES, CTaskCountersQueue::OP_DECREMENT, $arAccomplices);
             }
             // don't count expired soon tasks for auditors
             // if (is_array($arAuditors))
             // {
             // 	CTaskCountersQueue::push(
             // 		CTaskCountersProcessor::COUNTER_TASKS_AUDITOR_EXPIRED_CANDIDATES,
             // 		CTaskCountersQueue::OP_DECREMENT,
             // 		$arAuditors
             // 	);
             // }
         }
         if ($this->isCompletedStatus($status)) {
             $deadlineCounted = self::DEADLINE_NOT_COUNTED;
         } else {
             // Count as expired
             CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_MY_EXPIRED, CTaskCountersQueue::OP_INCREMENT, array($responsibleId));
             if ($originatorId != $responsibleId) {
                 CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_ORIGINATOR_EXPIRED, CTaskCountersQueue::OP_INCREMENT, array($originatorId));
             }
             if (is_array($arAccomplices)) {
                 CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_ACCOMPLICE_EXPIRED, CTaskCountersQueue::OP_INCREMENT, $arAccomplices);
             }
             if (is_array($arAuditors)) {
                 CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_AUDITOR_EXPIRED, CTaskCountersQueue::OP_INCREMENT, $arAuditors);
             }
             $deadlineCounted = self::DEADLINE_COUNTED_AS_EXPIRED;
         }
     } else {
         if (!$this->isCompletedStatus($status) && ($this->isDeadlineExpired($deadline) || $this->isDeadlineExpiredSoon($deadline))) {
             $expiredOrExpiredCandidate = true;
         } else {
             $expiredOrExpiredCandidate = false;
         }
         // Task become not expired and not to be expired soon, but it was counted
         if (!$expiredOrExpiredCandidate && $deadlineCounted != self::DEADLINE_NOT_COUNTED) {
             // Counted as expired? Decrements this counters
             if ($deadlineCounted == self::DEADLINE_COUNTED_AS_EXPIRED) {
                 CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_MY_EXPIRED, CTaskCountersQueue::OP_DECREMENT, array($responsibleId));
                 if ($originatorId != $responsibleId) {
                     CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_ORIGINATOR_EXPIRED, CTaskCountersQueue::OP_DECREMENT, array($originatorId));
                 }
                 if (is_array($arAccomplices)) {
                     CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_ACCOMPLICE_EXPIRED, CTaskCountersQueue::OP_DECREMENT, $arAccomplices);
                 }
                 if (is_array($arAuditors)) {
                     CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_AUDITOR_EXPIRED, CTaskCountersQueue::OP_DECREMENT, $arAuditors);
                 }
             } elseif ($deadlineCounted == self::DEADLINE_COUNTED_AS_EXPIRED_CANDIDATE) {
                 CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_MY_EXPIRED_CANDIDATES, CTaskCountersQueue::OP_DECREMENT, array($responsibleId));
                 // don't count expired soon tasks for originator
                 // if ($originatorId != $responsibleId)
                 // {
                 // 	CTaskCountersQueue::push(
                 // 		CTaskCountersProcessor::COUNTER_TASKS_ORIGINATOR_EXPIRED_CANDIDATES,
                 // 		CTaskCountersQueue::OP_DECREMENT,
                 // 		array($originatorId)
                 // 	);
                 // }
                 if (is_array($arAccomplices)) {
                     CTaskCountersQueue::push(CTaskCountersProcessor::COUNTER_TASKS_ACCOMPLICE_EXPIRED_CANDIDATES, CTaskCountersQueue::OP_DECREMENT, $arAccomplices);
                 }
                 // don't count expired soon tasks for auditors
                 // if (is_array($arAuditors))
                 // {
                 // 	CTaskCountersQueue::push(
                 // 		CTaskCountersProcessor::COUNTER_TASKS_AUDITOR_EXPIRED_CANDIDATES,
                 // 		CTaskCountersQueue::OP_DECREMENT,
                 // 		$arAccomplices
                 // 	);
                 // }
             }
             $deadlineCounted = self::DEADLINE_NOT_COUNTED;
         }
     }
     return $deadlineCounted;
 }