<?php

class AjaxController extends DefaultController
{

    public function accessRules()
    {
        return array(
            array('allow', // check for read Permissions
                'actions' => array(
                    "processAjaxAction",
                    "ajaxDelete",
                    "ajaxCopy",
                    "ajaxMove",
                    "ajaxCsv",
                ),
                'users' => array('@'),
            ),
            array('deny', // deny all users
                'users' => array('*'),
            ),
        );
    }

    public function actionProcessAjaxAction()
    {

        $sourceBookId = isset($_REQUEST["id"]) ? $_REQUEST["id"] : null;
        $affectedItems = isset($_REQUEST["selectedRows"]) ? $_REQUEST["selectedRows"] : null;
        $operation = isset($_REQUEST["function"]) ? $_REQUEST["function"] : $_REQUEST["JSONOperation"];
        $stopProcess = false;

        $offsetForDbRequests = 0;
        $limitForDbRequests = 100;
        $startTime = time();
        $actionAndTarget = explode("_", $operation);
        if (!isset($actionAndTarget[1])) {
            $actionAndTarget[] = $sourceBookId;
        }


        $action = $actionAndTarget[0];
        $targetBookId = $actionAndTarget[1];
        $ownerid = $this->getCurrentUser()->id;
        $sourceBookType = $this->getAddressbookType($sourceBookId);
        $targetBookType = $this->getAddressbookType($targetBookId);

        if (count($affectedItems) == 0) {

            $allAfactedItemsCount = $this->getAffactedItemsCount($sourceBookType, $sourceBookId, $ownerid);
        } else {
            $allAfactedItemsCount = count($affectedItems);
        }

        if ($action == "csvExport") {
            $downloadLink = $this->createUrl("default/downloadCsv");
        } else {
            $downloadLink = '#';
        }


        $ajaxData = array(
            'operation' => $action,
            'operationTargets' => $affectedItems,
            'sourceBookId' => $sourceBookId,
            'targetBookId' => $targetBookId,
            'requestUrl' => $this->getRequestUrlForAjaxAction($action),
            'startTime' => $startTime,
            'limit' => $limitForDbRequests,
            "offset" => $offsetForDbRequests,
            'count' => $allAfactedItemsCount,
            "stopProcess" => $stopProcess,
            "sourceBookType" => $sourceBookType,
            "targetBookType" => $targetBookType,
            "ownerId" => $ownerid,
            "downloadLink" => $downloadLink
        );
        echo json_encode($ajaxData);
    }

    private function getAffactedItemsCount($sourceBookType, $sourceBookId, $ownerid)
    {
        if ($sourceBookType == AddressbookType::group || $sourceBookType == AddressbookType::intern) {
            $attributes = array(
                'contact_tid' => $sourceBookId,
            );
        } elseif ($sourceBookType == AddressbookType::personal) {
            $attributes = array(
                'contact_tid' => $sourceBookId,
                'contact_owner' => $ownerid
            );
        }
        $allAfactedItemsCount = Addresses::model()->countAllByAttributes($attributes);
        return $allAfactedItemsCount;
    }

    private function getRequestUrlForAjaxAction($action)
    {
        if ($action == "delete") {
            return $this->createUrl("ajax/ajaxDelete");
        } else if ($action == "copy") {
            return $this->createUrl("ajax/ajaxCopy");
        } else if ($action == "move") {
            return $this->createUrl("ajax/ajaxMove");
        } else if ($action == "csvExport") {
            return $this->createUrl("ajax/ajaxCsv");
        }
    }

    private function getAddressbookType($bookId)
    {
        $user = $this->getCurrentUser();
        if (!$user) {
            app()->user->logout();
            app()->user->loginRequired();
        }
        $addressBookList = $user->getAddressbooks();
        if (isset($addressBookList[$bookId])) {
            $addressBook = $addressBookList[$bookId];
            return $addressBook->type;
        }
        return null;
    }

    public function actionAjaxDelete()
    {

        $ajaxData = $this->getAjaxDataFromPost();

        $addresses = $this->getAffectedItems($ajaxData);
        $addressBookID = null;
        foreach ($addresses as $model) {
            if (!isset($addressBookID)) {
                $addressBookID = $model->contact_tid;
            }
            $model->delete();
        }
        $this->initiateSyncForEachContactList($addressBookID);
        $ajaxData['offset'] = $this->calculateNewOffset($ajaxData);
        $this->setStopProgress($ajaxData);

        echo json_encode($ajaxData);
    }

