/* 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/. */

/**
 * This file is loaded into the printing options page by calPrintUtils.jsm if
 * we are printing the calendar. It injects a new form (from
 * calendar-tab-panels.inc.xhtml) for choosing the print output. It also
 * contains the javascript for the form.
 */

/* import-globals-from ../../../../toolkit/components/printing/content/print.js */

const { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");

// In a block to avoid polluting the global scope.
{
  let ownerWindow = window.browsingContext.topChromeWindow;
  let ownerDocument = ownerWindow.document;

  for (let href of [
    "chrome://messenger/skin/icons.css",
    "chrome://messenger/skin/variables.css",
    "chrome://messenger/skin/widgets.css",
    "chrome://calendar/skin/shared/widgets/minimonth.css",
  ]) {
    let link = document.head.appendChild(document.createElement("link"));
    link.rel = "stylesheet";
    link.href = href;
  }

  let otherForm = document.querySelector("form");
  otherForm.hidden = true;

  let form = document.importNode(
    ownerDocument.getElementById("calendarPrintForm").content.firstElementChild,
    true
  );
  if (AppConstants.platform != "win") {
    // Move the Next button to the end if this isn't Windows.
    let nextButton = form.querySelector("#next-button");
    nextButton.parentElement.append(nextButton);
  }
  form.addEventListener("submit", event => {
    event.preventDefault();
    form.hidden = true;
    otherForm.hidden = false;
  });
  otherForm.parentNode.insertBefore(form, otherForm);

  let backButton = form.querySelector("#back-button");
  backButton.addEventListener("click", () => {
    otherForm.hidden = true;
    form.hidden = false;
  });
  let backButtonContainer = form.querySelector("#back-button-container");
  let printButtonContainer = otherForm.querySelector("#button-container");
  printButtonContainer.parentNode.insertBefore(backButtonContainer, printButtonContainer);

  let eventsCheckbox = form.querySelector("input#events");
  let tasksCheckbox = form.querySelector("input#tasks");
  let tasksNotDueCheckbox = form.querySelector("input#tasks-with-no-due-date");
  let tasksCompletedCheckbox = form.querySelector("input#completed-tasks");

  let layout = form.querySelector("select#layout");

  let fromMinimonth = form.querySelector("calendar-minimonth#from-minimonth");
  let fromMonth = form.querySelector("select#from-month");
  let fromYear = form.querySelector("input#from-year");
  let fromDate = form.querySelector("select#from-date");

  let toMinimonth = form.querySelector("calendar-minimonth#to-minimonth");
  let toMonth = form.querySelector("select#to-month");
  let toYear = form.querySelector("input#to-year");
  let toDate = form.querySelector("select#to-date");

  for (let i = 0; i < 12; i++) {
    let option = document.createElement("option");
    option.value = i;
    option.label = cal.l10n.formatMonth(i + 1, "calendar", "monthInYear");
    fromMonth.appendChild(option.cloneNode(false));
    toMonth.appendChild(option);
  }

  eventsCheckbox.addEventListener("change", updatePreview);
  tasksCheckbox.addEventListener("change", function () {
    tasksNotDueCheckbox.disabled = !this.checked;
    tasksCompletedCheckbox.disabled = !this.checked;
    updatePreview();
  });
  tasksNotDueCheckbox.addEventListener("change", updatePreview);
  tasksCompletedCheckbox.addEventListener("change", updatePreview);

  layout.addEventListener("change", onLayoutChange);

  fromMinimonth.addEventListener("change", function () {
    if (toMinimonth.value < fromMinimonth.value) {
      toMinimonth.value = fromMinimonth.value;
    }

    updatePreview();
  });
  toMinimonth.addEventListener("change", updatePreview);

  fromMonth.addEventListener("keydown", function (event) {
    if (event.key == "ArrowDown" && fromMonth.selectedIndex == 11) {
      fromMonth.selectedIndex = 0;
      fromYear.value++;
      onMonthChange();
      event.preventDefault();
    } else if (event.key == "ArrowUp" && fromMonth.selectedIndex == 0) {
      fromMonth.selectedIndex = 11;
      fromYear.value--;
      onMonthChange();
      event.preventDefault();
    }
  });
  fromMonth.addEventListener("change", onMonthChange);
  fromYear.addEventListener("change", onMonthChange);
  toMonth.addEventListener("keydown", function (event) {
    if (event.key == "ArrowDown" && toMonth.selectedIndex == 11) {
      toMonth.selectedIndex = 0;
      toYear.value++;
      onMonthChange();
      event.preventDefault();
    } else if (event.key == "ArrowUp" && toMonth.selectedIndex == 0) {
      toMonth.selectedIndex = 11;
      toYear.value--;
      onMonthChange();
      event.preventDefault();
    }
  });
  toMonth.addEventListener("change", onMonthChange);
  toYear.addEventListener("change", onMonthChange);

  fromDate.addEventListener("change", function () {
    let fromValue = parseInt(fromDate.value, 10);
    for (let option of toDate.options) {
      option.hidden = option.value < fromValue;
    }
    if (toDate.value < fromValue) {
      toDate.value = fromValue;
    }

    updatePreview();
  });
  toDate.addEventListener("change", updatePreview);

  // Ensure the layout selector is focused and has a focus ring to make it
  // more obvious. The ring won't be added if already focused, so blur first.
  requestAnimationFrame(() => {
    layout.blur();
    Services.focus.setFocus(layout, Services.focus.FLAG_SHOWRING);
  });

  /** Show something in the preview as soon as it is ready. */
  function updateWhenReady() {
    document.removeEventListener("page-count", updateWhenReady);
    onLayoutChange();
  }
  document.addEventListener("page-count", updateWhenReady);

  /**
   * Update the available date options to sensible ones for the selected layout.
   * It would be nice to use HTML date inputs here but the browser this form is
   * loaded into won't allow it. Instead use lists of the most likely values,
   * which actually fits better for some print layouts.
   */
  function onLayoutChange() {
    if (layout.value == "list") {
      fromMinimonth.hidden = toMinimonth.hidden = false;
      fromMonth.hidden = fromYear.hidden = toMonth.hidden = toYear.hidden = true;
      fromDate.hidden = toDate.hidden = true;
    } else if (layout.value == "monthGrid") {
      let today = new Date();
      fromMonth.value = toMonth.value = today.getMonth();
      fromYear.value = toYear.value = today.getFullYear();

      fromMinimonth.hidden = toMinimonth.hidden = true;
      fromMonth.hidden = fromYear.hidden = toMonth.hidden = toYear.hidden = false;
      fromDate.hidden = toDate.hidden = true;
    } else {
      const FIRST_WEEK = -53;
      const LAST_WEEK = 53;

      while (fromDate.lastChild) {
        fromDate.lastChild.remove();
      }
      while (toDate.lastChild) {
        toDate.lastChild.remove();
      }

      // Always use Monday - Sunday week, regardless of prefs, because the layout requires it.
      let monday = cal.dtz.now();
      monday.isDate = true;
      monday.day = monday.day - monday.weekday + 1 + FIRST_WEEK * 7;

      for (let i = FIRST_WEEK; i < LAST_WEEK; i++) {
        let option = document.createElement("option");
        option.value = i;
        option.label = cal.dtz.formatter.formatDateLong(monday);
        fromDate.appendChild(option.cloneNode(false));

        let sunday = monday.clone();
        sunday.day += 6;
        option.label = cal.dtz.formatter.formatDateLong(sunday);
        option.hidden = i < 0;
        toDate.appendChild(option);

        monday.day += 7;
      }

      fromDate.value = toDate.value = 0;

      fromMinimonth.hidden = toMinimonth.hidden = true;
      fromMonth.hidden = fromYear.hidden = toMonth.hidden = toYear.hidden = true;
      fromDate.hidden = toDate.hidden = false;
    }

    updatePreview();
  }

  function onMonthChange() {
    if (parseInt(toYear.value, 10) < fromYear.value) {
      toYear.value = fromYear.value;
      toMonth.value = fromMonth.value;
    } else if (toYear.value == fromYear.value && parseInt(toMonth.value, 10) < fromMonth.value) {
      toMonth.value = fromMonth.value;
    }
    updatePreview();
  }

  /**
   * Read the selected options and update the preview document.
   */
  async function updatePreview() {
    let startDate = cal.dtz.now();
    startDate.isDate = true;
    let endDate = cal.dtz.now();
    endDate.isDate = true;

    if (layout.value == "list") {
      let fromValue = fromMinimonth.value;
      let toValue = toMinimonth.value;

      startDate.resetTo(
        fromValue.getFullYear(),
        fromValue.getMonth(),
        fromValue.getDate(),
        0,
        0,
        0,
        cal.dtz.floating
      );
      startDate.isDate = true;
      if (toValue > fromValue) {
        endDate.resetTo(
          toValue.getFullYear(),
          toValue.getMonth(),
          toValue.getDate(),
          0,
          0,
          0,
          cal.dtz.floating
        );
        endDate.isDate = true;
      } else {
        endDate = startDate.clone();
      }
      endDate.day++;
    } else if (layout.value == "monthGrid") {
      startDate.day = 1;
      startDate.month = parseInt(fromMonth.value, 10);
      startDate.year = parseInt(fromYear.value, 10);
      endDate.day = 1;
      endDate.month = parseInt(toMonth.value, 10);
      endDate.year = parseInt(toYear.value, 10);
      endDate.month++;
    } else {
      startDate.day = startDate.day - startDate.weekday + 1;
      startDate.day += parseInt(fromDate.value, 10) * 7;
      endDate.day = endDate.day - endDate.weekday + 1;
      endDate.day += parseInt(toDate.value, 10) * 7 + 7;
    }

    let filter = 0;
    if (tasksCheckbox.checked) {
      filter |= Ci.calICalendar.ITEM_FILTER_TYPE_TODO;
      if (tasksCompletedCheckbox.checked) {
        filter |= Ci.calICalendar.ITEM_FILTER_COMPLETED_ALL;
      } else {
        filter |= Ci.calICalendar.ITEM_FILTER_COMPLETED_NO;
      }
    }

    if (eventsCheckbox.checked) {
      filter |=
        Ci.calICalendar.ITEM_FILTER_TYPE_EVENT | Ci.calICalendar.ITEM_FILTER_CLASS_OCCURRENCES;
    }

    await cal.print.draw(
      PrintEventHandler.printPreviewEl.querySelector("browser").contentDocument,
      layout.value,
      startDate,
      endDate,
      filter,
      tasksNotDueCheckbox.checked
    );
    PrintEventHandler._updatePrintPreview();
  }
}
