import moment from 'moment';
import { event } from 'd3';
import { StartEndDuration } from './util.js';
import Pikaday from 'pikaday';
import { insertCSS } from './plotutil.js';

/*
 * Philip Crotwell
 * University of South Carolina, 2019
 * http://www.seis.sc.edu
 */
/**
 * Hour and Minute chooser using sliders.
 */

class HourMinChooser {
  // d3 not yet in flow-typed :(
  // d3 not yet in flow-typed :(
  // d3 not yet in flow-typed :(
  // d3 not yet in flow-typed :(
  // d3 not yet in flow-typed :(
  // d3 not yet in flow-typed :(
  // d3 not yet in flow-typed :(
  constructor(div, time, updateCallback) {
    let mythis = this;
    this.div = div;
    this.time = time;
    this.updateCallback = updateCallback;
    this.hourMinRegEx = /^([0-1]?[0-9]):([0-5]?[0-9])$/;

    this.myOnClick = function (e) {
      // click document outside popup closes popup
      // not sure this if matters???
      if (e.target !== mythis.hourMinField && e.target !== mythis.popupDiv) {
        mythis.hide();
      }
    };

    this.hourMinField = this.div.append("input").classed("pikatime", true).attr("value", this.time.format('HH:mm')).attr("type", "text").on("click", function () {
      mythis.showHide(); // don't propagate click up to document

      event.stopPropagation();
    }).on("change", function () {
      let match = mythis.hourMinRegEx.exec(mythis.hourMinField.property("value"));

      if (match) {
        mythis.hourMinField.style("background-color", null);
        let h = match[1];
        let m = match[2];
        mythis.time.hours(h);
        mythis.time.minutes(m);
        mythis.popupDiv.style("visibility", "hidden");
        mythis.timeModified();
      } else {
        mythis.hourMinField.property("value", mythis.time.format('HH:mm'));
      }
    });
    this.div.append("span").text("UTC");
    this.popupDiv = this.div.append("div").classed("hourminpopup", true).style("position", "absolute").style("visibility", "hidden").on("click", function () {
      // don't propagate click up to document
      event.stopPropagation();
    });
    this.hourDiv = this.popupDiv.append("div").classed("hour", true);
    this.hourSlider = this.hourDiv.append("label").text("Hour:").append("input");
    this.hourSlider.attr("type", "range").attr("min", "0").attr("max", "23").classed("hourSlider", true).on("input", function () {
      let nHour = +this.value;

      if (mythis.time.hours() !== nHour) {
        mythis.time.hours(nHour);
        mythis.hourSlider.property("value", nHour);
        mythis.timeModified();
      }
    });
    this.hourSlider.attr("value", this.time.hour());
    this.minuteDiv = this.popupDiv.append("div").classed("minute", true);
    this.minuteSlider = this.minuteDiv.append("label").text("Minute:").append("input");
    this.minuteSlider.attr("type", "range").attr("min", "0").attr("max", "59").classed("minuteSlider", true).on("input", function () {
      let nMinute = +this.value;

      if (mythis.time.minutes() !== nMinute) {
        mythis.time.minutes(nMinute);
        mythis.minuteSlider.property("value", nMinute);
        mythis.timeModified();
      }
    });
    this.minuteSlider.attr("value", time.minute());
  }
  /**
   * Updates the time without triggering the callback function.
   * @param  newTime new time to update sliders
   */


  updateTime(newTime) {
    this.time = newTime;
    this.hourMinField.property("value", this.time.format('HH:mm'));
    this.hourSlider.property("value", this.time.hour());
    this.minuteSlider.property("value", this.time.minute());
  }
  /**
   * Updates the sliders based on this.time and triggers the callback function.
   */


  timeModified() {
    this.hourSlider.property("value", this.time.hour());
    this.minuteSlider.property("value", this.time.minute());
    this.hourMinField.property("value", this.time.format('HH:mm'));
    this.updateCallback(this.time);
  }
  /**
   * Shows or hides the popup based on current visibility style
   */


