<?php

class CronController extends Controller
{

    const MINUTE = 'minute';
    const HOUR = 'hour';
    const DAY = 'day';
    const MONTH = 'month';
    const DAYOFWEEK = 'dayOfWeek';

    public function actionRun()
    {
        $cronJobs = $this->getCronRule();
        $this->startCleanUp();
        $this->findDueLdapInterfaces();
        $this->runCallProtectionImportByJob();
        foreach ($cronJobs as $cronJobName => $cronRule) {
            if (CronValidator::cronCanStart($cronRule->getCronRule())) {
                $this->createCronJobStartLogMessage($cronJobName);
                $cronRule->run();
            }
        }
    }

    public function getCronRule()
    {
        $cronJobNames = CronJobFactory::getAllCronJobNames();
        $cronJobs = array();

        foreach ($cronJobNames as $cronJobName) {
            $cronJobs[$cronJobName] = CronJobFactory::getCronJobInstance($cronJobName);
        }
        return $cronJobs;
    }

    protected function startCleanUp()
    {
        $cleanUpJobs = Job::model()->findAllByAttributes(array('type' => Job::Cleanup));
        $cronJob = CronJobFactory::getCronJobInstance(CronJobFactory::CLEANUP);
        foreach ($cleanUpJobs as $cleanUpJob) {
            if ($cleanUpJob->status == Job::Finished) {
                $cleanUpJob->delete();
            } else if ($cleanUpJob->status == Job::Failed) {
                continue;
            } else {
                $cronJob->runCleanupByJob($cleanUpJob);
            }
        }
    }

    protected function findDueLdapInterfaces()
    {
        $totalItemCount = LdapInterface::model()->countAllByAttributes(array('cronJobEnabled' => 1));
        $offset = 0;
        while ($offset < $totalItemCount) {
            $ldapInterfaces = LdapInterface::model()->findAllByAttributes(array('cronJobEnabled' => 1), null, 100, $offset);
            foreach ($ldapInterfaces as $ldapInterface) {
                if (!$this->hasRunningJob($ldapInterface->id) && CronValidator::cronCanStart($ldapInterface->cronRule)) {
                    $this->createImportJob($ldapInterface->id);
                }
            }
            $offset += 100;
        }
    }

    private function hasRunningJob($ldapInterfaceId)
    {
        $ldapMeta = json_encode(array('LdapInterfaceId' => $ldapInterfaceId));
        $jobs = Job::model()->findAllByAttributes(array('type' => Job::LDAPImport, 'meta' => $ldapMeta));
        if (empty($jobs)) {
            Log::d("Creating Job for LDAP-Interface ID: $ldapInterfaceId", "CronController");
            return false;
        } else {
            Log::d("Job for LDAP-Interface ID: $ldapInterfaceId is already running.", "CronController");
            return true;
        }
    }

    private function createImportJob($id)
    {
        $job = new Job();
        $job->type = Job::LDAPImport;
        $job->progress = 1;
        $job->meta = json_encode(array('LdapInterfaceId' => $id));
        $job->status = Job::Inserted;
        if (!$job->save()) {
            $this->createJobErrorLogMessage($job);
        }
    }

    private function createJobErrorLogMessage($job)
    {
        Log::e("An error has occurred in Job:  ID $job->id", 'CronController');
        Log::e("User-ID: $job->user_id", 'CronController');
        Log::e('Status: ' . $job->status, 'CronController');
        Log::e('Error Text : ' . json_encode($job->errors), 'CronController');
    }

    private function createCronJobStartLogMessage($cronJobName)
    {
        if ($cronJobName !== CronJobFactory::LDAP_IMPORT) {
            Log::v('Start cron-job for "' . $cronJobName . '"!', 'CronController');
        }
    }

    private function runCallProtectionImportByJob()
    {
        if (!CallProtection::getAPIKey()) {
            return;
        }
        $cleanUpJobs = Job::model()->findAllByAttributes(array('type' => Job::CallProtectionImport));
        $cronJob = CronJobFactory::getCronJobInstance(CronJobFactory::CALLPROTECTION);
        foreach ($cleanUpJobs as $cleanUpJob) {
            if ($cleanUpJob->status == Job::Finished) {
                Log::v('CallProtection import cron-job done.', 'CronController');
                $cleanUpJob->delete();
            } else if ($cleanUpJob->status == Job::Failed) {
                continue;
            } else {
                $cronJob->run('CronController');
            }
        }
    }
}
