/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

(function () {
  /* jshint loopfunc: true */
  'use strict';

  /**
   * @ngInject
   */
  CalendarController.$inject = ['$scope', '$rootScope', '$state', '$stateParams', '$mdDialog', 'sgHotkeys', 'Calendar', 'Component', 'Preferences', 'stateEventsBlocks'];
  function CalendarController($scope, $rootScope, $state, $stateParams, $mdDialog, sgHotkeys, Calendar, Component, Preferences, stateEventsBlocks) {
    var vm = this, deregisterCalendarsList, hotkeys = [], cdate = new Date(), currentCalendarDate = String(cdate.getFullYear()) + String((cdate.getMonth() + 1)).padStart(2, '0') + String((cdate.getDate())).padStart(2, '0');

    this.$onInit = function () {
      // Make the toolbar state of all-day events persistent
      if (angular.isUndefined(CalendarController.expandedAllDays))
        CalendarController.expandedAllDays = false;

      this.selectedDate = $stateParams.day.asDate();
      this.selectableDays = _.map(Preferences.defaults.SOGoCalendarWeekdays, function (day) {
        return _.indexOf(['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'], day);
      });
      this.expandedAllDays = CalendarController.expandedAllDays;
      this.views = stateEventsBlocks;

      _registerHotkeys(hotkeys);

      _formatDate(this.selectedDate);

      // Refresh current view when the list of calendars is modified
      deregisterCalendarsList = $rootScope.$on('calendars:list', _updateView);

      // NOTE: $onDestroy won't work with ui-router (tested with v1.0.20).
      $scope.$on('$destroy', function () {
        // Destroy event listener when the controller is being deactivated
        deregisterCalendarsList();
        // Deregister hotkeys
        _.forEach(hotkeys, function (key) {
          sgHotkeys.deregisterHotkey(key);
        });
      });
    };

    function _registerHotkeys(keys) {
      keys.push(sgHotkeys.createHotkey({
        key: l('hotkey_today'),
        description: l('Today'),
        callback: vm.changeDate,
        args: new Date()
      }));
      keys.push(sgHotkeys.createHotkey({
        key: l('hotkey_dayview'),
        description: l('Day'),
        callback: vm.changeView,
        args: 'day'
      }));
      keys.push(sgHotkeys.createHotkey({
        key: l('hotkey_weekview'),
        description: l('Week'),
        callback: vm.changeView,
        args: 'week'
      }));
      keys.push(sgHotkeys.createHotkey({
        key: l('hotkey_monthview'),
        description: l('Month'),
        callback: vm.changeView,
        args: 'month'
      }));
      keys.push(sgHotkeys.createHotkey({
        key: l('hotkey_multicolumndayview'),
        description: l('Multicolumn Day View'),
        callback: vm.changeView,
        args: 'multicolumnday'
      }));
      keys.push(sgHotkeys.createHotkey({
        key: 'left',
        description: l('Move backward'),
        callback: _goToPeriod,
        args: -1
      }));
      keys.push(sgHotkeys.createHotkey({
        key: 'right',
        description: l('Move forward'),
        callback: _goToPeriod,
        args: +1
      }));

      // Register the hotkeys
      _.forEach(keys, function (key) {
        sgHotkeys.registerHotkey(key);
      });
    }


    function _goToPeriod($event, direction) {
      var date;

      if ($stateParams.view == 'week') {
        date = vm.selectedDate.beginOfWeek(Preferences.defaults.SOGoFirstDayOfWeek).addDays(7 * direction);
      }
      else if ($stateParams.view == 'month') {
        date = vm.selectedDate;
        date.setDate(1);
        date.setMonth(date.getMonth() + direction);
      }
      else {
        date = vm.selectedDate.addDays(direction);
        while (!vm.isSelectableDay(date)) {
          date = date.addDays(direction);
        }
      }

      vm.changeDate($event, date);
    }

    /**
     * Format a date according to the current view.
     * - Day/Multicolumn: name of weekday
     * - Week: week number
     * - Month: name of month
     */
    function _formatDate(date) {
      if ($stateParams.view == 'month') {
        date.setDate(1);
        date.setHours(12);
        date.$dateFormat = '%B %Y';
      }
      else if ($stateParams.view == 'week') {
        date.setTime(date.beginOfWeek(Preferences.defaults.SOGoFirstDayOfWeek).getTime());
        date.$dateFormat = l('Week %d').replace('%d', '%U');
      }
      else {
        date.$dateFormat = '%A';
      }
    }

    function _updateView() {
      // The list of calendars has changed; update the views
      // See stateEventsBlocks in Scheduler.app.js
      Component.$eventsBlocksForView($stateParams.view, $stateParams.day.asDate()).then(function (data) {
        var i, j, view;
        for (i = 0; i < data.length; i++) {
          view = data[i];
          if (vm.views[i]) {
            _.forEach(view.allDayBlocks, function (blocks, day) {
              vm.views[i].allDayBlocks[day] = blocks;
            });
            _.forEach(view.blocks, function (blocks, day) {
              vm.views[i].blocks[day] = blocks;
            });
          }
          else {
            vm.views[i] = view;
          }
          if (view.id) {
            // Note: this can't be done in Component service since it would make Component dependent on
            // the Calendar service and create a circular dependency
            vm.views[i].calendar = new Calendar({ id: view.id, name: view.calendarName });
          }
        }
        // Remove previous views
        for (j = vm.views.length; j >= i; j--)
          vm.views.splice(j, 1);

        // Refresh view
        var d = new Date();
        var date = String(d.getFullYear()) + String((d.getMonth() + 1)).padStart(2, '0') + String((d.getDate())).padStart(2, '0');
        if (currentCalendarDate !== date) {
          $state.go('calendars.view', { day: date });
          currentCalendarDate = date;
        }
      });
    }

    // Expand or collapse all-day events
    this.toggleAllDays = function () {
      CalendarController.expandedAllDays = !CalendarController.expandedAllDays;
      this.expandedAllDays = CalendarController.expandedAllDays;
    };

    // Change calendar's date
    this.changeDate = function ($event, newDate, isToday = false) {
      var date = newDate ? newDate.getDayString() : angular.element($event.currentTarget).attr('date');
      if (newDate)
        _formatDate(newDate);

      if (isToday) {
        var d = new Date();
        date = String(d.getFullYear()) + String((d.getMonth() + 1)).padStart(2, '0') + String((d.getDate())).padStart(2, '0');
      }
      $state.go('calendars.view', { day: date });

      // Refresh calendar data if click on today
      if (isToday) {
        $rootScope.$emit('calendars:list');
      }
      // $state.transitionTo('calendars.view', { day: date });
    };

    // Change calendar's view
    this.changeView = function ($event, view) {
      $state.go('calendars.view', { view: view });
    };

    this.printView = function (centerIsClose, componentType) {
      $mdDialog.show({
        parent: angular.element(document.body),
        clickOutsideToClose: true,
        escapeToClose: true,
        templateUrl: 'UIxCalPrintDialog', // See UIxCalMainView.wox
        controller: PrintController,
        controllerAs: '$PrintDialogController',
        locals: {
          calendarView: $stateParams.view,
          visibleList: centerIsClose ? undefined : componentType
        }
      });

    };

    // Check if the week day should be visible/selectable
    this.isSelectableDay = function (date) {
      return _.includes(vm.selectableDays, date.getDay());
    };
  }

  /**
   * @ngInject
   */
  PrintController.$inject = ['$rootScope', '$scope', '$window', '$stateParams', '$mdDialog', '$log', 'Dialog', 'sgSettings', 'Preferences', 'Calendar', 'calendarView', 'visibleList'];
  function PrintController($rootScope, $scope, $window, $stateParams, $mdDialog, $log, Dialog, Settings, Preferences, Calendar, calendarView, visibleList) {
    var vm = this;
    var orientations = {
      day: 'portrait',
      week: 'landscape',
      month: 'landscape',
      multicolumnday: 'landscape'
    };

    this.$onInit = function () {
      // Default values
      this.pageSize = 'letter';
      this.workingHoursOnly = true;
      this.calendarView = calendarView;
      this.orientation = orientations[this.calendarView];
      this.visibleList = visibleList;

      angular.element(document.body).addClass(this.orientation);
      $scope.$watch(function () { return vm.pageSize; }, angular.bind(this, function (newSize, oldSize) {
        angular.element(document.body).removeClass(oldSize);
        angular.element(document.body).addClass(newSize);
      }));
    };

    this.$onDestroy = function () {
      angular.element(document.body).removeClass(['portrait', 'landscape', 'letter', 'legal', 'a4']);
    };

    this.print = function ($event) {
      $window.print();
      $event.stopPropagation();
      return false;
    };

    this.close = function () {
      $mdDialog.hide();
    };
  }

  angular
    .module('SOGo.SchedulerUI')
    .controller('CalendarController', CalendarController);
})();
