define(["dijit/dijit", "dojo"], function (dijit, dojo) {
  "use strict";
  /* global Cesium */

  var defined = Cesium.defined;
  var Clock = Cesium.Clock;
  var ClockRange = Cesium.ClockRange;
  var Timeline = Cesium.Timeline;
  var TimeInterval = Cesium.TimeInterval;
  var JulianDate = Cesium.JulianDate;
  var Color = Cesium.Color;
  var ClockViewModel = Cesium.ClockViewModel;
  var AnimationViewModel = Cesium.AnimationViewModel;

  var startDatePart, endDatePart, startTimePart, endTimePart;
  var timeline,
    clock,
    endBeforeStart,
    containerElement,
    animationViewModel,
    animation;

  function updateScrubTime(julianDate) {
    document.getElementById("mousePos").innerHTML =
      timeline.makeLabel(julianDate) + " UTC";
  }

  function handleSetTime(e) {
    if (defined(timeline)) {
      var scrubJulian = e.timeJulian;
      clock.shouldAnimate = false;
      clock.currentTime = scrubJulian;
      updateScrubTime(scrubJulian);
    }
  }

  function spanToString(span) {
    var spanUnits = "sec";
    if (span > 31536000) {
      span /= 31536000;
      spanUnits = "years";
    } else if (span > 2592000) {
      span /= 2592000;
      spanUnits = "months";
    } else if (span > 604800) {
      span /= 604800;
      spanUnits = "weeks";
    } else if (span > 86400) {
      span /= 86400;
      spanUnits = "days";
    } else if (span > 3600) {
      span /= 3600;
      spanUnits = "hours";
    } else if (span > 60) {
      span /= 60;
      spanUnits = "minutes";
    }
    return span.toString() + " " + spanUnits;
  }

  function handleSetZoom(e) {
    dojo.byId("formatted").innerHTML =
      //'<br/>Epoch: ' + timeline.makeLabel(e.epochJulian) + ' UTC' +
      "<br/>Start: " +
      timeline.makeLabel(e.startJulian) +
      " UTC" +
      "<br/>&nbsp;Stop: " +
      timeline.makeLabel(e.endJulian) +
      " UTC" +
      "<br/>&nbsp;Span: " +
      spanToString(e.totalSpan) +
      "<br/>&nbsp;&nbsp;Tic: " +
      spanToString(e.mainTicSpan);
    updateScrubTime(clock.currentTime);
  }

  function makeTimeline(startJulian, scrubJulian, endJulian) {
    clock = new Clock({
      startTime: startJulian,
      currentTime: scrubJulian,
      stopTime: endJulian,
      clockRange: ClockRange.LOOP_STOP,
      multiplier: 60,
      shouldAnimate: true,
    });

    timeline = new Timeline("time1", clock);
    timeline.addEventListener("settime", handleSetTime, false);
    timeline.addEventListener("setzoom", handleSetZoom, false);

    timeline.addTrack(
      new TimeInterval({
        start: startJulian,
        stop: JulianDate.addSeconds(startJulian, 60 * 60, new JulianDate()),
      }),
      8,
      Color.RED,
      new Color(0.55, 0.55, 0.55, 0.25)
    );

    timeline.addTrack(
      new TimeInterval({
        start: JulianDate.addSeconds(endJulian, -60 * 60, new JulianDate()),
        stop: endJulian,
      }),
      8,
      Color.LIME
    );

    var middle = JulianDate.secondsDifference(endJulian, startJulian) / 4;
    timeline.addTrack(
      new TimeInterval({
        start: JulianDate.addSeconds(startJulian, middle, new JulianDate()),
        stop: JulianDate.addSeconds(startJulian, middle * 3, new JulianDate()),
      }),
      8,
      Color.DEEPSKYBLUE,
      new Color(0.55, 0.55, 0.55, 0.25)
    );

    var clockViewModel = new ClockViewModel(clock);
    animationViewModel = new AnimationViewModel(clockViewModel);
    animation = new Animation(dojo.byId("animationWidget"), animationViewModel);

    function tick() {
      var time = clock.tick();
      updateScrubTime(time);
      requestAnimationFrame(tick);
    }
    tick();
  }

  // Adjust start/end dates in reaction to any calendar/time clicks
  //
  function newDatesSelected() {
    var startJulian, endJulian;

    if (startDatePart && startTimePart) {
      startJulian = JulianDate.fromIso8601(startDatePart + startTimePart + "Z"); // + 'Z' for UTC
    }
    if (endDatePart && endTimePart) {
      endJulian = JulianDate.fromIso8601(endDatePart + endTimePart + "Z");
    }

    if (startJulian && endJulian) {
      if (JulianDate.secondsDifference(endJulian, startJulian) < 0.1) {
        endBeforeStart.style.display = "block";
        containerElement.style.visibility = "hidden";
      } else {
        endBeforeStart.style.display = "none";
        containerElement.style.visibility = "visible";
        if (!timeline) {
          makeTimeline(startJulian, startJulian, endJulian);
        }
        clock.startTime = startJulian;
        clock.stopTime = endJulian;
        timeline.zoomTo(startJulian, endJulian);
      }
    }
  }

  // React to calendar date clicks
  //
  function newStartDateSelected(newDate) {
    startDatePart = dojo.date.stamp.toISOString(newDate, {
      selector: "date",
    });
    newDatesSelected();
  }
  function newEndDateSelected(newDate) {
    endDatePart = dojo.date.stamp.toISOString(newDate, {
      selector: "date",
    });
    newDatesSelected();
  }

  // React to time-of-day selectors
  //
  function getTimePart(newTime) {
    var h = newTime.getHours().toString();
    h = h.length < 2 ? "0" + h : h;
    var m = newTime.getMinutes().toString();
    m = m.length < 2 ? "0" + m : m;
    var s = newTime.getSeconds().toString();
    s = s.length < 2 ? "0" + s : s;
    return "T" + h + ":" + m + ":" + s;
  }
  function newStartTimeSelected(newTime) {
    startTimePart = getTimePart(newTime);
    newDatesSelected();
  }
  function newEndTimeSelected(newTime) {
    endTimePart = getTimePart(newTime);
    newDatesSelected();
  }

  // React to theme changes
  //
  function setThemeLighter() {
    document.body.className = "claro cesium-lighter";
    dijit.byId("themeSelector").set("label", "Theme: Lighter");
    animation.applyThemeChanges();
  }
  function setThemeDarker() {
    document.body.className = "claro";
    dijit.byId("themeSelector").set("label", "Theme: Darker");
    animation.applyThemeChanges();
  }
  function cycleTheme() {
    if (document.body.className === "claro") {
      setThemeLighter();
    } else {
      setThemeDarker();
    }
  }

  window.addEventListener(
    "resize",
    function () {
      timeline.resize();
      animation.resize();
    },
    false
  );

  dojo.ready(function () {
    endBeforeStart = document.getElementById("endBeforeStart");
    containerElement = document.getElementById("timelineAndAnimation");
    dojo.connect(dijit.byId("startCal"), "onChange", newStartDateSelected);
    dojo.connect(dijit.byId("endCal"), "onChange", newEndDateSelected);
    dojo.connect(dijit.byId("startTimeSel"), "onChange", newStartTimeSelected);
    dojo.connect(dijit.byId("endTimeSel"), "onChange", newEndTimeSelected);

    dojo.connect(dijit.byId("themeSelector"), "onClick", cycleTheme);
    dojo.connect(dijit.byId("themeLighter"), "onClick", setThemeLighter);
    dojo.connect(dijit.byId("themeDarker"), "onClick", setThemeDarker);

    dijit.byId("startTimeSel").set("value", "T00:00:00");
    dijit.byId("endTimeSel").set("value", "T24:00:00");

    var today = JulianDate.now();
    var tomorrow = JulianDate.addDays(today, 1, new JulianDate());
    dijit.byId("startCal").set("value", JulianDate.toDate(today));
    dijit.byId("endCal").set("value", JulianDate.toDate(tomorrow));
  });
});
