dc.ui.TimelineDialog = dc.ui.Dialog.extend({

  GRAPH_OPTIONS : {
    xaxis     : {mode : 'time', minTickSize: [1, "day"]},
    yaxis     : {ticks: [], min: -0.5},
    selection : {mode : 'x', color: '#09f'},
    legend    : {show : false},
    series    : {lines : {show : false}, points : {show : true, radius: 4, fill: true, fillColor: 'rgba(255, 255, 235, 0.7)'}},
    grid      : {backgroundColor: '#fff', tickColor: '#ddd', borderWidth: 0, hoverable : true, clickable : true}
  },

  ROW_HEIGHT : 50,
  MIN_HEIGHT : 100,

  DATE_FORMAT : "%b %d, %y",

  POINT_COLOR : '#555',

  id : 'timeline_dialog',

  events : {
    'click .zoom_out':              '_zoomOut',
    'click .ok':                    'confirm',
    'plothover .timeline_plot':     '_showTooltop',
    'plotselected .timeline_plot':  '_zoomIn',
    'plotclick .timeline_plot':     '_openPage'
  },

  constructor : function(documents) {
    this.documents = documents;
    dc.ui.Dialog.call(this, {
      mode        : 'custom',
      title       : this.displayTitle(),
      information : 'Drag a range of dates to zoom in.'
    });
    dc.ui.spinner.show();
    this._loadDates();
  },

  render : function() {
    dc.ui.Dialog.prototype.render.call(this);
    this.$('.custom').html(JST['document/timeline']({docs : this.documents, minHeight : this.MIN_HEIGHT, rowHeight : this.ROW_HEIGHT}));
    this._zoomButton = this.make('span', {'class' : 'minibutton zoom_out dark not_enabled'}, 'Zoom Out');
    this.addControl(this._zoomButton);
    this.center();
    return this;
  },

  displayTitle : function() {
    if (this.documents.length == 1) return 'Timeline for "' + dc.inflector.truncate(this.documents[0].get('title'), 55) + '"';
    return "Timeline for " + this.documents.length + " Documents";
  },

  // Redraw the Flot Plot.
  drawPlot : function() {
    $.plot(this.$('.timeline_plot'), this._data, this._options);
  },

  _loadDates : function() {
    var dates = _.pluck(this.documents, 'id');
    $.getJSON('/documents/dates', {'ids[]' : dates}, _.bind(this._plotDates, this));
  },

  // Chart the dates for the selected documents.
  _plotDates : function(resp) {
    dc.ui.spinner.hide();
    if (resp.dates.length == 0) return this._noDates();
    this.render();
    var color = this.POINT_COLOR;
    var series = {}, styles = {}, ids = this._dateIds = {};
    _.each(this.documents, function(doc, i) {
      ids[doc.id]      = {};
      series[doc.id]   = [];
      styles[doc.id]   = {pos : i, color : color};
    });
    _.each(resp.dates, function(json) {
      var docId         = json.document_id;
      var date          = json.date * 1000;
      ids[docId][date]  = json.id;
      series[docId].push([date, styles[docId].pos]);
    });
    this._data = _.map(series, function(val, key) {
      return {data : val, color : styles[key].color, docId : parseInt(key, 10)};
    });
    this._options = _.clone(this.GRAPH_OPTIONS);
    this._options.xaxis.min   = null;
    this._options.xaxis.max   = null;
    this._options.yaxis.max   = this.documents.length - 0.5;
    this._options.yaxis.ticks = _.map(this.documents, function(doc){
      return [styles[doc.id].pos, dc.inflector.truncate(doc.get('title'), 30)];
    });
    this.drawPlot();
  },

  // Create a tooltip to show a hovered date.
  _showTooltop : function(e, pos, item) {
    this._pos = pos;
    if (this._request) return;
    if (!item) return dc.ui.tooltip.hide();
    var docId = item.series.docId;
    var id    = this._dateIds[docId][item.datapoint[0]];
    var model = EntityDates.get(id);
    if (model) return this._renderTooltip(model);
    this._request = $.getJSON('/documents/dates', {id : id}, _.bind(function(resp) {
      delete this._request;
      if (!resp) return;
      var model   = new dc.model.Entity(resp.date);
      EntityDates.add(model);
      this._renderTooltip(model);
    }, this));
  },

  _renderTooltip : function(date) {
    var title   = dc.inflector.truncate(Documents.get(date.get('document_id')).get('title'), 45);
    var excerpt = date.get('excerpts')[0];
    dc.ui.tooltip.show({
      left  : this._pos.pageX,
      top   : this._pos.pageY,
      title : title,
      text  : '<b>p.' + excerpt.page_number + '</b> ' + dc.inflector.trimExcerpt(excerpt.excerpt)
    });
  },

  // Allow clicking on date ranges to jump to the page containing the date
  // in the document.
  _openPage : function(e, pos, item) {
    if (!item) return;
    var unixTime = item.datapoint[0] / 1000;
    var doc = Documents.get(item.series.docId);
    window.open(doc.viewerUrl() + "?date=" + unixTime);
  },

  // Allow selection of date ranges to zoom in.
  _zoomIn : function(e, ranges) {
    $(this._zoomButton).setMode('is', 'enabled');
    this._options.xaxis.min = ranges.xaxis.from;
    this._options.xaxis.max = ranges.xaxis.to;
    this.drawPlot();
  },

  // Zoom back out to see the entire timeline.
  _zoomOut : function() {
    $(this._zoomButton).setMode('not', 'enabled');
    this._options.xaxis.min = null;
    this._options.xaxis.max = null;
    this.drawPlot();
  },

  // Close, with an error, when no dates are found.
  _noDates : function() {
    var count = this.documents.length;
    this.close();
    var message = "None of the " + count + " documents contained recognizable dates.";
    if (count <= 1) message = "We were unable to recognize any dates for " + '"' + this.documents[0].get('title') + '"';
    dc.ui.Dialog.alert(message);
  }

});