<?xml version="1.0"?>
<!--
   - ***** BEGIN LICENSE BLOCK *****
   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
   -
   - The contents of this file are subject to the Mozilla Public License Version
   - 1.1 (the "License"); you may not use this file except in compliance with
   - the License. You may obtain a copy of the License at
   - http://www.mozilla.org/MPL/
   -
   - Software distributed under the License is distributed on an "AS IS" basis,
   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   - for the specific language governing rights and limitations under the
   - License.
   -
   - The Original Code is calendar views.
   -
   - The Initial Developer of the Original Code is Oracle Corporation
   - Portions created by the Initial Developer are Copyright (C) 2005
   - the Initial Developer. All Rights Reserved.
   -
   - Contributor(s):
   -   Stuart Parmenter <stuart.parmenter@oracle.com>
   -   Simon Paquet <bugzilla@babylonsounds.com>
   -   Joey Minta <jminta@gmail.com>
   -   Stefan Sitter <ssitter@googlemail.com>
   -   Philipp Kewisch <mozilla@kewis.ch>
   -
   - Alternatively, the contents of this file may be used under the terms of
   - either the GNU General Public License Version 2 or later (the "GPL"), or
   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
   - in which case the provisions of the GPL or the LGPL are applicable instead
   - of those above. If you wish to allow use of your version of this file only
   - under the terms of either the GPL or the LGPL, and not to allow others to
   - use your version of this file under the terms of the MPL, indicate your
   - decision by deleting the provisions above and replace them with the notice
   - and other provisions required by the GPL or the LGPL. If you do not delete
   - the provisions above, a recipient may use your version of this file under
   - the terms of any one of the MPL, the GPL or the LGPL.
   -
   - ***** END LICENSE BLOCK ***** -->

<!DOCTYPE bindings
[
  <!ENTITY % dtd1 SYSTEM "chrome://calendar/locale/global.dtd" > %dtd1;
  <!ENTITY % dtd2 SYSTEM "chrome://calendar/locale/calendar.dtd" > %dtd2;
]>

