/**
 * metrics client
 * By Joe Turgeon [http://arithmetric.com]
 * 2/17/2010
 */

var metrics = function () {
  // Class variables
  var curdate, curymd, curmjd, indexMin, indexMax,
    layout, layoutRows, layoutCols,
    width, height;

  // Main application initialization
  function go() {
    // check application components
    if (!metricsData || !metricsDate || !metricsDateSelector || !metricsSetSelector) {
      alert('Cannot load: Missing required application components. Please try reloading this page to continue.');
      return;
    }
    var cvstest = $('<canvas></canvas>');
    if (!cvstest.length) {
      $('#messages').text('metrics requires a web browser that supports the new canvas element from HTML 5. Please try Mozilla Firefox or Google Chrome.');
    }
    else if (!cvstest.get(0).getContext('2d') || !cvstest.get(0).getContext('2d').fillText) {
      $('#messages').text('This web browser does not fully support the new canvas element from HTML 5 (drawing text is not supported). Graph labels will not be displayed. Please try Mozilla Firefox 3.5 or Google Chrome.');
    }

    // define current date in YMD and MJD format
    curdate = new Date();
    var y = curdate.getFullYear();
    var m = curdate.getMonth() + 1;
    var d = curdate.getDate();
    curymd = y + '/' + m + '/' + d;
    curmjd = metricsDate.ymd_to_jd(y, m, d);
    indexMin = curmjd - 365;
    indexMax = curmjd;

    // load data set definitions
    metricsData.loadDataSets();

    // set up the initial layout
    setupLayout();

    // set up workspace event handlers
    startEvents();

    // add an empty graph
    newGraph([]);

    // ready
    $('#messages').text('Ready');
  }

  function startEvents() {
    $(window).resize(handleResize);
    $(document).keydown(handleKey);
    $('a.popup').click(function (e) {var url = $(this).attr('href');if (url && url.length) {window.open(url); e.preventDefault();}});
  }

  function handleResize(e) {
    resizeCanvas();
  }

  function handleKey(e) {
    var handled = false;
    var keycode = (e.which > 0) ? e.which : e.keyCode;
    if (metricsDateSelector.hasFocus()) {
      if (!e.shiftKey && keycode >= 65 && keycode <= 90) {
        keycode += 32;
      }
      handled = metricsDateSelector.input(keycode);
    }
    else if (metricsSetSelector.hasFocus()) {
      if (!e.shiftKey && keycode >= 65 && keycode <= 90) {
        keycode += 32;
      }
      handled = metricsSetSelector.input(keycode);
    }
    else {
      switch (keycode) {
        case 27: // escape
          hideInfo();
          handled = true;
          break;
        case 38: // up arrow
          handled = true;
          break;
        case 40: // down arrow
          handled = true;
          break;
        case 37: // left arrow
          if (!e.shiftKey) {
            indexMin -= 90;
          }
          else if (e.shiftKey && (indexMax - 90) > indexMin) {
            indexMax -= 90;
          }
          updateGraphs();
          handled = true;
          break;
        case 39: // right arrow
          if (!e.shiftKey && (indexMin + 90) < indexMax) {
            indexMin += 90;
          }
          else if (e.shiftKey && (indexMax + 90) <= curmjd) {
            indexMax += 90;
          }
          updateGraphs();
          handled = true;
          break;
        case 65: // A
          metricsSetSelector.activate(addGraph);
          handled = true;
          break;
        case 78: // N
          metricsSetSelector.activate(newGraph);
          handled = true;
          break;
        case 68: // D
          metricsDateSelector.activate(setRange, null, indexMin, indexMax);
          handled = true;
          break;
        case 72: // H
          showHelp();
          handled = true;
          break;
        default:
//          $('#messages').text('key press: ' + String.fromCharCode(keycode) + ' ' + keycode);
          break;
      }
    }
    if (handled) {
      e.preventDefault();
    }
  }

  function setupLayout() {
    // initalize layout variables
    layout = [];
    layoutRows = 0;
    layoutCols = 0;

    // refresh dimensions and update layout
    resizeCanvas();
  }

  function resizeCanvas() {
    width = Math.floor($(window).width() - (2 * $('#main').offset().left)) - 2;
    height = Math.floor($(window).height() - $('#main').offset().top) - 6;
    updateLayout();
  }

  function updateLayout() {
    if (layoutCols && layoutRows) {
      var itemWidth = Math.floor(width / layoutCols);
      var itemHeight = Math.floor(height / layoutRows);
      var items = layout.length;
      for (var i = 0; i < items; i++) {
        layout[i].graph.width = itemWidth;
        layout[i].graph.height = itemHeight;
      }
      updateGraphs();
    }
  }

  function updateGraphs() {
    if (layoutCols && layoutRows) {
      var items = layout.length;
      for (var i = 0; i < items; i++) {
        layout[i].graph.indexMin = indexMin;
        layout[i].graph.indexMax = indexMax;
        layout[i].graph.update();
      }
    }
  }

  function addGraph(setName) {
    if (!layout.length) {
      newGraph(setName);
      return;
    }
    var children = metricsData.getDataSetChildren(setName);
//TODO: select which graph to add to
    if (children.length) {
      layout[0].graph.setNames = layout[0].graph.setNames.concat(children);
    }
    else {
      layout[0].graph.setNames.push(setName);
    }
    updateLayout();
  }

  function newGraph(setName) {
    if (layout.length == 1 && layout[0] && layout[0].graph && !layout[0].graph.setNames.length) {
      addGraph(setName);
      return;
    }
    var children = metricsData.getDataSetChildren(setName);
    if (children.length) {
      setName = children;
    }
    var el = new MetricsUIGraph(setName, indexMin, indexMax, width, height);
    $('#main').append(el.getElement());
    var graph = {row: layoutRows, col: 0, graph: el};
    layout.push(graph);
    layoutRows++;
    layoutCols = 1;
    updateLayout();
  }

  function checkGraphs() {
    var changed = false;
    var active = [];
    var num = layout.length;
    for (var i = 0; i < num; i++) {
      if (layout[i].graph && layout[i].graph.setNames && layout[i].graph.setNames.length) {
        active.push(layout[i]);
      }
      else {
        if (layout[i].graph && layout[i].graph.element) {
          $(layout[i].graph.element).remove();
        }
        changed = true;
      }
    }
    if (changed) {
      layout = active;
      layoutRows = layout.length;
      if (layout.length) {
        updateLayout();
      }
      else {
        newGraph([]);
      }
    }
  }

  function setRange(startmjd, endmjd) {
    indexMin = startmjd;
    indexMax = endmjd;
    updateGraphs();
  }

  function showAbout() {
    $('#changelog').hide();
    $('#help').hide();
    $('#about').toggle();
  }

  function showChangelog() {
    $('#about').hide();
    $('#help').hide();
    $('#changelog').toggle();
  }

  function showHelp() {
    $('#changelog').hide();
    $('#about').hide();
    $('#help').toggle();
  }

  function hideInfo() {
    $('#about').hide();
    $('#changelog').hide();
    $('#help').hide();
  }

  // Define public methods and properties
  return {
    about: showAbout,
    addGraph: addGraph,
    newGraph: newGraph,
    checkGraphs: checkGraphs,
    changelog: showChangelog,
    go: go,
    help: showHelp,
    hideInfo: hideInfo,
    setRange: setRange
  };
}();

$(document).ready(metrics.go);