  showHide() {
    if (this.popupDiv.style("visibility") === "hidden") {
      this.popupDiv.style("visibility", "visible").classed("is-bound", true);

      this._adjustPopupPosition();

      window.document.addEventListener("click", this.myOnClick, false);
    } else {
      this.popupDiv.style("visibility", "hidden");
      window.document.removeEventListener("click", this.myOnClick);
    }
  }
  /**
   * Hides the popup with sliders.
   */


  hide() {
    this.popupDiv.style("visibility", "hidden").classed("is-bound", false);
    window.document.removeEventListener("click", this.myOnClick);
  }
  /** @private */


  _adjustPopupPosition() {
    let field = this.hourMinField.node();
    let width = this.hourMinField.offsetWidth;
    let height = this.hourMinField.offsetHeight;
    let viewportWidth = window.innerWidth;
    let viewportHeight = window.innerHeight;
    let scrollTop = window.pageYOffset;
    let left = field.offsetLeft;
    let top = field.offsetTop + field.offsetHeight;

    while (field = field.offsetParent) {
      left += field.offsetLeft;
      top += field.offsetTop;
    } // default position is bottom & left


    if (left + width > viewportWidth) {
      left = left - width + field.offsetWidth;
    }

    if (top + height > viewportHeight + scrollTop) {
      top = top - height - field.offsetHeight;
    }

    this.popupDiv.style("left", left + 'px');
    this.popupDiv.style("top", top + 'px');
  }

}
/**
 * Date and Time chooser using pikaday for the date and the above
 * HourMinChooser for the hour and minute of time.
 */

class DateTimeChooser {
  // d3 not yet in flow-typed :(
  constructor(div, label, initialTime, updateCallback) {
    this.div = div;
    this.label = label;
    this.time = moment.utc(initialTime);
    this.time.second(0).millisecond(0); // only hour and min?

    this.updateCallback = updateCallback;
    this.dateField = div.append("label").text(this.label).append("input").classed("pikaday", true).attr("value", this.time.toISOString()).attr("type", "text").on("click", function () {
      if (mythis.picker.isVisible()) {
        mythis.picker.hide();
      }
    });
    let mythis = this;
    this.picker = new Pikaday({
      field: this.dateField.node(),
      //  trigger: inputField.node(),
      format: "YYYY-MM-DD",
      onSelect: function onSelect() {
        let pikaValue = this.getMoment();
        let origTime = moment.utc(mythis.time);

        if (origTime.year() !== pikaValue.year() || origTime.dayOfYear() !== pikaValue.dayOfYear()) {
          mythis.time.year(pikaValue.year());
          mythis.time.dayOfYear(pikaValue.dayOfYear());
          mythis.timeModified();
        }
      }
    });

    this._internalSetTime(this.time);

    this.hourMin = new HourMinChooser(div, this.time, function (time) {
      mythis._internalSetTime(time);

      mythis.timeModified();
    });
  }
  /**
   * Updates the time without triggering the callback function.
   * @param  newTime new time to update sliders
   */


  updateTime(newTime) {
    this._internalSetTime(newTime);

    this.hourMin.updateTime(newTime);
  }
  /**
   * triggers the callback function.
   */


  timeModified() {
    this.updateCallback(this.time);
  }

  getTime() {
    return this.time;
  }
  /** @private */


  _internalSetTime(newTime) {
    this.time = newTime;
    this.dateField.attr("value", this.time.toISOString()); // re-moment to avoid utc issue in

    this.picker.setMoment(moment([this.time.year(), this.time.month(), this.time.date()]));
  }

}
/**
 * Combination of two DateTimeChoosers to specify a start and end time.
 */