<bindings id="calendar-alarms"
   xmlns="http://www.mozilla.org/xbl"
   xmlns:xbl="http://www.mozilla.org/xbl"
   xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

  <binding id="calendar-alarm-widget" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
    <resources>
      <stylesheet src="chrome://global/skin/button.css"/>
      <stylesheet src="chrome://calendar/skin/calendar-alarm-dialog.css"/>
    </resources>

    <content orient="horizontal">
      <xul:vbox pack="start">
        <xul:image class="alarm-calendar-image"/>
      </xul:vbox>
      <xul:vbox>
        <xul:label anonid="alarm-title-label" class="alarm-title-label" crop="end"/>
        <xul:vbox class="additional-information-box">
          <xul:label anonid="alarm-date-label" class="alarm-date-label"/>
          <xul:hbox>
            <xul:label anonid="alarm-location-label" class="location-label">&calendar.alarm.location.label;</xul:label>
            <xul:description anonid="alarm-location-description" class="alarm-location-description" crop="end"/>
          </xul:hbox>
          <xul:hbox pack="start">
            <xul:label class="text-link alarm-details-label"
                   value="&calendar.alarm.details.label;"
                   onclick="showDetails(event)"
                   onkeypress="showDetails(event)"/>
          </xul:hbox>
        </xul:vbox>
      </xul:vbox>
      <xul:spacer flex="1"/>
      <xul:label anonid="alarm-relative-date-label" class="alarm-relative-date-label"/>
      <xul:vbox class="alarm-action-buttons" pack="center">
        <xul:button anonid="alarm-snooze-button"
                    type="menu"
                    label="&calendar.alarm.snoozefor.label;">
          <xul:menupopup type="snooze-menupopup" ignorekeys="true"/>
        </xul:button>
        <xul:button anonid="alarm-dismiss-button"
                    label="&calendar.alarm.dismiss.label;"
                    oncommand="dismissAlarm()"/>
      </xul:vbox>
    </content>

    <implementation>
      <constructor><![CDATA[
        Components.utils.import("resource://calendar/modules/calUtils.jsm");
      ]]></constructor>

      <field name="mItem">null</field>
      <field name="mAlarm">null</field>

      <property name="item"
                onget="return this.mItem;"
                onset="this.mItem = val; this.updateLabels(); return val;"/>
      <property name="alarm"
                onget="return this.mAlarm;"
                onset="this.mAlarm = val; this.updateLabels(); return val;"/>

      <method name="updateLabels">
        <body><![CDATA[
          if (!this.mItem || !this.mAlarm) {
              // Setup not complete, do nothing for now.
              return;
          }

          let formatter = cal.getDateFormatter();
          let titleLabel = document.getAnonymousElementByAttribute(this, "anonid", "alarm-title-label");
          let locationDescription = document.getAnonymousElementByAttribute(this, "anonid", "alarm-location-description");
          let dateLabel = document.getAnonymousElementByAttribute(this, "anonid", "alarm-date-label");

          // Dates
          let startString = {};
          let endString = {};

          if (cal.isEvent(this.mItem)) {
              dateLabel.textContent = formatter.formatItemInterval(this.mItem);
          } else if (cal.isToDo(this.mItem)) {
              let startDate = this.mItem.entryDate || this.mItem.dueDate;
              if (startDate) {
                  // A Task with a start or due date, show with label
                  startDate = startDate.getInTimezone(cal.calendarDefaultTimezone());
                  dateLabel.textContent = calGetString("calendar",
                                                       "alarmStarts",
                                                       [formatter.formatDateTime(startDate)]);
              } else {
                  // If the task has no start date, then format the alarm date.
                  dateLabel.textContent = formatter.formatDateTime(this.mAlarm.alarmDate);
              }
          } else {
              throw Components.results.NS_ERROR_ILLEGAL_VALUE;
          }

          // Relative date
          this.updateRelativeDateLabel();

          // Title, location
          titleLabel.value = this.mItem.title || "";
          locationDescription.value = this.mItem.getProperty("LOCATION") || "";
          locationDescription.hidden = (locationDescription.value.length < 1);

          document.getAnonymousElementByAttribute(this, "anonid", "alarm-location-label").hidden =
              (locationDescription.value.length < 1);
        ]]></body>
      </method>

      <method name="updateRelativeDateLabel">
        <body><![CDATA[
          let formatter = cal.getDateFormatter();
          let item = this.mItem;
          let relativeDateLabel = document.getAnonymousElementByAttribute(this, "anonid", "alarm-relative-date-label");
          let relativeDateString;
          let startDate = item[calGetStartDateProp(item)] || item[calGetEndDateProp(item)];
          if (!startDate) {
              // No start or end date, therefore the alarm must be absolute and
              // have an alarm date.
              relativeDateString = [formatter.formatDateTime(this.mAlarm.alarmDate)];
          } else {
              startDate = startDate.getInTimezone(calendarDefaultTimezone());
              let currentDate = now();
              let sinceDayStart = (currentDate.hour * 3600) + (currentDate.minute * 60);

              currentDate.second = 0;
              startDate.second = 0;

              let sinceAlarm = currentDate.subtractDate(startDate).inSeconds;
              this.mAlarmToday = (sinceAlarm < sinceDayStart) && (sinceAlarm > sinceDayStart - 86400);

              if (this.mAlarmToday) {
                  // The alarm is today
                  relativeDateString = calGetString("calendar",
                                                    "alarmTodayAt",
                                                    [formatter.formatTime(startDate)]);
              } else if (sinceAlarm <= sinceDayStart - 86400 && sinceAlarm > sinceDayStart - 172800) {
                  // The alarm is tomorrow
                  relativeDateString = calGetString("calendar",
                                                    "alarmTomorrowAt",
                                                    [formatter.formatTime(startDate)]);
              } else if (sinceAlarm < sinceDayStart + 86400 && sinceAlarm > sinceDayStart) {
                  // The alarm is yesterday
                  relativeDateString = calGetString("calendar",
                                                    "alarmYesterdayAt",
                                                    [formatter.formatTime(startDate)]);
              } else {
                  // The alarm is way back
                  relativeDateString = [formatter.formatDateTime(startDate)];
              }
          }

          relativeDateLabel.textContent = relativeDateString;
        ]]></body>
      </method>

      <method name="showDetails">
        <parameter name="event"/>
        <body><![CDATA[
          if (event.type == "click" ||
              (event.type == "keypress" &&
               (event.keyCode == event.DOM_VK_ENTER ||
                event.keyCode == event.DOM_VK_RETURN))) {
              let detailsEvent = document.createEvent('Events');
              detailsEvent.initEvent('itemdetails', true, false);
              this.dispatchEvent(detailsEvent);
          }
        ]]></body>
      </method>

      <method name="dismissAlarm">
        <body><![CDATA[
          let dismissEvent = document.createEvent('Events');
          dismissEvent.initEvent('dismiss', true, false);
          this.dispatchEvent(dismissEvent);
        ]]></body>
      </method>
    </implementation>
  </binding>

  <binding id="calendar-snooze-popup">
    <content ignorekeys="true">
      <xul:menuitem label="&calendar.alarm.snooze.5minutes.label;"
                    value="5"
                    oncommand="snoozeItem(event)"/>
      <xul:menuitem label="&calendar.alarm.snooze.10minutes.label;"
                    value="10"
                    oncommand="snoozeItem(event)"/>
      <xul:menuitem label="&calendar.alarm.snooze.15minutes.label;"
                    value="15"
                    oncommand="snoozeItem(event)"/>
      <xul:menuitem label="&calendar.alarm.snooze.30minutes.label;"
                    value="30"
                    oncommand="snoozeItem(event)"/>
      <xul:menuitem label="&calendar.alarm.snooze.45minutes.label;"
                    value="45"
                    oncommand="snoozeItem(event)"/>
      <xul:menuitem label="&calendar.alarm.snooze.1hour.label;"
                    value="60"
                    oncommand="snoozeItem(event)"/>
      <xul:menuitem label="&calendar.alarm.snooze.2hours.label;"
                    value="120"
                    oncommand="snoozeItem(event)"/>
      <xul:menuitem label="&calendar.alarm.snooze.1day.label;"
                    value="1440"
                    oncommand="snoozeItem(event)"/>
      <children/>
      <xul:menuseparator/>
      <xul:hbox class="snooze-options-box">
        <xul:textbox anonid="snooze-value-textbox"
                     oninput="updateAccessibleName()"
                     type="number"
                     hidespinbuttons="true"
                     size="3"/>
        <xul:menulist anonid="snooze-unit-menulist"
                      class="snooze-unit-menulist menuitem-non-iconic"
                      allowevents="true">
         <xul:menupopup anonid="snooze-unit-menupopup"
                        position="after_start"
                        ignorekeys="true"
                        class="menulist-menupopup">
           <xul:menuitem closemenu="single" class="unit-menuitem" label="&calendar.global.units.minutes;" value="1"/>
           <xul:menuitem closemenu="single" class="unit-menuitem" label="&calendar.global.units.hours;" value="60"/>
           <xul:menuitem closemenu="single" class="unit-menuitem" label="&calendar.global.units.days;" value="1440"/>
         </xul:menupopup>
        </xul:menulist>
        <xul:toolbarbutton anonid="snooze-popup-ok"
                           class="snooze-popup-button snooze-popup-ok-button"
                           oncommand="snoozeOk()"/>
        <xul:toolbarbutton anonid="snooze-popup-cancel"
                           class="snooze-popup-button snooze-popup-cancel-button"
                           aria-label="&calendar.alarm.snooze.cancel;"
                           oncommand="snoozeCancel()"/>
      </xul:hbox>
    </content>
    <implementation>
      <constructor><![CDATA[
        let snoozePref = getPrefSafe("calendar.alarms.defaultsnoozelength", 0);
        if (snoozePref <= 0) {
          snoozePref = 5;
        }

        let unitList = document.getAnonymousElementByAttribute(this, "anonid", "snooze-unit-menulist");
        let unitValue = document.getAnonymousElementByAttribute(this, "anonid", "snooze-value-textbox");

        let selectedIndex = 0;
        if ((snoozePref % 60) == 0) {
            snoozePref = snoozePref / 60;
            if ((snoozePref % 24) == 0) {
                snoozePref = snoozePref / 24;
                selectedIndex = 2; // Days
            } else {
                selectedIndex = 1; // Hours
            }
        } else {
            selectedIndex = 0; // Minutes
        }

        unitList.selectedIndex = selectedIndex;
        unitValue.value = snoozePref;

        updateAccessibleName();
      ]]></constructor>

      <method name="snoozeAlarm">
        <parameter name="minutes"/>
        <body><![CDATA[
          let snoozeEvent = document.createEvent('Events');
          snoozeEvent.initEvent('snooze', true, false);
          snoozeEvent.detail = minutes;

          // The onsnooze attribute is set on the menupopup, this binding is
          // instanciated on the menupopup's arrowscrollbox. Therefore we need
          // to go up one node.
          let handler = this.parentNode.getAttribute("onsnooze");
          let cancel = false;
          if (handler) {
              let fn = new Function("event", handler);
              cancel = (fn.call(this, snoozeEvent) === false);
          }

          if (!cancel) {
              this.dispatchEvent(snoozeEvent);
          }
        ]]></body>
      </method>

      <method name="snoozeItem">
        <parameter name="event"/>
        <body><![CDATA[
          this.snoozeAlarm(event.target.value);
        ]]></body>
      </method>

      <method name="snoozeOk">
        <body><![CDATA[
          let unitList = document.getAnonymousElementByAttribute(this, "anonid", "snooze-unit-menulist");
          let unitValue = document.getAnonymousElementByAttribute(this, "anonid", "snooze-value-textbox");

          let minutes = (unitList.value || 1) * unitValue.value;
          this.snoozeAlarm(minutes);
        ]]></body>
      </method>

      <method name="snoozeCancel">
        <body><![CDATA[
          this.parentNode.hidePopup();
        ]]></body>
      </method>

      <method name="updateAccessibleName">
        <body><![CDATA[
          let unitList = document.getAnonymousElementByAttribute(this, "anonid", "snooze-unit-menulist");
          let unitValue = document.getAnonymousElementByAttribute(this, "anonid", "snooze-value-textbox");
          let okButton = document.getAnonymousElementByAttribute(this, "anonid", "snooze-popup-ok");

          let unitName = {
              1: "Minutes",
              60: "Hours",
              1440: "Days"
          }[unitList.value] || "Minutes";

          let pluralString = calGetString("calendar-alarms", "reminderCustomUnit" + unitName);
          let unitPlural = PluralForm.get(unitValue.value, pluralString)
                                     .replace("#1", unitValue.value);

          let accessibleString = calGetString("calendar-alarms",
                                              "reminderSnoozeOkA11y",
                                              [unitPlural]);
          okButton.setAttribute("aria-label", accessibleString);
        ]]></body>
      </method>
    </implementation>
  </binding>
</bindings>