    public function actionAjaxCopy()
    {

        $ajaxData = $this->getAjaxDataFromPost();

        if ($ajaxData["sourceBookId"] === $ajaxData["targetBookId"]) {
            if ($ajaxData["offset"] !== 0 && $ajaxData["offset"] !== "0") {
                $ajaxData["offset"] = ($ajaxData["offset"] + $ajaxData["limit"]);
            } else {
                $ajaxData["count"] = $ajaxData["count"] * 2;
            }
        }

        $addresses = $this->getAffectedItems($ajaxData, $ajaxData["offset"]);

        foreach ($addresses as $model) {

            $newAddress = $model->createCopy();
            $newAddress->contact_tid = $ajaxData["targetBookId"];
            $newAddress->contact_owner = $ajaxData["ownerId"];
            $newAddress->save();
            $this->copyVCardDataWithAddress($newAddress);
        }
        $this->initiateSyncForEachContactList($ajaxData["targetBookId"]);
        $ajaxData['offset'] = $this->calculateNewOffset($ajaxData);
        $this->setStopProgress($ajaxData);

        echo json_encode($ajaxData);
    }

    private function copyVCardDataWithAddress($address)
    {
        $vCardData = iCloudData::model()->findByAttributes(array('directoryId' => $address->id));
        if (!empty($vCardData)) {
            $vCardCopy = $vCardData->createCopy($address);
            $vCardCopy->setNewICloudContactListIDs($address->contact_tid);
        }
    }
    
    public function actionAjaxMove()
    {

        $ajaxData = $this->getAjaxDataFromPost();

        $addresses = $this->getAffectedItems($ajaxData);
        $oldAddressBook = null;
        foreach ($addresses as $model) {
            if(!isset($oldAddressBook)){
                $oldAddressBook = $model->contact_tid;
            }
            $model->contact_tid = $ajaxData["targetBookId"];
            $this->updateAssociatedVCrad($model);
            $model->save();
        }
        $this->initiateSyncForEachContactList($ajaxData["targetBookId"]);
        $this->initiateSyncForEachContactList($oldAddressBook);
        $ajaxData['offset'] = $this->calculateNewOffset($ajaxData);
        $this->setStopProgress($ajaxData);

        echo json_encode($ajaxData);
    }

    private function updateAssociatedVCrad($address)
    {
        $iCloudData = iCloudData::model()->findByAttributes(array('fileId' => $address->id));
        if (!empty($iCloudData)) {
            $iCloudData->removeVCardFromICloudContactsList();
            $iCloudData->setNewICloudContactListIDs($address->contact_tid);
        }
    }

    private function initiateSyncForEachContactList($addressBookID)
    {
        $iCloudContactsLists = iCloudContactsList::model()->findAllByAttributes(array('plDirectoryId' => $addressBookID));
        if (!empty($iCloudContactsLists)) {
            foreach ($iCloudContactsLists as $iCloudContactsList) {
                if (isset($iCloudContactsList)) {
                    $iCloudContactsList->startICloudSync();
                }
            }
        }
    }

    public function actionAjaxCsv()
    {

        $ajaxData = $this->getAjaxDataFromPost();
        $addresses = $this->getAffectedItems($ajaxData, $ajaxData["offset"]);

        $this->writeAddressCSVFile($addresses, $ajaxData);

        $ajaxData['offset'] = $this->calculateNewOffset($ajaxData);
        $this->setStopProgress($ajaxData);

        echo json_encode($ajaxData);
    }

    private function writeAddressCSVFile($addresses, $ajaxData)
    {
        $data = $this->getCsvData($addresses);
        $tempFile = $this->getTempFileName($ajaxData);

        if ($ajaxData["offset"] == 0) {
            $this->createCsvFile($tempFile);
            $this->appandCsvFile($tempFile, $data, $delimiter = ";");
        } else {
            $this->appandCsvFile($tempFile, $data, $delimiter = ";");
        }
    }

    private function getTempFileName($ajaxData)
    {
        $tmpPath = tempPath('csv');
        $filname = Yii::app()->user->sudoUser . "csvTmp" . $ajaxData["startTime"] . ".csv";
        return $tmpPath . $filname;
    }

    private function createCsvFile($tempFile, $delimiter = ";")
    {
        $header = $this->getAddressesCsvHeader(new Addresses());
        $handle = fopen($tempFile, "w");
        fputcsv($handle, $header, $delimiter);
        fclose($handle);
    }