class TimeRangeChooser {
  constructor(div, callbackFunction) {
    this.callbackFunction = callbackFunction;
    let endTime = moment.utc();
    this.duration = 300;
    let startTime = moment.utc(endTime).subtract(this.duration, 'second');
    this.div = div;
    this.div.classed("timeRangeChooser", true);
    let mythis = this;
    let startDiv = div.append("div").classed("start", true);
    this.startChooser = new DateTimeChooser(startDiv, "Start:", startTime, function (startTime) {
      mythis.endChooser.updateTime(moment.utc(startTime).add(mythis.duration, 'seconds'));
      mythis.callbackFunction(mythis.getTimeRange());
    });
    let durationDiv = div.append("div").classed("duration", true);
    durationDiv.append("label").text("Duration:").append("input").classed("pikatime", true).attr("value", this.duration).attr("type", "text").on("input", function () {
      let nDur = +Number.parseInt(this.value);
      mythis.duration = nDur;
      mythis.startChooser.updateTime(moment.utc(mythis.endChooser.getTime()).subtract(mythis.duration, 'seconds'));
      mythis.callbackFunction(mythis.getTimeRange());
    });
    let endDiv = div.append("div").classed("end", true);
    this.endChooser = new DateTimeChooser(endDiv, "End:", endTime, function (endTime) {
      mythis.startChooser.updateTime(moment.utc(endTime).subtract(mythis.duration, 'seconds'));
      mythis.callbackFunction(mythis.getTimeRange());
    });
  }

  getTimeRange() {
    return new StartEndDuration(this.startChooser.getTime(), this.endChooser.getTime());
  }

}
/**
 * CSS for the parts of HourMin, DateTime and TimeRange choosers
 * that are not using pikaday.
 */

const chooser_css = "\n\ndiv.timeRangeChooser div div.hourminpopup {\n    z-index: 9999;\n    display: block;\n    position: relative;\n    color: #333;\n    background-color: white;\n    border: 1px solid #ccc;\n    border-bottom-color: #bbb;\n    font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n    box-shadow: 0 5px 15px -5px rgba(0,0,0,.5);\n}\n\n\n\n.hourminpopup.is-hidden {\n    display: none;\n}\n.hourminpopup.is-bound {\n    position: absolute;\n    box-shadow: 0 5px 15px -5px rgba(0,0,0,.5);\n    background-color: white;\n}\n\ndiv.hourminpopup div label {\n  display: block;\n  float: right;\n}\ndiv.hourminpopup div {\n    display: block;\n    float: right;\n    clear: both;\n}\n\ndiv.hourminpopup input {\n    width: 150px;\n}\n\ndiv.timeRangeChooser div {\n  margin: 2px;\n}\n\ninput.pikaday {\n  width: 70px;\n}\ninput.pikatime {\n  width: 50px;\n}\n\n";
/**
 * CSS for the pikaday chooser.
 */

