var display_month;
var today = new Date ();
var month_names = [
  'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
  'September', 'October', 'November', 'December'
];
var day_names = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
var calendar_events = [];
var selected_day = null;

function auto_show_month (date_ref) {
  var url_date = window.location.hash.substr (1);
  if (url_date.match (/^20[01][0-9]-[01][0-9]-[0-3][0-9]$/)) {
    show_month (url_date, true);
  } else {
    show_month (date_ref);
  }
}

function show_month (date_ref, autoload_date) {
  
  document.getElementById ('events_loading').style.visibility = 'visible';
  
  if (date_ref != undefined && date_ref != null) {
    
    var date_parts = date_ref.split ('-');
    display_month = new Date ();
    display_month.setFullYear (date_parts[0]);
    display_month.setMonth (date_parts[1] - 1);
    display_month.setDate (1);
  }
  
  selected_day = null;
  
  var events_table = document.getElementById ('calendar_events');
  
  var i, j, row, col, p, rows, cols, day;
  
  if (events_table.childNodes.length == 0) {
    
    for (i = 0; i < 6; i++) {
      row = document.createElement ('tr');
      
      for (j = 0; j < 7; j++) {
        col = document.createElement ('td');
        col.appendChild (document.createTextNode ('\u00a0'));
        row.appendChild (col);
      }
      
      events_table.appendChild (row);
    }
    
  }
  
  // fill date boxes with actual numbers from month
  var offset = display_month.getDay () - 1;
  if (offset == -1) offset = 6;
  var cell_number = 1;
  var day = 1;
  var max_days = 31;
  
  rows = events_table.childNodes;
  for (i = 0; i < rows.length; i++) {
    row = rows.item (i);
    cols = row.childNodes;
    for (j = 0; j < cols.length; j++) {
      col = cols.item (j);
      col.className = '';
      if (cell_number > offset && day <= max_days) {
        col.innerHTML = day;
        if (day == today.getDate () &&
            display_month.getMonth () == today.getMonth () &&
            display_month.getFullYear () == today.getFullYear ()) {
          col.id = 'calendar_today';
        } else {
          col.removeAttribute ('id');
        }
        day++;
      } else {
        col.innerHTML = '&nbsp;';
      }
      cell_number++;
    }
  }
  
  var month_holder = document.getElementById ('month_name');
  var month_text = month_names[display_month.getMonth ()] + ' ' +
    display_month.getFullYear ();
  month_holder.innerHTML = month_text;
  document.title = document.title.replace (/^[^:]+/, 'Events, ' + month_text);
  
  // AJAX call to get month's events
  if (autoload_date) {
    calendar_handler.set_autoload (date_ref);
  } else {
    calendar_handler.set_autoload (false);
  }
  queue.request (
    'get',
    'ajax/events.php?m=' + display_month.getFullYear () + '-' + str_pad (
      display_month.getMonth () + 1,
      2,
      '0',
      STR_PAD_LEFT
    ),
    calendar_handler
  );
  
}

function next_month () {
  var month = display_month.getMonth () + 1;
  if (month == 12) {
    display_month.setFullYear (display_month.getFullYear () + 1);
    display_month.setMonth (0);
  } else {
    display_month.setMonth (month);
  }
  show_month ();
}

function prev_month () {
  var month = display_month.getMonth () - 1;
  if (month == -1) {
    display_month.setFullYear (display_month.getFullYear () - 1);
    display_month.setMonth (11);
  } else {
    display_month.setMonth (month);
  }
  show_month ();
}