    private function appandCsvFile($tempFile, $data, $delimiter = ";")
    {
        $handle = fopen($tempFile, "a");
        foreach ($data as $fields) {
            fputcsv($handle, $fields, $delimiter);
        }
        fclose($handle);
    }

    private function getAjaxDataFromPost()
    {
        return array(
            'operation' => filter_input(INPUT_POST, 'operation'),
            'operationTargets' => isset($_REQUEST["operationTargets"]) ? $_REQUEST["operationTargets"] : array(),
            'sourceBookId' => filter_input(INPUT_POST, 'sourceBookId'),
            'targetBookId' => filter_input(INPUT_POST, 'targetBookId'),
            'requestUrl' => filter_input(INPUT_POST, 'requestUrl'),
            'startTime' => filter_input(INPUT_POST, 'startTime'),
            'limit' => filter_input(INPUT_POST, 'limit'),
            "offset" => filter_input(INPUT_POST, 'offset'),
            'count' => filter_input(INPUT_POST, 'count'),
            "stopProcess" => filter_input(INPUT_POST, "stopProcess"),
            "sourceBookType" => filter_input(INPUT_POST, "sourceBookType"),
            "targetBookType" => filter_input(INPUT_POST, "targetBookType"),
            "ownerId" => filter_input(INPUT_POST, "ownerId"),
            "downloadLink" => filter_input(INPUT_POST, "downloadLink"),
        );
    }

    private function getAffectedItems(&$ajaxData, $offset = 0)
    {

        //FIXME : I only create a new instance of Addressbook to include AddressbookTypes enum class ... 
        $addressBook = new Addressbook();

        if ($ajaxData["operationTargets"] !== "null") {
            $addresses = $this->getAddressesByPk($ajaxData);
        } else if ($ajaxData["sourceBookType"] == AddressbookType::personal) {
            $addresses = $this->getPersonalAddresses($ajaxData, $offset);
        } else if ($ajaxData["sourceBookType"] == AddressbookType::group) {
            $addresses = $this->getPublicAddresses($ajaxData, $offset);
        } else if ($ajaxData["sourceBookType"] == AddressbookType::intern) {
            $addresses = $this->getPublicAddresses($ajaxData, $offset);
        }

        return $addresses;
    }

    private function getAddressesByPk(&$ajaxData)
    {

        $models = array();
        foreach ($ajaxData["operationTargets"] as $key => $value) {
            if (count($models) < $ajaxData["limit"]) {
                $model = Addresses::model()->findByPk($ajaxData["operationTargets"][$key]);
                if ($model) {
                    $models[] = $model;
                    unset($ajaxData["operationTargets"][$key]);
                } else {
                    break;
                }
            }
        }
        return $models;
    }

    private function getPersonalAddresses($ajaxData, $offset)
    {

        $models = Addresses::model()->find(
                array(
            "contact_owner" => $ajaxData["ownerId"],
            "contact_tid" => $ajaxData["sourceBookId"]
                ), "n_given", $ajaxData["limit"], $offset
        );

        return $models;
    }

    private function getPublicAddresses($ajaxData, $offset)
    {

        $models = Addresses::model()->find(
                array(
            "contact_tid" => $ajaxData["sourceBookId"]
                ), "n_given", $ajaxData["limit"], $offset
        );

        return $models;
    }

    private function writeCsvHeader($tmpPath)
    {
        $delimiter = ";"; // FIXME ?
        $handle = fopen($tmpPath, "w");
        $headerAttributeNames = array_keys(Addresses::csvRelevantAttributes());

        fputcsv($handle, $headerAttributeNames, $delimiter);
        fclose($handle);
    }

    private function writeAddressToTempFile($handle, $model)
    {
        $data = $model->getCsvValues();
        fputcsv($handle, $data);
    }

    private function calculateNewOffset($ajaxData)
    {
        $newOffset = $ajaxData["offset"] + $ajaxData["limit"];
        if ($newOffset > $ajaxData["count"]) {
            return $ajaxData["count"];
        }
        return $newOffset;
    }

    private function setStopProgress(&$ajaxData)
    {

        if ($ajaxData['offset'] >= $ajaxData['count']) {
            $ajaxData['offset'] = $ajaxData['count'];
            $ajaxData['stopProcess'] = true;
        }
    }
}
