/*jslint browser: true, onevar: true, plusplus: true, eqeqeq: true, bitwise: true, forin: true  */
/*global window, crossPlatform */

// The moonPhase namespace
var moonPhase = window.moonPhase || {};

// Declare module-level variables
moonPhase.nextLast = null;
moonPhase.timeout  = null;
moonPhase.elements = {
    'main':        null,
    'config_icon': null,
    'moon':        null,
    'last':        null,
    'next':        null,
    'credit':      null,
    'config':      null,
    'size':        null,
    'text':        null,
    'hemisphere':  null
  };
moonPhase.prefs = {
  'text':       'auto',
  'size':       'auto',
  'hemisphere': 'north'
};

// Stub to be overridden in platforms with a generic content proxy
moonPhase.proxify = moonPhase.proxify || function (url) {return url;};

//init: Initialize the gadget
moonPhase.init = function () {
  var id, name;

  // Attach links to HTML elements 
  for (id in moonPhase.elements) {
    moonPhase.elements[id] = document.getElementById(id);
  }

  // Create preference objects
  for (name in moonPhase.prefs) {
    moonPhase.prefs[name] = 
      new crossPlatform.Storage(name, moonPhase.prefs[name]);
  }

  // Set the wrench icon for the config button 
  moonPhase.elements.config_icon.style.backgroundImage = 
    'url(' + moonPhase.proxify('http://daylightmap.com/moon/wrench_16.png') + ')';

  // Attach (and call) the resize handler to load content
  crossPlatform.addHandler(window, 'resize', moonPhase.load);
  moonPhase.load();

//  _IG_Analytics('UA-1556555-7', '/moon/' + platform + '/test');
};
crossPlatform.addHandler(window, 'load', moonPhase.init);

//load: Load the visible content appropriate for the current size of the gadget
moonPhase.load = function () {
  var width, showText, size, hemisphere, imgSrc, now;

  // Get the screen width
  width = crossPlatform.getWidth(window);

  if (moonPhase.prefs.text.get() === 'auto') {
    showText = (width > 220);
  } else {
    showText = (moonPhase.prefs.text.get() === 'yes');
  }

  if (showText) {
    // Show the ancillary text
    moonPhase.elements.last.style.display = 'inline';
    moonPhase.elements.next.style.display = 'inline';

    if (!moonPhase.nextLast ||
        (Number(new Date()) > moonPhase.nextLast.next.when)) { 
      // Retrieve the next/last data
      crossPlatform.fetchXML('http://daylightmap.com/moon/next_last.xml.php', 
          moonPhase.receiveNextLast);
    } else {
      // No retrieval necessary, just show it
      moonPhase.showText();
    }
  } else {
    // Hide the ancillary text
    moonPhase.elements.last.style.display = 'none';
    moonPhase.elements.next.style.display = 'none';
  }

  if ((moonPhase.prefs.size.get() === 'small') ||
      ((moonPhase.prefs.size.get() === 'auto') &&
       (width < 180))) {
    size = 'small';
  } else if (width < 800) {
    size = 'medium';
  } else {
    size = 'large';
  }

  hemisphere = moonPhase.prefs.hemisphere.get();

  if (size === 'large') {
    // Large display (for full-sized monitors) 
    imgSrc = 'luna_' + hemisphere + '_large.jpg';
    document.body.style.overflow = 'auto';
    moonPhase.elements.moon.height = 625;
    moonPhase.elements.moon.width  = 625;
  } else {
    // Ordinary gadget-sized siaplay
    imgSrc = 'luna_' + hemisphere + '_small.jpg';
    document.body.style.overflow = '';
  
    if (size === 'small') {
      // Small display
      moonPhase.elements.moon.height = 88;
      moonPhase.elements.moon.width  = 88;
    } else {
      // Medium-sized display
      moonPhase.elements.moon.height = 176;
      moonPhase.elements.moon.width  = 176;
    }
  }
  
  // Add a cache-control parameter to ensure the hourly moon image is fresh
  now = new Date();
  imgSrc += '?cache=' + now.getUTCMonth() + now.getUTCDate() + now.getUTCHours();

  // Set the source for the main moon image
  moonPhase.elements.moon.src = 
    moonPhase.proxify('http://daylightmap.com/moon/images/' + imgSrc);

  crossPlatform.adjustSize();
};