function event_info (date, id, event_title, event_is_vegan, event_description, attendee_lists,
    venue_id, venue_name, venue_is_restaurant) {
  this.id = id;
  this.title = event_title;
  this.description = event_description;
  this.attendee_lists = attendee_lists;
  this.venue_id = venue_id;
  this.venue_name = venue_name;
  this.venue_is_restaurant = venue_is_restaurant;
  this.date = date;
  
  this.display = function (parent_node) {
    
    var heading = document.createElement ('h5');
    
    parent_node.appendChild (heading);
    heading.appendChild (document.createTextNode (this.title));
    
    var venue = document.createElement ('p');
    var venue_intro = document.createElement ('strong');
    venue_intro.appendChild (document.createTextNode ('Venue: '));
    venue.appendChild (venue_intro);
    var venue_a = document.createElement ('a');
    if (this.venue_id != '') {
      venue_a.href = (venue_is_restaurant? '/restaurants/': '/venues/') + this.venue_id;
      venue_a.appendChild (document.createTextNode (this.venue_name));
    } else {
      venue_a.href = 'login_form.php?r=' +
        encodeURIComponent (window.location.pathname + window.location.hash) +
        '#' + this.date.substr (0, 10);
      venue_a.appendChild (document.createTextNode ('please log in for more information'));
    }
    venue.appendChild (venue_a);
    parent_node.appendChild (venue);
    
    var desc = document.createElement ('div');
    desc.className = 'event_description';
    
    desc.innerHTML = this.description;
    
    parent_node.appendChild (desc);
    
    var attendee_intro = document.createElement ('p');
    var attending = this.attendee_lists[1];
    var attendee_names, attendee_id;
    var num_attending;
    if (typeof (attending) == 'object') {
      num_attending = attending.length;
    } else {
      num_attending = attending;
    }
    attendee_intro.innerHTML = '<strong>' + num_attending + ' ' +
      (num_attending == 1? 'person</strong> has': 'people</strong> have') +
      ' said that they <strong>will</strong> attend this event. ';
    if (typeof (attending) == 'object' && attending.length > 0) {
      attendee_intro.innerHTML +=
        '<a href="#" onclick="show_attendees (this); return false;">Who?</a>';
      desc.appendChild (attendee_intro);
      attendee_names = document.createElement ('p');
      attendee_names.style.display = 'none';
      for (attendee_id in attending) {
        if (attendee_id > 0) attendee_names.innerHTML += ', ';
        attendee_names.innerHTML += attending[attendee_id];
      }
      desc.appendChild (attendee_names);
    } else {
      desc.appendChild (attendee_intro);
    }
    
    var attendee_intro = document.createElement ('p');
    var attending = this.attendee_lists[0];
    var num_attending;
    if (typeof (attending) == 'object') {
      num_attending = attending.length;
    } else {
      num_attending = attending;
    }
    attendee_intro.innerHTML = '<strong>' + num_attending + ' ' +
      (num_attending == 1? 'person</strong> has': 'people</strong> have') +
      ' said that they <strong>will not</strong> attend this event. ';
    if (typeof (attending) == 'object' && attending.length > 0) {
      attendee_intro.innerHTML +=
        '<a href="#" onclick="show_attendees (this); return false;">Who?</a>';
      desc.appendChild (attendee_intro);
      attendee_names = document.createElement ('p');
      attendee_names.style.display = 'none';
      for (attendee_id in attending) {
        if (attendee_id > 0) attendee_names.innerHTML += ', ';
        attendee_names.innerHTML += attending[attendee_id];
      }
      desc.appendChild (attendee_names);
    } else {
      desc.appendChild (attendee_intro);
    }
    
    var user_attend = document.createElement ('p');
    user_attend.className = 'confirmation';
    user_attend.innerHTML = 'Will you be attending? &nbsp; ' +
      '<a href="rsvp.php?id=' + this.id + '&amp;r=y">YES</a> &nbsp; <a href="rsvp.php?id=' + this.id +
      '&amp;r=n">NO</a>';
    
    desc.appendChild (user_attend);
    
  }
}

function english_ordinal (num) {
  var str = String (Number (num) + 0);
  
  var ord = 'th';
  if (str.length == 1 || str.charAt (str.length - 2) != '1') {
    switch (str.charAt (str.length - 1)) {
      case '1':
        ord = 'st';
        break;
      case '2':
        ord = 'nd';
        break;
      case '3':
        ord = 'rd';
        break;
      default:
        ord = 'th';
    }
  }
  
  return str + ord;
}


/**
* 
* UNSUSED AND UNTESTED
* 
* Finds the cell in the calendar table of the day specified
**/
function find_day_cell (day_num) {
  var table = document.getElementById ('calendar_events');
  var tds = table.getElementsByTagName ('td');
  var td, i;
  for (i = 0; i < tds.length; i++) {
    td = tds.item (i);
    if (td.childNodes.length > 0 && td.firstChild.data == day_num) {
      return td;
    }
  }
  return null;
}

