// function includeJavaScriptFile(path) {{{
//
// Creates a JavaScript <script> element and appends it
// to the <head>.
//
function includeJavaScriptFile(path) {
  // Ensure that we have a non-empty string.'
  if ((typeof(path) != 'string') || (!path))
    {return;}

  // Ensure that we can find the <head>.
  var head = jQuery('head');
  if (!head)
    {return;}

  var element   = document.createElement('script');
  element.type  = 'text/javascript';
  element.src   = path;

  head.append(element);

  return true;
} // }}}

// function buildTheDashboard() {{{
//
// Determines which dashboard widgets to build,
// builds them, and adds them to the DOM.
//
function buildTheDashboard() {
  var parsed_widgets = jQuery.parseJSON(json_widgets);

  jQuery.each(parsed_widgets, function(index, widget) {
    if (widget.type == 'number')
      {dashboard.addNumberWidget(widget);}
    else if (widget.type == 'short_messages')
      {dashboard.addShortMessagesWidget(widget);}
    else if (widget.type == 'line_graph')
      {dashboard.addLineGraphWidget(widget);}
  });
} // }}}

function createUpdateTimerFor(widget) { // {{{
  $(this).everyTime(widget.update_interval, widget.name, function() {
    widget.updateData();
  });
} // }}}

// Begin Dashboard class. {{{
var Dashboard = new JS.Class({
  initialize: function(options) { // {{{
    this.basePath             = options.basePath;

    this.numberWidgets        = new Array();
    this.shortMessagesWidgets = new Array();
    this.lineGraphWidgets     = new Array();
  
    this.div                      = jQuery('#dashboard');
    this.numberWidgetsDiv         = this.div.find('.dashboard-numbers');
    this.shortMessagesWidgetsDiv  = this.div.find('.dashboard-short-messages');
    this.lineGraphWidgetsDiv      = this.div.find('.dashboard-line-graphs');
  }, // }}}

  addNumberWidget: function(options) { // {{{
    var widget      = new NumberWidget(options);
    var templateDiv = this.numberWidgetsDiv.find('.widget-template');

    var widgetDiv   = templateDiv.clone(false)
      .removeClass('widget-template')
      .addClass('number-widget')
      .attr('id', widget.divID())
      .appendTo(this.numberWidgetsDiv);

    // Set the new div's title.
    widgetDiv.find('.widget-title').html(widget.title);

    widget.setDataDivTo(widgetDiv.find('.widget-data'));
    widget.updateData();

    createUpdateTimerFor(widget);

    this.numberWidgets.push(widget);

    widgetDiv.show();
  }, // }}}

  addShortMessagesWidget: function(options) { // {{{
    var widget      = new ShortMessagesWidget(options);
    var templateDiv = this.shortMessagesWidgetsDiv.find('.widget-template');

    var widgetDiv   = templateDiv.clone(false)
      .removeClass('widget-template')
      .addClass('short-messages-widget')
      .attr('id', widget.divID())
      .appendTo(this.shortMessagesWidgetsDiv);

    // Set the new div's title.
    widgetDiv.find('.widget-title').html(widget.title);

    widget.setDataDivTo(widgetDiv.find('.widget-data'));
    widget.updateData();

    createUpdateTimerFor(widget);

    this.shortMessagesWidgets.push(widget);

    widgetDiv.show();
  }, // }}}

  addLineGraphWidget: function(options) { // {{{
    var widget      = new LineGraphWidget(options);
    var templateDiv = this.lineGraphWidgetsDiv.find('.widget-template');

    var widgetDiv   = templateDiv.clone(false)
      .removeClass('widget-template')
      .addClass('line-graph-widget')
      .attr('id', widget.divID())
      .appendTo(this.lineGraphWidgetsDiv);

    // Set the new div's title.
    widgetDiv.find('.widget-title').html(widget.title);

    var dataDiv = widgetDiv.find('.widget-data')
      .attr('id', widget.divID() + '-data');

    widget.setDataDivTo(dataDiv);

    widget.updateData();

    // I don't know why, but setting these properties when dataDiv
    // is initialized fails to work. They work here, though...
    dataDiv.css('height',  widget.height)
    dataDiv.css('width',   widget.width)

    createUpdateTimerFor(widget);

    this.lineGraphWidgets.push(widget);

    widgetDiv.show();
  } // }}}
});
// End Dashboard class. }}}

