<?php

Prado::using('Application.facades.Facade');
Prado::using('Application.facades.EventFacade');
Prado::using('Application.dto.CalendarDTO');
Prado::using('Application.dto.CalendarGroupDTO');
Prado::using('Application.model.Calendar');
Prado::using('Application.model.Category');
Prado::using('Application.model.UserPreference');
Prado::using('Application.user.DbUser');

class CalendarFacade extends Facade {

    private function _getCategoriesForCalendars(array $calendars) {
        return Category::finder()->findAllByPks(
            array_map(
                function($calendar) {
                    return $calendar->CategoryID;
                },
                $calendars
            )
        );
    }

    private $_defaultPreference = NULL;
    public function getDefaultPreference() {
        if ($this->_defaultPreference === NULL) {
            $this->_defaultPreference = Calendar::finder()->findAllByIsVisible(1);
        }
        return $this->_defaultPreference;
    }

    public function getCalendarPreference(DbUser $user) {
        if ($user->IsGuest) {
            return $this->getDefaultPreference();
        } else {
            return $user->DbRecord->Calendars;
        }
    }

    public function getPreferenceList(DbUser $user) {
        $calendars = $this->getCalendarPreference($user);
        if ($calendars) {
            $categories = array_map(
                function($category) use($calendars) {
                    $dto = new CalendarGroupDTO();
                    $dto->loadRecord($category, $calendars);
                    return $dto;
                },
                $this->_getCategoriesForCalendars($calendars)
            );
            usort($categories, ['CalendarGroupDTO', '__compare']);
            return $categories;
        }
        return [];
    }

    public function isCalendarPreferred(DbUser $user, $calendarID) {
        return in_array(
            $calendarID,
            array_map(
                function($calendar) {
                    return $calendar->UID;
                },
                $this->getCalendarPreference($user)
            )
        );
    }

    public function addToPreference(DbUser $user, $calendarID) {
        if (!$user->IsGuest) {
            $calendar = Calendar::finder()->findByPk($calendarID);
            if ($calendar) {
                $this->setPreferredCalendar($user->DbRecord, $calendar);
            }
        }
    }

    public function removeFromPreference(DbUser $user, $calendarID) {
        if (!$user->IsGuest) {
            $preferenceRecord = UserPreference::finder()->find(
                '_user = ? AND _calendar = ?',
                $user->DbRecord->ID,
                $calendarID
            );
            if ($preferenceRecord) {
                $preferenceRecord->delete();
            }
        }
    }

    public function setPreferredCalendar(User $user, Calendar $calendar) {
        $preference = new UserPreference();
        $preference->CalendarID = $calendar->UID;
        $preference->UserID = $user->ID;
        $preference->save();
    }

    public function setPreferredCalendars(User $user, $calendars) {
        //TODO: remove old preference, optionally
        $transaction = $this->beginTransaction();
        try {
            foreach ($calendars as $calendar) {
                $this->setPreferredCalendar($user, $calendar);
            }
            $transaction->commit();
        } catch (Exception $e) {
            $transaction->rollback();
            throw $e;
        }
    }

    public function getEventsForTimeframe(CalendarDTO $calendar,
                                          DateTime $dateFrom,
                                          DateTime $dateTo,
                                          $order = 'ASC') {
        $calendar = Calendar::finder()->findAllByUID($calendar->ID);
        if ($calendar) {
            $events = EventFacade::getInstance()->getEventList(
                $dateFrom->format('Y-m-d H:i:s'),
                $dateTo->format('Y-m-d H:i:s'),
                $calendar,
                $order
            );
            return array_map(
                function($event) use($calendar) {
                    $dto = new EventDTO();
                    $dto->loadRecord($event, $calendar);
                    return $dto;
                },
                $events
            );
        }
        return [];
    }

    public function getAll() {
        $records = Calendar::finder()->withCategory()->findAll('ORDER BY name ASC');
        foreach ($records as $record) {
            $this->_fillUrlCache($record);
        }
        return $records;
    }

    public function getCategories() {
        return Category::finder()->findAll('ORDER BY name ASC');
    }

    public function get($uid) {
        $records = Calendar::finder()->withCategory()->findAllByPks($uid);
        foreach ($records as $record) {
            $this->_fillUrlCache($record);
        }
        return $records;
    }

    private $_urlCache = [];
    private function _fillUrlCache($record) {
        if ($record && $record->CustomUrl
            && !isset($this->_urlCache[$record->CustomUrl])) {
            $dto = new CalendarDTO();
            if ($record) {
                $dto->loadRecord($record);
            } else {
                $dto = NULL;
            }
            return $this->_urlCache[$record->CustomUrl] = $dto;
        }
    }

    public function resolveUrl($url) {
        if ($url) {
            if (isset($this->_urlCache[$url])) {
                return $this->_urlCache[$url];
            }
            $record = Calendar::finder()->findByCustomUrl($url);
            if ($record) {
                return $this->_fillUrlCache($record);
            }
        }
        return NULL;
    }

}

?>