<?php

class iContactsConnector extends AbstractProviderConnector
{

    protected $limit = 5;

    public function confirmCredential($model)
    {
        $model->password = strrev(bin2hex($model->password));
        $model->token = $model->username;
        $model->addressBookURI = $model->serverURI;
        $model->authenticated = 1;
        $model->passwordStatus = ThirdPartyCredentialStatus::valid;

        if ($model->save()) {
            Log::v("Created new thirdPartyCredential model for iCloudSync.", "iContactsConnector");
            $this->saveICloudContactsList($model);
        } else {
            $this->createErrorLogMessages($model);
            throw new CHttpException(500, 'Can not save thirdPartyCredential. [iContactsConnector]');
        }
    }

    private function saveICloudContactsList($model)
    {
        if (!empty($model->syncCalendars)) {
            $this->createCalendarICloudList($model);
        }
        if (!empty($model->addressBookId)) {
            $this->createContactICloudList($model);
        } else {
            $this->redirect($this->createUrl('/phonesettingsThirdPartyCredentials/default/index'));
        }
    }

    private function createCalendarICloudList($model)
    {
        $calendars = json_decode($model->syncCalendars, true);
        foreach ($calendars as $calendar) {
            $contactsList = $this->createNewICloudContactsList($model, $calendar);
            $contactsList->uploadList = $this->checkForLocalDataToUpload($contactsList);
            if (!$contactsList->save()) {
                $this->createErrorLogMessages($contactsList);
            }
            Log::v("Created new iCloudContactsList model.", "iContactsConnector");
        }
    }

    private function createContactICloudList($model)
    {
        $contactsList = $this->createNewICloudContactsList($model);
        if ($contactsList->save()) {
            Log::v("Created new iCloudContactsList model.", "iContactsConnector");
            $this->redirect($this->createUrl('/phonesettingsThirdPartyCredentials/default/index'));
        } else {
            $this->createErrorLogMessages($contactsList);
            throw new CHttpException(500, 'Can not save iCloudContactsList. [iContactsConnector]');
        }
    }

    private function createNewICloudContactsList($thirdPartyCredential, $calendar = null)
    {
        $contactsList = new iCloudContactsList();
        $contactsList->owner = $thirdPartyCredential->owner;
        $contactsList->thirdPartyCredentialId = $thirdPartyCredential->id;

        if (empty($calendar)) {
            $contactsList->plDirectoryId = $thirdPartyCredential->addressBookId;
            $contactsList->iCloudDirectoryPath = $thirdPartyCredential->serverURI;
            $contactsList->iCloudType = iCloudTypes::contacts;
        } else {
            foreach ($calendar as $iCloudPath => $plDirectory) {
                $contactsList->plDirectoryId = $plDirectory;
                $contactsList->iCloudDirectoryPath = $iCloudPath;
                $contactsList->iCloudType = iCloudTypes::calendars;
            }
        }

        $contactsList->uploadList = $this->checkForLocalDataToUpload($contactsList);
        return $contactsList;
    }

    private function checkForLocalDataToUpload($contactsList)
    {
        $attributes = $this->getAttributes($contactsList);

        if ($attributes) {
            if ($contactsList->iCloudType == iCloudTypes::contacts) {
                $numberOfAddresses = Addresses::model()->countAllByAttributes($attributes);
            } elseif ($contactsList->iCloudType == iCloudTypes::calendars) {
                $numberOfAddresses = CalendarEvent::model()->countAllByAttributes($attributes);
            } else {
                Log::e("Invalid iCloudType", "[iContactsConnector]");
                Log::e("iCloudType: $contactsList->iCloudType", "[iContactsConnector]");
            }

            return $this->getAddressIds($attributes, $numberOfAddresses, $contactsList->iCloudType);
        }
    }

    private function getAttributes($contactsList)
    {
        if (is_object($contactsList)) {
            if ($contactsList->iCloudType == iCloudTypes::contacts) {
                return array(
                    'contact_tid' => $contactsList->plDirectoryId,
                    'contact_owner' => $contactsList->owner,
                );
            } elseif ($contactsList->iCloudType == iCloudTypes::calendars) {
                return array(
                    'calendar' => $contactsList->plDirectoryId,
                    'owner' => $contactsList->owner,
                );
            } else {
                Log::e("Invalid iCloudType", "[iContactsConnector]");
                Log::e("iCloudType: $contactsList->iCloudType", "[iContactsConnector]");
                return null;
            }
        } else {
            Log::e("Invalid ContactList", "[iContactsConnector]");
            return;
        }
    }

    private function getAddressIds($attributes, $limit, $iCloudType)
    {
        $uploadList = array();
        $offset = 0;
        while ($offset < $limit) {
            $files = array();

            if ($iCloudType == iCloudTypes::contacts) {
                $files = Addresses::model()->find($attributes, null, 100, $offset);
            } else {
                $files = CalendarEvent::model()->find($attributes, null, 100, $offset);
            }
            foreach ($files as $file) {
                $uploadList[] = $file->id;
            }
            $offset += 100;
        }
        Log::d('Created upload list.', 'iCloudSync [ContactListUpdater]');
        return empty($uploadList) ? null : json_encode($uploadList);
    }

    protected function gatherMetaDataForSyncJob($model)
    {
        $client = new iCloudClient($model->username, $model->password);
        $iCloudContactsLists = iCloudContactsList::model()->findAllByAttributes(array('thirdPartyCredentialId' => $model->id));

        foreach ($iCloudContactsLists as $iCloudContactsList) {
            $iCloudDirectory = $client->updateICloudDirectory($iCloudContactsList);

            if ($iCloudDirectory != ErrorCode::iCloudInvalidUserIdOrPassword) {
                $this->checkDirectoryForChanges($iCloudContactsList, $model, $iCloudDirectory);
            } else {
                $model->passwordStatus = ThirdPartyCredentialStatus::invalid;
                $model->save();
            }
        }
    }

    private function checkDirectoryForChanges($iCloudContactsList, $model, $iCloudDirectory)
    {
        $updater = new iCloudContactListUpdater($iCloudContactsList, $model->id);
        $updatedICloudContactsList = $updater->updateICloudContactsList($iCloudDirectory);

        if (isset($updatedICloudContactsList)) {
            $totalItemCount = $updatedICloudContactsList->findGreatestNumberOfListElements();
            $this->createSyncJob($model->id, $totalItemCount);
        }
    }

    protected function initiateProviderSpecificSync($meta, $model)
    {        
        $contactsLists = iCloudContactsList::model()->findAllByAttributes(array('thirdPartyCredentialId' => $model->id));

        $numItems = count($contactsLists);
        $i = 0;

        foreach ($contactsLists as $contactsList) {
            $iCloudSync = new iCloudSync($meta, $model);
            if (++$i !== $numItems) {
                $iCloudSync->synchronize($contactsList);
            } else {
                return $iCloudSync->synchronize($contactsList);
            }
        }
    }
}