function show_day (day) {
  var event_id;
  var event_info = document.getElementById ('event_info');
  
  event_info.innerHTML = '';
  
  var is_first_event = true;
  for (event_id in calendar_events[day]) {
    if (is_first_event) {
      var day, month, year;
      var date = new Date ();
      var date_parts = calendar_events[day][event_id].date.split ('-');
      year = Number (date_parts[0]);
      month = date_parts[1] - 1;
      date.setYear (year);
      date.setMonth (month);
      var day_parts = date_parts[2].split (',');
      day = day_parts[0];
      date.setDate (day);
      
      date.output = function () {
        var str = day_names[this.getDay ()] + ', ';
        var day = String (this.getDate ());
        str += english_ordinal (day);
        str += ' ' + month_names[this.getMonth ()];
        
        return str;
      }
      
      var num_events = calendar_events[day].length;
      event_info.innerHTML = '<h4>' + num_events + ' event' + (num_events == 1? '': 's') +
        ' on ' + date.output () + '</h4>';
      
      is_first_event = false;
    }
    calendar_events[day][event_id].display (event_info);
  }
  
}

var http_response_code = new Array ();
http_response_code[404] = 'page not found';

var msie = false;
if (navigator.userAgent.match ('MSIE') !== null) msie = true;

var queue = new Queue ();


// time to wait before polling active requests
var DELAY = 100;
var STR_PAD_LEFT = 0;
var STR_PAD_RIGHT = 1;

var date_days = new Array ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
var date_months = new Array ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');

function str_pad (input, length, padding, side) {
  input = String (input);
  padding = String (padding);
  if (input.length < length) {
    var padding_complete = '';
    var diff = length - input.length;
    for (var i = 0; i < diff; i += padding.length) {
      padding_complete += padding;
    }
    
    if (side == STR_PAD_RIGHT) {
      input = input + padding_complete.substr (0, diff);
    } else {
      input = padding_complete.substr (0, diff) + input;
    }
  }
  return input;
}

// Queue, Request and returned_node_to_dom can be used in later AJAX apps
function Queue () {
  this.request_queue = new Array ();
  this.requester_active = false;
  this.created = true;
  
  this.request = function (method, url, action, further_data, further_data2) {
    
    // add new request
    this.request_queue.push (new Request (method, url, action, further_data, further_data2));
    
    this.activate ();
  }
  
  this.activate = function () {
    if (this.requester_active != true && this.request_queue.length > 0) {
      this.requester_active = true;
      // document.getElementById ('loading').innerHTML = 'Loading...';
      this.request_queue[this.request_queue.length - 1].send ();
      window.setTimeout ('queue.process ();', DELAY);
    } else if (this.request_queue.length == 0) {
      // document.getElementById ('loading').innerHTML = '';
    }
  }
  
  this.process = function () {
    // debug_txt += "Queue.process\n";
    if (this.request_queue.length > 0) {
      
      // process request from FIFO buffer
      var first_request = this.request_queue[0];
      if (first_request.ready_state () == 4) {
        if (first_request.status () == 200) {
          
          // process response
          first_request.process ();
          
        } else if (first_request.status () != 0) {
          trace ('Return status: ' + first_request.status ());
          var ajax_error = 'AJAX call to ' + first_request.url + ' returned server error:\n' +
            first_request.status ();
          if (http_response_code[first_request.status ()]) {
            ajax_error += ' (' + http_response_code[first_request.status ()] + ')';
          }
          alert (ajax_error);
        }
        
        // remove item from queue
        this.request_queue.shift ();
        
        this.requester_active = false;
        this.activate ();
        
      } else {
        
        // keep waiting
        window.setTimeout ('queue.process ();', DELAY);
      }
    }
  }
}