// Begin DashboardWidget class. {{{
var DashboardWidget = new JS.Class({
  initialize: function(options) {
    this.type             = options.type;
    this.name             = options.name;
    this.title            = options.title;
    this.update_interval  = options.update_interval;
  },

  dataURL: function() {
    return dashboard.basePath + this.name;
  },

  divID: function() {
    return this.name + '-' + this.type + '-widget';
  },

  setDataDivTo: function(element) {
    this.dataDiv = element;
  }
});
// End DashboardWidget class. }}}

// Begin NumberWidget class. {{{
var NumberWidget = new JS.Class(DashboardWidget, {
  initialize: function(options) {
    options['type'] = 'number';
    this.callSuper(options);
  },

  updateData: function() {
    if (!this.dataDiv)
      {return false;}

    // This is needed so that the dataDiv property is accessible with jQuery.get() .
    var element = this.dataDiv;

    jQuery.get(this.dataURL(), function(data) {
      element.fadeOut(400, function() {
        element.html(data);
        element.fadeIn();
      });
    }, 'text');
  }
});
// End NumberWidget class. }}}

// Begin ShortMessagesWidget class. {{{
var ShortMessagesWidget = new JS.Class(DashboardWidget, {
  initialize: function(options) {
    options['type'] = 'short_messages';
    this.callSuper(options);
    this.maxDataItems = 5;
  },

  firstDataItem: function() {
    return this.dataDiv.find('li.widget-data-item:first');
  },

  dataItemsCount: function() {
    return this.dataDiv.find('li.widget-data-item').length;
  },

  createDataItem: function() {
    return this.dataDiv.find('li.widget-data-template')
      .clone(false)
      .removeClass('widget-data-template')
      .addClass('widget-data-item');
  },

  updateData: function() {
    if (!this.dataDiv)
      {return false;}

    var new_data  = '';
    var new_li    = this.createDataItem();

    // We use ajax() instead of get() because the "async" option must
    // be false. If it isn't, we're unable to determine if data was
    // obtained.
    var get_result = jQuery.ajax({
      url:      this.dataURL(),
      type:     'GET',
      async:    false,
      cache:    false,
      dataType: 'text',
      timeout:  this.updateInterval,
      success:  function(data) {
        new_li.html(data);
        new_data = data;
      }
    });

    // If no data was obtained, return. Otherwise, an empty list item
    // will be shown.
    if (new_data == '')
      {return false;}

    new_li.appendTo(this.dataDiv.find('ul'));

    // Hide the first list item if we've reached the maximum number of
    // list items to show in this widget.
    if (this.dataItemsCount() > this.maxDataItems) {
      var firstDataItem = this.firstDataItem();

      firstDataItem.slideUp(400, function() {
        firstDataItem.remove();
      });
    }

    new_li.slideDown();
  }
});
// End ShortMessagesWidget class. }}}

// Begin LineGraphWidget class. {{{
var LineGraphWidget = new JS.Class(DashboardWidget, {
  initialize: function(options) {
    this.height         = options.height;
    this.width          = options.width;
    this.seriesColours  = options.line_colours;
    this.x_axis         = options.x_axis;

    options.type  = 'line_graph';
    this.callSuper(options);
  },

  updateData: function() {
    if (!this.graph)
      {this.createGraph();}

    // This is needed so that the dataDiv property is accessible with jQuery.get() .
    var graph = this.graph;

    jQuery.get(this.dataURL(), function(data) {
      graph.series[0].data = data;
      graph.replot({resetAxes: true});
    }, 'json');
  },

  createGraph: function() {
    includeJavaScriptFile('/javascripts/jqplot-0.9.7/plugins/jqplot.dateAxisRenderer.min.js');

    var x_axis_format = {};
    if (this.x_axis === 'dates') {
      var x_axis_format = {
        renderer:     jQuery.jqplot.DateAxisRenderer,
        tickOptions:  {formatString: '%Y-%m-%d'}
      }
    }

    this.graph = jQuery.jqplot(this.dataDiv.attr('id'), [ [] ], {
      title:        this.title,
      seriesColors: this.seriesColours,
      axes:         {
                      xaxis: x_axis_format
                    }
    });
  }
});
// End LineGraphWidget class. }}}