<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
   - License, v. 2.0. If a copy of the MPL was not distributed with this
   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->

<bindings 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="recurrence-preview" extends="xul:box">
    <resources>
      <stylesheet src="chrome://calendar/content/widgets/calendar-widget-bindings.css"/>
    </resources>               
    <content>
      <xul:box flex="1" style="overflow: hidden;">
        <xul:grid flex="1" anonid="mainbox">
          <xul:columns>
            <xul:column anonid="column"/>
            <xul:column flex="1"/>
          </xul:columns>
          <xul:rows>
            <xul:row anonid="row">
              <xul:minimonth anonid="minimonth" readonly="true"/>
              <xul:minimonth anonid="minimonth" readonly="true"/>
              <xul:minimonth anonid="minimonth" readonly="true"/>
              <xul:spacer/>
            </xul:row>
          </xul:rows>
        </xul:grid>
      </xul:box>
    </content>

    <implementation>

      <field name="mRecurrenceInfo">null</field>
      <field name="mResizeHandler">null</field>
      <field name="mDateTime">null</field>

      <constructor><![CDATA[
        var self = this;
        this.mResizeHandler = function recurrence_preview_resizeHandler() {
            self.onResize();
        };
        window.addEventListener("resize", this.mResizeHandler, true);
      ]]></constructor>

      <destructor><![CDATA[
        window.removeEventListener("resize", this.mResizeHandler, true);
      ]]></destructor>

      <property name="dateTime">
        <setter><![CDATA[
            return this.mDateTime = val.clone();
        ]]></setter>
        <getter><![CDATA[
            if (this.mDateTime == null) {
                this.mDateTime = now();
            }
            return this.mDateTime;
        ]]></getter>
      </property>
      <method name="onResize">
        <body><![CDATA[
          var mainbox =
              document.getAnonymousElementByAttribute(
                  this, "anonid", "mainbox");
          var minimonth =
              document.getAnonymousElementByAttribute(
                  this, "anonid", "minimonth");

          var row =
              document.getAnonymousElementByAttribute(
                  this, "anonid", "row");
          var rows = row.parentNode;

          var contentWidth = minimonth.boxObject.width;
          var containerWidth =
              document.getAnonymousNodes(this)[0]
                  .boxObject.width;

          // Now find out how much elements can be displayed.
          // this is a simple division which always yields a positive integer value.
          var numHorizontal =
              (containerWidth -
                  (containerWidth % contentWidth)) /
                      contentWidth;

          var contentHeight = minimonth.boxObject.height;
          var containerHeight =
              document.getAnonymousNodes(this)[0]
                  .boxObject.height;

          // Now find out how much elements can be displayed.
          // this is a simple division which always yields a positive integer value.
          var numVertical =
              (containerHeight -
                  (containerHeight % contentHeight)) /
                      contentHeight;
          numVertical = Math.max(1, numVertical);

          // Count the number of existing rows
          var numRows = 0;
          var rowIterator = row;
          while (rowIterator) {
              numRows++;
              rowIterator = rowIterator.nextSibling;
          }

          // Adjust rows
          while (numRows < numVertical) {
              var newNode = row.cloneNode(true);
              rows.appendChild(newNode);
              numRows++;
          }
          while (numRows > numVertical) {
              rows.firstChild.remove();
              numRows--
          }

          // Adjust columns in the grid
          var column =
              document.getAnonymousElementByAttribute(
                  this, "anonid", "column");
          var columns = column.parentNode;
          while ((columns.childNodes.length - 1) < numHorizontal) {
              var newColumn = column.cloneNode(false);
              columns.insertBefore(newColumn, column.nextSibling);
          }
          while ((columns.childNodes.length - 1) > numHorizontal) {
              columns.firstChild.remove();
          }

          // Walk all rows and adjust column elements
          row = document.getAnonymousElementByAttribute(
                   this, "anonid", "row");
          while (row) {
              var firstChild = row.firstChild;
              while ((row.childNodes.length - 1) < numHorizontal) {
                  var newNode = firstChild.cloneNode(true);
                  firstChild.parentNode.insertBefore(newNode, firstChild);
              }
              while ((row.childNodes.length - 1) > numHorizontal) {
                  row.firstChild.remove();
              }
              row = row.nextSibling;
          }

          this.updateContent();
          this.updatePreview(this.mRecurrenceInfo);
        ]]></body>
      </method>

      <method name="updateContent">
        <body><![CDATA[
          var dt = cal.dateTimeToJsDate(this.dateTime);
          var row = document.getAnonymousElementByAttribute(
                        this, "anonid", "row");
          while (row) {
              var numChilds = row.childNodes.length - 1;
              for (var i = 0; i < numChilds; i++) {
                  var minimonth = row.childNodes[i];
                  minimonth.showMonth(dt);
                  dt.setMonth(dt.getMonth() + 1);
              }
              row = row.nextSibling;
          }
        ]]></body>
      </method>

      <method name="updatePreview">
        <parameter name="aRecurrenceInfo"/>
        <body><![CDATA[
          this.mRecurrenceInfo = aRecurrenceInfo;
          var start = this.dateTime.clone();
          start.day = 1;
          start.hour = 0;
          start.minute = 0;
          start.second = 0;
          var end = start.clone();
          end.month++;
                      
          // the 'minimonth' controls are arranged in a
          // grid, sorted by rows first -> iterate the rows that may exist.
          var row = document.getAnonymousElementByAttribute(this, "anonid", "row");
          while (row) {
          
              // now iterater all the child nodes of this row
              // in order to visit each minimonth in turn.
              var numChilds = row.childNodes.length - 1;
              for (var i = 0; i < numChilds; i++) {
              
                  // we now have one of the minimonth controls while 'start'
                  // and 'end' are set to the interval this minimonth shows.
                  var minimonth = row.childNodes[i];
                  minimonth.showMonth(cal.dateTimeToJsDate(start));
                  if (aRecurrenceInfo) {
                      
                      // retrieve an array of dates that represents all occurrences
                      // that fall into this time interval [start,end[.
                      // note: the following loop assumes that this array conains
                      // dates that are strictly monotonically increasing.
                      // should getOccurrenceDates() not enforce this assumption we
                      // need to fall back to some different algorithm.
                      var dates = aRecurrenceInfo.getOccurrenceDates(start, end, 0, {});
                      
                      // now run throgh all days of this month and set the
                      // 'busy' attribute with respect to the occurrence array.
                      var index = 0;
                      var occurrence = null;
                      if (index < dates.length) {
                          occurrence =
                              dates[index++]
                                  .getInTimezone(start.timezone);
                      }
                      var current = start.clone();
                      while (current.compare(end) < 0) {
                        let box = minimonth.getBoxForDate(current);
                        if (box) {
                            if (occurrence &&
                                occurrence.day == current.day &&
                                occurrence.month == current.month &&
                                occurrence.year == current.year) {
                                box.setAttribute("busy", 1);
                                if (index < dates.length) {
                                    occurrence =
                                        dates[index++]
                                            .getInTimezone(start.timezone);
                                    // take into account that the very next occurrence
                                    // can happen at the same day as the previous one.
                                    if (occurrence.day == current.day &&
                                        occurrence.month == current.month &&
                                        occurrence.year == current.year) {
                                        continue;
                                    }
                                } else {
                                    occurrence = null;
                                }
                            } else {
                                box.removeAttribute("busy");
                            }
                        }
                        current.day++;
                      }
                  }
                  start.month++;
                  end.month++;
              }
              row = row.nextSibling;
          }
        ]]></body>
      </method>
    </implementation>
  </binding>
</bindings>