function Request (method, url, action, option, option2) {
  this.url = url;
  this.action = action;
  this.method = method.toUpperCase ();
  this.requester = null;
  this.internet_explorer = false;
  this.node_id = null;
  this.post_data = null;
  
  if (option != null) {
    this.post_data = option;
  }
  
  this.ready_state = function () {
    if (this.requester == null) {
      // trace ("Request.ready_state: -1");
      return -1;
    } else {
      // trace ("Request.ready_state: " + this.requester.readyState);
      return this.requester.readyState;
    }
  }
  
  this.status = function () {
    if (this.requester == null) {
      return -1;
    } else {
      return this.requester.status;
    }
  }
  
  this.send = function () {
    // try Moz/Safari method, then IE
    if (window.XMLHttpRequest) {
      this.requester = new XMLHttpRequest ();
    } else if (this.requester = new ActiveXObject("MSXML2.XMLHTTP.3.0")) {
      this.internet_explorer = true;
    }
    
    if (this.requester != null) {
      trace ('requester.open('+method+', '+url+', true)');
      this.requester.open(method, url, true);
      if (this.method == 'POST') {
        // trace ("this.requester.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');");
        this.requester.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        // this.requester.setRequestHeader("Content-length", post_data.length);
        // this.requester.setRequestHeader("Connection", "close");
      }
      trace ('requester.send('+this.post_data+ ')');
      this.requester.send(this.post_data);
    } else {
      alert ('Your browser does not appear to support AJAX');
    }
  }
  
  this.process = function () {
    if (this.requester != null) {
      // check for errors
      var top_node = false;
      
      // skip any comments, whitespace, etc. and find the first real XML node
      var top_children = this.requester.responseXML.childNodes;
      var curr_child_num = 0;
      var curr_child = null;
      while (!top_node) {
        if (top_children.length <= curr_child_num) {
          break;
        }
        curr_child = top_children.item (curr_child_num);
        if (curr_child.nodeType == 1) {
          top_node = curr_child;
        } else {
          curr_child_num++;
        }
      }
      
      if (!top_node) {
        alert ('Invalid XML returned via AJAX, please contact the web site administrator');
        return false;
      }
      
      if (top_node.nodeName.toLowerCase () == 'error') {
        // alert (top_node.xml);
        alert (top_node.firstChild.data);
      } else {
        
        // New mechanism -- use handler if provided
        if (typeof (this.action) == 'object') {
          this.action.process (top_node);
          return;
        }
        
        switch (this.action) {
          case OVERWRITE_NODE:
            //alert ('XML nodes returned:' + top_node.xml);
            if (this.internet_explorer) {
              var target_node = document.getElementById (this.node_id);
              var dom_node = returned_node_to_dom (top_node, null, null, true);
              var children_xml = '';
              var curr_child;
              for (var i = 0; i < top_node.childNodes.length; i++) {
                curr_child = top_node.childNodes.item (i);
                children_xml += curr_child.xml;
              }
              target_node.parentNode.replaceChild (dom_node, target_node);
              if (this.internet_explorer) {
                // IE forgets the node's id, so we need to forcefully set it
                dom_node.id = this.node_id;
              }
              //alert ("setting innerHTML:\n" + children_xml);
              dom_node.innerHTML = children_xml;
            } else {
              var dom_node = returned_node_to_dom (top_node, null, null, false);
              // alert ('Node ID: ' + this.node_id);
              // alert (view_dom_tree (dom_node));
              var target_node = document.getElementById (this.node_id);
              
              if (!this.internet_explorer) {
                // FF doesn't update select lists properly so that selected options are selected
                update_select_lists (dom_node);
              }
              
              target_node.parentNode.replaceChild (dom_node, target_node);
              if (this.internet_explorer) {
                // IE forgets the node's id, so we need to forcefully set it
                dom_node.id = this.node_id;
              }
              
            }
            break;
          
          default:
            alert ('Invalid AJAX query type: ' + this.action);
        }
      }
    } else {
      alert ('Request.function called on null requester');
    }
  }
}

function view_dom_tree (node, so_far, tab_width) {
  var attr;
  var child;
  
  if (so_far == null) {
    so_far = '';
  }
  
  for (var i = 0; i < tab_width; i++) {
    so_far += ' ';
  }
  
  if (node.nodeType != 3) {
    trace ('Viewing node ' + node.tagName);
    so_far += '<' + node.tagName;
    if (node.attributes) {
      for (var i = 0; i < node.attributes.length; i++) {
        attr = node.attributes.item (i);
        so_far += ' ' + attr.name + '="' + attr.value + '"';
      }
    }
    so_far += ">\n";
    
    for (var i = 0; i < node.childNodes.length; i++) {
      child = node.childNodes.item (i);
      so_far += view_dom_tree (child, '', tab_width + 2);
    }
  } else {
    so_far += node.data;
  }
  
  return so_far;
}

function determine_radio_value (radio_el) {
  
  for (var i in radio_el) {
    if (radio_el[i].checked == true) {
      return radio_el[i].value;
    }
  }
  
  return false;
}