// receiveNextLast: Callback for the next/last XML retrieval
moonPhase.receiveNextLast = function (responseXML) {
  var nodes;
  if (!responseXML) {
    // Error retrieving the data - try again, using exponential back-off with jitter
    moonPhase.delay = moonPhase.delay || 5 * 1000;
    // Give up after 4 failures.
    if (moonPhase.delay <= 40 * 1000) {
      moonPhase.delay *= 2;
      window.setTimeout(moonPhase.load, moonPhase.delay);
    }
  } else {
    // Cache the retrieved data into a JS variable and show it on screen 
    nodes = responseXML.getElementsByTagName('phase');
    try {
      moonPhase.nextLast = {
        'last': {'type': crossPlatform.escapeHTML(nodes[0].getAttribute('type')),
                 'when': crossPlatform.nodeValue(nodes[0])},
        'next': {'type': crossPlatform.escapeHTML(nodes[1].getAttribute('type')),
                 'when': crossPlatform.nodeValue(nodes[1])}
      };
    } catch (e) {
      moonPhase.nextLast = null;
    }
    moonPhase.showText();
  }
};

// showText: Extract the next/last data from the local cache to the visible HTML 
moonPhase.showText = function () {
  if (!!moonPhase.nextLast) {
    // Cache has been filled - go ahead!
    moonPhase.elements.last.innerHTML = moonPhase.nextLast.last.type + ' moon ' + 
      moonPhase.timeDelta(moonPhase.nextLast.last.when) + ' ago';
    moonPhase.elements.next.innerHTML = moonPhase.nextLast.next.type + ' moon in ' +
      moonPhase.timeDelta(moonPhase.nextLast.next.when);

    // Refresh the text display in 1 hour
    if (!!moonPhase.timeout) {
      window.clearTimeout(moonPhase.timeout);
    }
    moonPhase.timeout = window.setTimeout(moonPhase.load, 60 * 60 * 1000);
  }
};

// timeDelta: Generate a human-readable string showing the difference between the 
//            current time and the given JS Date object, as in "3 days, 22 hours" 
moonPhase.timeDelta = function (date)
{
  var days = Math.abs(date - Number(new Date())) / (24 * 60 * 60 * 1000), 
      hours = Math.round((days - Math.floor(days)) * 24), 
      result = '';

  if (Math.floor(hours) === 24) {
    days += 1;
    hours = 0;
  }

  if (days >= 1) {
    result = result + Math.floor(days) + '&nbsp;day';
    if (days >= 2) {
      result = result + 's';
    }
    result = result + ', ';
  }

  result = result + Math.floor(hours) + '&nbsp;hour';
  if (hours !== 1) {
    result = result + 's';
  }

  return result;
};

// saveConfig: Save settings from the config panel to their preferences objects
moonPhase.saveConfig = function () {
  var name, selector;

  try {
    for (name in moonPhase.prefs) {
      selector = moonPhase.elements[name]; 
      moonPhase.prefs[name].set(selector.options[selector.selectedIndex].value);
    }

    moonPhase.load();
  } catch (e) {
    alert('Unable to save settings: ' + e.message);
    if (!!window.console && !!console.log) {
      console.log(e.message);
    }
  }
  moonPhase.hideConfig();
};

// loadConfig: Load settings into the config pane
moonPhase.loadConfig = function () {
  var name, value, selector, s;

  for (name in moonPhase.prefs) {
    value = moonPhase.prefs[name].get();
    selector = moonPhase.elements[name];
    for (s = 0; s < selector.length; s += 1) {
      selector.options[s].selected = (selector.options[s].value === value);
    }
  }
};

// showConfig: Display the configuration pane
moonPhase.showConfig = function () {
  moonPhase.loadConfig();
  moonPhase.elements.main.style.display   = 'none';
  moonPhase.elements.config.style.display = 'block';
  crossPlatform.adjustSize();
};

// hideConfig: Switch display from the configuration pane back to the default
moonPhase.hideConfig = function () {
  moonPhase.elements.config.style.display = 'none';
  moonPhase.elements.main.style.display   = 'block';
  crossPlatform.adjustSize();
};

