if (!window.Uladoo) window.Uladoo = {};

Uladoo.chart = function(spec) {
  var dataPoints = spec.dataPoints;
  var chartContainer = spec.chartContainer;
  var aggregationLevel = "day";

  var aggregationScales = {
    "day": 60 * 60 * 24
  }; 

  var graphWindows = {
    "day": 9
  };

  var graphPointRadius = 7;

  var graphWindow = function() {
    return aggregationScales[aggregationLevel] * graphWindows[aggregationLevel] * 1000;
  };

  var aggregateDataPoints = function() {
    var dataBucketsMap = {};
    var dataBucketsList = [];

    $.each(dataPoints, function() {
      var bucket = this[0] - (this[0] % aggregationScales["day"]);
      dataBucketsMap[bucket] == null ? dataBucketsMap[bucket] = this[1] : dataBucketsMap[bucket] += this[1]
    });
    $.each(dataBucketsMap, function(key,value) {
      dataBucketsList.push([parseInt(key,10), value]);
    });
    return $.each(sortDataPoints(dataBucketsList), function() {
      this[0] *= 1000;
    });
  };

  var sortDataPoints = function(dataPoints) {
    return dataPoints.sort(function(a, b) {
      return a[0] - b[0]; 
    }).reverse();
  };

  // initialize xAxisMax to first data point
  var xAxisMax = aggregateDataPoints()[0][0];
  var xAxisMin = function() {
    return xAxisMax - graphWindow();
  }

  var monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
  var dayNames = ["Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"];

  var updateChartLabel = function() {
    var maxDate = new Date(xAxisMax);
    var minDate = new Date(xAxisMin());
    var label = "";
    if (aggregationLevel == "day") {
      if (maxDate.getUTCFullYear() == minDate.getUTCFullYear()) {
        if (maxDate.getUTCMonth() == minDate.getUTCMonth()) {
          label = monthNames[maxDate.getUTCMonth()] + " " + maxDate.getUTCFullYear();
        }
        else {
          label = monthNames[minDate.getUTCMonth()] + "/" + monthNames[maxDate.getUTCMonth()] + " " + maxDate.getUTCFullYear();
        }
      } else {
        label = monthNames[minDate.getUTCMonth()] + " " + minDate.getUTCFullYear() + "/" + 
                monthNames[maxDate.getUTCMonth()] + " " + maxDate.getUTCFullYear();
      }
    }
    $(spec.chartLabel).text(label);
  }

  var that = {
    dataPoints: aggregateDataPoints(),

    draw: function() {
      $.plot($(chartContainer), [this.dataPoints], {
        grid: {
          color: "#888",
          backgroundColor: "#FFF",
          hoverable: true
        },
        points: {
          show: true,
          radius: graphPointRadius
        },
        lines: {show: true},
        yaxis: {
          minTickSize: 1
        },
        xaxis: { 
          max: xAxisMax,
          min: xAxisMin(),
          mode: "time",
          ticks: 9,
          timeformat: "%m/%d"
        }
      }); //end plot 

      // disable forward nav if current graph contains first data point
      if (xAxisMax == this.dataPoints[0][0]) {
        $(spec.forward).addClass("disabled");
      }
      else {
        $(spec.forward).removeClass("disabled");
      }

      // disable backward nav if current graph contains last data point
      if ((xAxisMax - graphWindow()) <= this.dataPoints[this.dataPoints.length-1][0]) {
        $(spec.backward).addClass("disabled");
      }
      else {
        $(spec.backward).removeClass("disabled");
      }

      // set initial chart label
      updateChartLabel(); 

    }// end draw
  };
  
  $(spec.forward).click(function(event) {
    var newMax = xAxisMax + (aggregationScales[aggregationLevel] * 1000)
    if(newMax > that.dataPoints[0][0]) {
      return false;
    } else {
      xAxisMax = newMax;
      that.draw();
      return false;
    }
  });

  $(spec.backward).click(function(event) {
    var newMax = xAxisMax - (aggregationScales[aggregationLevel] * 1000)
    if((newMax - graphWindow()) < that.dataPoints[that.dataPoints.length-1][0]) {
      return false;
    } else {
      xAxisMax = newMax;
      that.draw();
      return false;
    }
  });

  $(spec.ten).click(function(event) {
    if(!$(this).hasClass("disabled")) {
      graphWindows["day"] = 9;
      graphPointRadius = 7;
      $(this).addClass("disabled");
      $(spec.thirty).removeClass("disabled");
      $(spec.sixty).removeClass("disabled");
      that.draw();
    }
    return false;
  });

  $(spec.thirty).click(function(event) {
    if(!$(this).hasClass("disabled")) {
      graphWindows["day"] = 29;
      graphPointRadius = 5;
      $(this).addClass("disabled");
      $(spec.ten).removeClass("disabled");
      $(spec.sixty).removeClass("disabled");
      that.draw();
    }
    return false;
  });
  
  $(spec.sixty).click(function(event) {
    if(!$(this).hasClass("disabled")) {
      graphWindows["day"] = 59;
      graphPointRadius = 4;
      $(this).addClass("disabled");
      $(spec.ten).removeClass("disabled");
      $(spec.thirty).removeClass("disabled");
      that.draw();
    }
    return false;
  });
  
  var showToolTip = function(x, y, contents) {
    $("<div id=\"tooltip\">" + contents + "</div>").css( {
      position: "absolute",
      display: "none",
      top: y + 15,
      left: x + 15,
      border: "1px solid #fdd",
      padding: "2px",
      "background-color": "#FFAEB9",
      opacity: 0.80
    }).appendTo("body").fadeIn(200);
  }  

  var formatToolTipText = function(dataPoint) {
    var d = new Date(dataPoint[0]);
    var text = "";
    if (aggregationLevel == "day") {
      text = dayNames[d.getUTCDay()] + " " + monthNames[d.getUTCMonth()] + " " + d.getUTCDate();
    }
    return text + ", " + dataPoint[1];
  };

  var previousToolTipDataPoint = null;
  $(spec.chartContainer).bind("plothover", function(event, pos, item) {
    if(item) {
      if(previousToolTipDataPoint != item.datapoint) {
        previousToolTipDataPoint = item.datapoint; 
        $("#tooltip").remove();
        showToolTip(item.pageX, item.pageY, formatToolTipText(item.datapoint));
      }
    } else {
      $("#tooltip").remove();
      previousToolTipDataPoint = null; 
    }
  });
  return that;
}