const pikaday_css = "\n@charset \"UTF-8\";\n\n/*!\n * Pikaday\n * Copyright \xA9 2014 David Bushell | BSD & MIT license | http://dbushell.com/\n */\n\n.pika-single {\n    z-index: 9999;\n    display: block;\n    position: relative;\n    color: #333;\n    background: #fff;\n    border: 1px solid #ccc;\n    border-bottom-color: #bbb;\n    font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n}\n\n/*\nclear child float (pika-lendar), using the famous micro clearfix hack\nhttp://nicolasgallagher.com/micro-clearfix-hack/\n*/\n.pika-single:before,\n.pika-single:after {\n    content: \" \";\n    display: table;\n}\n.pika-single:after { clear: both }\n\n.pika-single.is-hidden {\n    display: none;\n}\n\n.pika-single.is-bound {\n    position: absolute;\n    box-shadow: 0 5px 15px -5px rgba(0,0,0,.5);\n}\n\n.pika-lendar {\n    float: left;\n    width: 240px;\n    margin: 8px;\n}\n\n.pika-title {\n    position: relative;\n    text-align: center;\n}\n\n.pika-label {\n    display: inline-block;\n    position: relative;\n    z-index: 9999;\n    overflow: hidden;\n    margin: 0;\n    padding: 5px 3px;\n    font-size: 14px;\n    line-height: 20px;\n    font-weight: bold;\n    background-color: #fff;\n}\n.pika-title select {\n    cursor: pointer;\n    position: absolute;\n    z-index: 9998;\n    margin: 0;\n    left: 0;\n    top: 5px;\n    opacity: 0;\n}\n\n.pika-prev,\n.pika-next {\n    display: block;\n    cursor: pointer;\n    position: relative;\n    outline: none;\n    border: 0;\n    padding: 0;\n    width: 20px;\n    height: 30px;\n    /* hide text using text-indent trick, using width value (it's enough) */\n    text-indent: 20px;\n    white-space: nowrap;\n    overflow: hidden;\n    background-color: transparent;\n    background-position: center center;\n    background-repeat: no-repeat;\n    background-size: 75% 75%;\n    opacity: .5;\n}\n\n.pika-prev:hover,\n.pika-next:hover {\n    opacity: 1;\n}\n\n.pika-prev,\n.is-rtl .pika-next {\n    float: left;\n    background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAUklEQVR42u3VMQoAIBADQf8Pgj+OD9hG2CtONJB2ymQkKe0HbwAP0xucDiQWARITIDEBEnMgMQ8S8+AqBIl6kKgHiXqQqAeJepBo/z38J/U0uAHlaBkBl9I4GwAAAABJRU5ErkJggg==');\n}\n\n.pika-next,\n.is-rtl .pika-prev {\n    float: right;\n    background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAU0lEQVR42u3VOwoAMAgE0dwfAnNjU26bYkBCFGwfiL9VVWoO+BJ4Gf3gtsEKKoFBNTCoCAYVwaAiGNQGMUHMkjGbgjk2mIONuXo0nC8XnCf1JXgArVIZAQh5TKYAAAAASUVORK5CYII=');\n}\n\n.pika-prev.is-disabled,\n.pika-next.is-disabled {\n    cursor: default;\n    opacity: .2;\n}\n\n.pika-select {\n    display: inline-block;\n}\n\n.pika-table {\n    width: 100%;\n    border-collapse: collapse;\n    border-spacing: 0;\n    border: 0;\n}\n\n.pika-table th,\n.pika-table td {\n    width: 14.285714285714286%;\n    padding: 0;\n}\n\n.pika-table th {\n    color: #999;\n    font-size: 12px;\n    line-height: 25px;\n    font-weight: bold;\n    text-align: center;\n}\n\n.pika-button {\n    cursor: pointer;\n    display: block;\n    box-sizing: border-box;\n    -moz-box-sizing: border-box;\n    outline: none;\n    border: 0;\n    margin: 0;\n    width: 100%;\n    padding: 5px;\n    color: #666;\n    font-size: 12px;\n    line-height: 15px;\n    text-align: right;\n    background: #f5f5f5;\n}\n\n.pika-week {\n    font-size: 11px;\n    color: #999;\n}\n\n.is-today .pika-button {\n    color: #33aaff;\n    font-weight: bold;\n}\n\n.is-selected .pika-button,\n.has-event .pika-button {\n    color: #fff;\n    font-weight: bold;\n    background: #33aaff;\n    box-shadow: inset 0 1px 3px #178fe5;\n    border-radius: 3px;\n}\n\n.has-event .pika-button {\n    background: #005da9;\n    box-shadow: inset 0 1px 3px #0076c9;\n}\n\n.is-disabled .pika-button,\n.is-inrange .pika-button {\n    background: #D5E9F7;\n}\n\n.is-startrange .pika-button {\n    color: #fff;\n    background: #6CB31D;\n    box-shadow: none;\n    border-radius: 3px;\n}\n\n.is-endrange .pika-button {\n    color: #fff;\n    background: #33aaff;\n    box-shadow: none;\n    border-radius: 3px;\n}\n\n.is-disabled .pika-button {\n    pointer-events: none;\n    cursor: default;\n    color: #999;\n    opacity: .3;\n}\n\n.is-outside-current-month .pika-button {\n    color: #999;\n    opacity: .3;\n}\n\n.is-selection-disabled {\n    pointer-events: none;\n    cursor: default;\n}\n\n.pika-button:hover,\n.pika-row.pick-whole-week:hover .pika-button {\n    color: #fff;\n    background: #ff8000;\n    box-shadow: none;\n    border-radius: 3px;\n}\n\n/* styling for abbr */\n.pika-table abbr {\n    border-bottom: none;\n    cursor: help;\n}\n\n";

if (document) {
  insertCSS(chooser_css);
  insertCSS(pikaday_css);
}

export { DateTimeChooser, HourMinChooser, TimeRangeChooser, chooser_css, pikaday_css };
//# sourceMappingURL=datechooser.js.map