function create_el (name, attrs) {
  
  var node;
  
  if (!msie) {
    node = document.createElement (name);
    if (node && typeof (attrs) == 'object') {
      for (var attr in attrs) {
        node.setAttribute (attr, attrs[attr]);
      }
    }
  } else {
    var attrs_str = '';
    if (typeof (attrs) == 'object') {
      for (var attr in attrs) {
        attrs_str += ' ' + attr + '="' + String (attrs[attr]).replace ('"', '\\"') + '"';
      }
    }
    node = document.createElement ('<' + name + ' ' + attrs_str + '>');
  }
  
  return node;
}

function trace () {
  // nothing to do
  
}

/* ********************************************************************************************************
   ********************************************************************************************************
   ********************************************************************************************************
   ******************************************************************************************************** */

// Handlers for AJAX calls
function CalendarHandler () {
  
  this.autoload = false;
  this.autoload_date = false;
  
  this.process = function (top_node) {
    
    var popup_text = '';
    calendar_events = [];
    
    if (top_node.getAttribute ('month') != 'invalid') {
      var events = top_node.childNodes;
      var event_id;
      
      var cols, col, col_id;
      
      cols = document.getElementById ('calendar_events').getElementsByTagName ('td');
      col_id = 0;
      col = cols.item (col_id);
      
      var curr_event, event_date, event_time, event_day, event_title, event_text, event_obj, is_vegan,
        cats, cat_id, cat, cat_type, attendee_category, attendee, attendees, attendee_lists,
        event_db_id, venue_id, venue_name, venue_is_restaurant;
      
      for (event_id = 0; event_id < events.length; event_id++) {
        
        curr_event = events.item (event_id);
        
        event_date = curr_event.getAttribute ('d').split (' ');
        event_day = event_date[0];
        event_time = event_date[1];
        
        event_title = event_time + ', ' + curr_event.getAttribute ('t');
        is_vegan = (curr_event.getAttribute ('v') == 1? true: false);
        event_text = curr_event.firstChild.data;
        
        attendee_lists = [[], []];
        
        cats = curr_event.getElementsByTagName ('al');
        
        if (cats.length > 0) {
          for (cat_id = 0; cat_id < cats.length; cat_id++) {
            cat = cats.item (cat_id);
            if (cat.getAttribute ('r') == 'y') {
              cat_type = 1;
            } else {
              cat_type = 0;
            }
            attendees = cat.childNodes;
            for (attendee = 0; attendee < attendees.length; attendee++) {
              attendee_lists[cat_type].push (attendees[attendee].firstChild.data);
            }
          }
        } else {
          attendee_lists[0] = Number (curr_event.getAttribute ('an'));
          attendee_lists[1] = Number (curr_event.getAttribute ('ay'));
        }
        
        event_db_id = curr_event.getAttribute ('id');
        venue_id = curr_event.getAttribute ('vid');
        if (venue_id == null) venue_id = '';
        venue_name = String (curr_event.getAttribute ('vn'));
        venue_is_restaurant = Number (curr_event.getAttribute ('vr'));
        
        event_obj = new event_info (
          top_node.getAttribute ('month') + '-' + event_date, event_db_id, event_title, is_vegan, event_text,
          attendee_lists, venue_id, venue_name, venue_is_restaurant
        );
        
        while (col_id < cols.length) {
          if (col.innerHTML == event_day) {
            if (calendar_events[event_day]) {
              calendar_events[event_day].push (event_obj);
            } else {
              calendar_events[event_day] = [event_obj];
            }
            add_event_action (col);
            if (is_vegan) {
              col.className = 'vegan_event';
            } else {
              col.className = 'other_event';
            }
            if (this.autoload && this.autoload_date == event_day) {
              col.onclick ();
            }
            break;
          } else {
            col_id++;
            col = cols.item (col_id);
          }
        }
      }
      
      document.getElementById ('events_loading').style.visibility = 'hidden';
    }
  }
  
  this.set_autoload = function (autoload) {
    
    if (typeof (autoload) == 'string' && autoload.match (/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/)) {
      this.autoload = true;
      this.autoload_date = Number (autoload.substr (autoload.length - 2));
    } else {
      this.autoload = false;
    }
  }
}

function add_event_action (col) {
  col.onclick = function () {
    if (selected_day != null) {
      selected_day.className = selected_day.className.replace (' selected', '');
    }
    if (!col.className.match (' selected')) {
      col.className += ' selected';
    }
    selected_day = col;
    show_day (col.innerHTML);
  }
}

function show_attendees (node) {
  node.parentNode.nextSibling.style.display = 'block';
  node.style.display = 'none';
}

var calendar_handler = new CalendarHandler ();
