/**
*
* File: default.js
*
* Global javascript file.
*  
*/

/* Global Constants */
var Constants =
{
  LOGOUT:
    {
      SERVLET: 'MainServlet',
      METHOD: 'logout',
      USER_COOKIES: ['UserName', 'UserID', 'AccessClass', 'PortalURL']
    },
  PAGE:
    {
      LOGIN: 'ZumeLogin.jsp',
      PATIENT_OVERVIEW : 'PatientGraphPrint.jsp',
      PATIENT_JOURNAL_DAILY: 'PatientJournalDaily.jsp',
      PATIENT_JOURNAL_WEEKLY: 'PatientJournalWeekly.jsp',
      PATIENT_JOURNAL_MONTHLY: 'PatientJournalMonthly.jsp',
      PATIENT_TABLE: 'PTTableDataPrint.jsp',
      PATIENT_PROFILE: 'PatientProfilePrint.jsp',
      PATIENT_SETUP: 'PatientSetup.jsp'
    }
};

/*
* BEGIN AJAX functions
*/

/* Formats an Xml Request for AJAX */
function formatXmlRequest(method, params)
{
  var request = '<ZL><COMMAND>WEBCOMMAND</COMMAND><METHODNAME>' + method + '</METHODNAME><REQUEST><PARAMETERS>';
  for (key in params)
  {
    var tag = key.replace(/_/g, '-').toUpperCase();
    request += '<' + tag + '>' + params[key] + '</' + tag + '>'; 
  }
  request += '</PARAMETERS></REQUEST></ZL>';
  
  return request;
}

/* Formats an Xml Request for AJAX with parametes as acomplete string*/
function formatXmlRequestStr(method, params)
{
  var request = '<ZL><COMMAND>WEBCOMMAND</COMMAND><METHODNAME>' + method + '</METHODNAME><REQUEST><PARAMETERS>'+ params +'</PARAMETERS></REQUEST></ZL>';
   
  return request;
}

/* Utility function for retrieving the value of an Xml Node */
function getXmlNodeValue(xmlDoc, nodeName)
{
  var node = xmlDoc.getElementsByTagName(nodeName);
  if (node.length > 0 && node[0].firstChild)
  {
    return node[0].firstChild.data;
  }
  return '';
}

/*
* END AJAX functions
*/

/* Formats a phone number for display */
function formatPhone(phoneNumber)
{
  if (phoneNumber == null || phoneNumber == '' || phoneNumber.match(/null/i))
  {
    return '';
  }
  else
  {
    var matches = phoneNumber.match(/(\d{3})?(\d{3})(\d{4})/);
    switch (matches.length)
    {
      case 4:
        return matches[1] + '-' + matches[2] + '-' + matches[3];
        break;
      case 3:
        return matches[1] + '-' + matches[2];
        break
      default:
        return phoneNumber;
        break;
    }
  }
}

function Capitalize(str){
    return str.replace(/\w+/g, function(a){
        return a.charAt(0).toUpperCase() + a.slice(1).toLowerCase();
    });
};

/* Determines the default display type of an element based on its tag name. */
/* Based on W3C default CSS recommendations: http://www.w3.org/TR/CSS21/sample.html */
/* Proper display values have been commented out and replaced by empty string to handle browser compatibility issues for current set of browsers */
/* Hopefully, at some point, browsers can support full compatibility and we can use the proper values */
/* http://reference.sitepoint.com/css/display */
function getDefaultDisplayType(elementId)
{
  var element = YAHOO.util.Dom.get(elementId);
  
  // Most likely tags are listed first.
  switch (element.tagName.toLowerCase())
  {
    case 'table':
      return '';
      // IE doesn't support display table.
      //return 'table';
    case 'tr':
      return '';
      // IE doesn't support display table-row.
      //return 'table-row';
    case 'td':
    case 'th':
      return '';
      // IE doesn't support display table-cell.
      //return 'table-cell';
    case 'li':
      return 'list-item';
    case 'input':
    case 'select':
      return '';
      // FF2 doesn't support display inline-block.
      //return 'inline-block';
    case 'div':
    case 'p':
    case 'h1':
    case 'h2':
    case 'h3':
    case 'h4':
    case 'h5':
    case 'h6':
    case 'form':
    case 'ol':
    case 'ul':
    case 'hr':
    case 'blockquote':
    case 'dd':
    case 'dl':
    case 'dt':
    case 'fieldset':
    case 'center':
    case 'dir':
    case 'menu':
    case 'pre':
    case 'html':
    case 'body':
    case 'address':
    case 'frame':
    case 'frameset':
    case 'noframes':
      return 'block';
    case 'thead':
      return 'table-header-group';
    case 'tbody':
      return '';
      // IE doesn't support display table-row-group.
      //return 'table-row-group';
    case 'tfoot':
      return 'table-footer-group';
    case 'col':
      return '';
      // IE doesn't support display table-column.
      //return 'table-column';
    case 'colgroup':
      return '';
      // IE doesn't support display table-column-group.
      //return 'table-column-group';
    case 'caption':
      return '';
      // IE doesn't support display table-caption.
      //return 'table-caption';
    default:
      return 'inline';
  }
}
  
/* Convenience method to set the selected value of a select form element. */
function setSelectValue(selectEl, value)
{
  value = ""+value;
  var select = YAHOO.util.Dom.get(selectEl);
  for (var i = 0; i < select.options.length; i++)
  {
    var option = select.options[i];
    option.selected = (option.value.toLowerCase() == value.toLowerCase()); 
  }
}

/* Convenience method to get the selected value of a select form element. */
function getSelectValue(selectEl)
{
  var select = YAHOO.util.Dom.get(selectEl);
  for (var i = 0; i < select.options.length; i++)
  {
    var option = select.options[i];
    if (option.selected)
    {
      return option.value;
    }
  }
  return '';
}
function getSelectPropertyValue(selectEl,propName)
{
  var select = YAHOO.util.Dom.get(selectEl);
  for (var i = 0; i < select.options.length; i++)
  {
    var option = select.options[i];
    if (option.selected)
    {
      return option.attributes[propName].value;
    }
  }
  return '';
}

/* Convenience method to retrieve a collection of form inputs. Useful for collecting radio button and checkbox groups. */
function getInputCollection(type, name)
{
  var allInputs = document.getElementsByTagName('input');
  var lowerType = type.toLowerCase();
  
  var result = [];
  for (var i = 0; i < allInputs.length; i++)
  {
    var input = allInputs[i];
    if (input.name == name && input.getAttribute('type').toLowerCase() == lowerType)
    {
      result[result.length] = input;
    }
  }
  return result;
}

/* Convenience method to get the checked value of a radio button. */
function getRadioValue(radioEl)
{
  var radios;
  if (!YAHOO.lang.isArray(radioEl))
  {
    var radio = YAHOO.util.Dom.get(radioEl);
    radios = getInputCollection('radio', radio.name);
  }
  else
  {
    radios = [];
    for (var i = 0; i < radioEl.length; i++)
    {
      radios[i] = YAHOO.util.Dom.get(radioEl[i]);
    }
  }
  
  for (var i = 0; i < radios.length; i++)
  {
    var radio = radios[i];
    if (radio.checked)
    {
      return radio.value;
    }
  }
  return '';  
}

/* Convenience method to get the checked value of a checkbox button. */
function getCheckboxValue(checkboxEl)
{
  var checks;
  if (!YAHOO.lang.isArray(checkboxEl))
  {
    var check = YAHOO.util.Dom.get(checkboxEl);
    checks = getInputCollection('checkbox', check.name);
  }
  else
  {
    checks = [];
    for (var i = 0; i < checkboxEl.length; i++)
    {
      checks[i] = YAHOO.util.Dom.get(checkboxEl[i]);
    }
  }
  
  var result = [];
  for (var i = 0; i < checks.length; i++)
  {
    var check = checks[i];
    if (check.checked)
    {
      result[result.length] = check.value;
    }
  }
  return result;  
}

/* Creates a cookie that expires in a given number of hours */
function createCookie(name, value, hours)
{
  var date = new Date();
  date.setTime(date.getTime() + (hours * 60 * 60 * 1000));
  
  YAHOO.util.Cookie.set(name, value, {expires: date.toGMTString(), path: '/'});
}

/* Logs out the user. Clears cookies and notifies the server by AJAX */
function logoutUser(loginUrl)
{
  var temp;
  try
  {
    for (var i = 0; i < Constants.LOGOUT.USER_COOKIES.length; i++)
    {
      YAHOO.util.Cookie.remove(Constants.LOGOUT.USER_COOKIES[i]);
    }
  }
  catch (e)
  {
  }
  
  if(loginUrl==temp)
  	;
  else
  	Constants.PAGE.LOGIN = loginUrl;
  
  var requestString = formatXmlRequest(Constants.LOGOUT.METHOD, {});
  var request = YAHOO.util.Connect.asyncRequest('POST', Constants.LOGOUT.SERVLET, {success: logoutSuccess, failure: logoutFailure}, requestString);

  return false;
}

/* Regardless of success or failure, redirect to the login page. */
function logoutSuccess()
{
  window.location = Constants.PAGE.LOGIN;
}

function logoutFailure()
{
  window.location = Constants.PAGE.LOGIN;
}

/*
* BEGIN Object Classes
*/

/* Simplified version of prototype.js Function.bind. */
Function.prototype.bind = function()
{
  var method = this;
  var obj = arguments[0];

  var args = [];
  for (var i = 1; i < arguments.length; i++)
  {
    args[args.length] = arguments[i];
  }
  
  return function()
  {
    var newArgs = [];
    for (var i = 0; i < arguments.length; i++)
    {
      newArgs[i] = arguments[i];
    }
    return method.apply(obj, args.concat(newArgs));
  }
}

/* Tab Set widget */
/* Class for a set of tabs */
var TabSet = function(tabSetClass, hasMouseOverBehaviors)
{
  var tabEls = YAHOO.util.Dom.getElementsByClassName(tabSetClass);
  if (tabEls.length > 0)
  {
    this.el = tabEls[0];
  }
  else
  {
    return;
  }

  this.tabs = this.el.getElementsByTagName('a');
  
  this.setupTabs();
  
  if (hasMouseOverBehaviors)
  {
    /* Set hover behaviors */
    YAHOO.util.Event.addListener(this.el, "mouseout", this.mouseout, this, true);
    for (var i = 0; i < this.tabs.length; i++)
    {
      YAHOO.util.Event.addListener(this.tabs[i], 'mouseover', this.mouseover, i + 1, this);
    }
  }
};

TabSet.prototype =
{
  /* Displays originally selected tab */
  mouseout: function(e)
  {
    this.showTab(this.selected);
  },
  
  /* Displays tab specified by index (1-based) */
  mouseover: function(e, index)
  {
    this.showTab(index);
  },
  
  /* Shows the tab at index (1-based) */
  showTab: function(index)
  {
    var newClass = this.getClass(index);
    YAHOO.util.Dom.replaceClass(this.el, this.currClass, newClass);
    /* Track the current class */
    this.currClass = newClass;
  },
  
  setupTabs: function()
  {
    /* Default to the first tab */
    this.selected = 1;
    this.tabCount = this.tabs.length;
    this.currClass = this.getClass(1);
  
    /* See if a different tab is selected by class name */
    var matches = this.el.className.match(/tab(\d+)Of\d+Selected/);
    if (matches)
    {
      this.currClass = matches[0];
      this.selected = matches[1];
    }
  },
  
  getClass: function(index)
  {
    return 'tab' + index + 'Of' + this.tabCount + 'Selected';
  }
}

/* Tab set for secondary tabs */
var SecondaryTabSet = function(tabSetClass, hasMouseOverBehaviors)
{
  SecondaryTabSet.superclass.constructor.call(this, tabSetClass, hasMouseOverBehaviors);
}

YAHOO.lang.extend(SecondaryTabSet, TabSet,
{
  setupTabs: function()
  {
    /* Default to the first tab */
    this.selected = 1;
    this.currClass = this.getClass(1);
  
    /* See if a different tab is selected by class name */
    var matches = this.el.className.match(/tab(\d+)Selected/);
    if (matches)
    {
      this.currClass = matches[0];
      this.selected = matches[1];
    }
  },
  
  getClass: function(index)
  {
    return 'tab' + index + 'Selected';
  }
});

/* Floating Element widget */
/* Positions element with the given id at position [x, y] relative to the browser window regardless of resizing or scrolling */
var FloatingEl = function(id, position)
{
  this.el = YAHOO.util.Dom.get(id);
  this.setPosition(position);
}

FloatingEl.prototype =
{
  /* Sets the position of the element relative to the browser window */
  setPosition: function(position)
  {
    this.posX = position[0] ? position[0] : 0;
    this.posY = position[1] ? position[1] : 0;
  },
  
  /* Starts the element floating */
  start: function()
  {
    this.floating = true;
    this.float();
  },
  
  /* Stops the element floating */
  stop: function()
  {
    this.floating = false;
  },
  
  /* Floats the element. */
  float: function()
  {
    if (this.floating)
    {
      /* If position is negative, calculate the position from the right or bottom edge of the screen */
      var newPosX = (this.posX < 0) ? YAHOO.util.Dom.getViewportWidth() + this.posX : this.posX;
      var newPosY = (this.posY < 0) ? YAHOO.util.Dom.getViewportHeight() + this.posY : this.posY;
  
      /* Account for vertical scroll */
      newPosY += YAHOO.util.Dom.getDocumentScrollTop();
      
      /* Reposition element */
      YAHOO.util.Dom.setXY(this.el, [newPosX, newPosY]);
  
      /* Refloat every 1 millisecond */
      setTimeout(this.float.bind(this), 1);
    }
  }
}

/* Show/hide widget */
var ShowHide = function(controlId, subjectIds)
{
  this.HIDDEN_CLASS = 'closed';
  this.CACHE_NAME = 'showHide';

  this.control = YAHOO.util.Dom.get(controlId);

  if (!this.control)
  {
    return;
  }

  this.subjects = [];
  this.displayType = [];
  for (var i = 0; i < subjectIds.length; i++)
  {
    this.subjects[i] = YAHOO.util.Dom.get(subjectIds[i]);
    /* Get original display setting for subjects. */
    if (this.subjects[i])
    {
      this.displayType[i] = getDefaultDisplayType(this.subjects[i]);
      // Assume all show/hide elements are at least display block.
      if (this.displayType[i] == 'inline')
      {
        this.displayType[i] = 'block';
      }
    }
  }
  
  /* Add click event listener */
  YAHOO.util.Event.addListener(this.control, 'click', this.click, this, true);
}

ShowHide.prototype =
{
  /* Toggles the show/hide of subjects */
  click: function(e)
  {
    this.toggleDisplay();

    /* Disable default link behavior */
    YAHOO.util.Event.stopEvent(e);
  },

  /* Switches subject elements between original display type and display none */
  /* Changes the class on control to reflect show/hide state */
  toggleDisplay: function()
  {
    if (YAHOO.util.Dom.hasClass(this.control, this.HIDDEN_CLASS))
    {
      YAHOO.util.Dom.removeClass(this.control, this.HIDDEN_CLASS);
    }
    else
    {
      YAHOO.util.Dom.addClass(this.control, this.HIDDEN_CLASS);
    }
    
    var showHideState = {};
    for (var i = 0; i < this.subjects.length; i++)
    {
      var subject = this.subjects[i];
      if (subject)
      {
        if (subject.style.display == 'none')
        {
          subject.style.display = this.displayType[i];
          showHideState[subject.id] = 1;
        }
        else
        {
          subject.style.display = 'none';
          showHideState[subject.id] = 0;
        }
      }
    }
    
    // Maintain the show/hide state across HTTP requests.
    this.saveShowHideState(showHideState);
  },
  
  /* Saves the show/hide state across HTTP requests */
  saveShowHideState: function(showHideState)
  {
    var currShowHideState = SessionCache.get(this.CACHE_NAME);

    // The cache holds state for all show/hide instances.
    // So maintain the current state and only override the settings for this instance.
    for (key in showHideState)
    {
      currShowHideState[key] = showHideState[key];
    }

    SessionCache.set(this.CACHE_NAME, currShowHideState);
  }
}

/* Client-side session management */
/* Stores session information in a cookie */
/* Can only store limited amounts of info */
/* Not for use with secure info */
var SessionCache = {};
SessionCache.SESSION_TTL = 2; // Session expires in 2 hours.

/* Gets an object from the cache */
SessionCache.get = function(cacheName)
{
  var cookie = YAHOO.util.Cookie.get(cacheName);
  return (cookie == null) ? {} : YAHOO.lang.JSON.parse(cookie);
}

/* Sets an object in the cache */
SessionCache.set = function(cacheName, obj)
{
  var jsonString = YAHOO.lang.JSON.stringify(obj);
  createCookie(cacheName, jsonString, SessionCache.SESSION_TTL);
}

/* Class for an edit in place form that toggles between a read only view and an edit view. */
/*
  Accepts a callbacks object containing callback methods for:
  initialize - Called when initializing the EditInPlaceForm
  cancel - Called when the cancel button is clicked, just before returning to read-only form.
  save - Called when the cancel button is clicked to save any changes to the edit form.
  updateEditForm - Called to update the edit form with values.
  updateReadForm - Called to update the read-only form with values.
*/
var EditInPlaceForm = function(readId, editId, callbacks)
{
  this.readForm = YAHOO.util.Dom.get(readId);
  this.editForm = YAHOO.util.Dom.get(editId);

  this.callbacks = callbacks;

  this.showReadForm();

  var editBtns = YAHOO.util.Dom.getElementsByClassName('button', 'a', this.readForm);
  
  /* Stop if there is no edit button */ 
  if (editBtns.length == 0)
  {
    return;
  }
  
  this.editBtn = editBtns[0];

  this.cancelBtn = YAHOO.util.Dom.getElementsByClassName('button', 'a', this.editForm)[0];
  this.saveBtn = YAHOO.util.Dom.getElementsByClassName('buttonPref', 'a', this.editForm)[0];
  
  YAHOO.util.Event.addListener(this.editBtn, 'click', this.clickEdit, this, true);
  YAHOO.util.Event.addListener(this.cancelBtn, 'click', this.clickCancel, this, true);
  YAHOO.util.Event.addListener(this.saveBtn, 'click', this.clickSave, this, true);
  
  /* Run the initialize callback if any */
  if (this.callbacks.initialize)
  {
    this.callbacks.initialize.call(this);
  }
}

EditInPlaceForm.prototype =
{
  clickEdit: function(e)
  {
    this.showEditForm();

    /* Disable default link behavior */
    YAHOO.util.Event.stopEvent(e);
  },
  
  clickCancel: function(e)
  {
    if (this.callbacks.cancel)
    {
      this.callbacks.cancel.call(this, this.editForm);
    }

    this.showReadForm();

    /* Disable default link behavior */
    YAHOO.util.Event.stopEvent(e);
  },
  
  clickSave: function(e)
  {
    var returnVal = true;
    if (this.callbacks.save)
    {
      returnVal = this.callbacks.save.call(this, this.editForm);
    }

    if (returnVal)
    {
      this.showReadForm();
    }

    /* Disable default link behavior */
    YAHOO.util.Event.stopEvent(e);
  },
  
  showEditForm: function()
  {
    /* Update the edit form with a callback. */
    if (this.callbacks.updateEditForm)
    {
      this.callbacks.updateEditForm.call(this, this.editForm);
    }
    this.editForm.style.display = 'block';
    this.readForm.style.display = 'none';
  },
  
  showReadForm: function()
  {
    /* Update the read form with a callback. */
    if (this.callbacks.updateReadForm)
    {
      this.callbacks.updateReadForm.call(this, this.readForm);
    }
    this.readForm.style.display = 'block';
    this.editForm.style.display = 'none';
  }
}

/* DataTable widget */
var DataTable = function(tableId, sortFields)
{
  this.TEMPLATE_CLASS = 'template';
  this.HEADER_CLASS = 'header';
  this.SUMMARY_CLASS = 'summary';
  this.ODD_ROW_CLASS = 'odd';

  this.table = YAHOO.util.Dom.get(tableId);
  this.header = YAHOO.util.Dom.getElementsByClassName(this.HEADER_CLASS, 'tr', this.table)[0];
  this.template = YAHOO.util.Dom.getElementsByClassName(this.TEMPLATE_CLASS, 'tr', this.table)[0];
  this.summary = YAHOO.util.Dom.getElementsByClassName(this.SUMMARY_CLASS, 'tr', this.table)[0];
  
  /* Create a custom event for sorting */
  this.onresort = new YAHOO.util.CustomEvent('resort', this);
  
  this.sortEls = {};

  /* Attach event handlers for sort fields */
  for (var i = 0; i < sortFields.length; i++)
  {
    var sortField = sortFields[i];
    var el = YAHOO.util.Dom.getElementsByClassName(sortField, 'a', this.table)[0];
    this.sortEls[sortField] = el
    YAHOO.util.Event.addListener(el, 'click', this.resort, sortField, this);
  }
}

DataTable.prototype =
{
  resort: function(e, sort)
  {
    /* Update the sort field */
    this.setSortField(sort);
  
    /* Fire the custom event */
    this.onresort.fire(this.sortField, this.sortDirection);

    /* Disable default link behavior */
    YAHOO.util.Event.stopEvent(e);
  },
  
  setSortField: function(sort, direction)
  {
    /* Remove sort indicator for current sort field */
    if (this.sortField)
    {
      YAHOO.util.Dom.removeClass(this.sortEls[this.sortField], (this.sortDirection == 1) ? 'asc' : 'desc');
    }

    /* Toggle between ascending and descending or start with ascending if sorting  by a new field */
    this.sortDirection = direction ? direction : (this.sortField == sort) ? -1 * this.sortDirection : 1;
    this.sortField = sort;
    
    /* Set sort indicator for new sort field */
    YAHOO.util.Dom.addClass(this.sortEls[this.sortField], (this.sortDirection == 1) ? 'asc' : 'desc');
  },

  /* Displays data in the table */
  /* Pass in a callback function to fill data into the table row */
  displayData: function(data, fillDataCallback)
  {
    this.clearData();
    var tableBody = this.table.tBodies[0];
    for (var i = 0; i < data.length; i++)
    {
      var datum = data[i];
      
      var row = this.template.cloneNode(true);
      tableBody.appendChild(row);

      fillDataCallback(row, datum);

      YAHOO.util.Dom.removeClass(row, this.TEMPLATE_CLASS);
      
      if (i % 2)
      {
        YAHOO.util.Dom.addClass(row, this.ODD_ROW_CLASS);
      }
    }

    // Make sure summary is the last row.
    if (this.summary)
    {
      tableBody.appendChild(this.summary);
      // Should be table-row, but IE doesn't support it.
      this.summary.style.display = '';
    }
  },
  
  /* Removes data rows from the table */
  clearData: function()
  {
    var rows = this.table.getElementsByTagName('tr');

    var deleteRows = [];
    for (var i = 0; i < rows.length; i++)
    {
      var row = rows[i];
      if (row != this.header && row != this.template && row != this.summary)
      {
        deleteRows[deleteRows.length] = row;
      }
    }

    for (var i = 0; i < deleteRows.length; i++)
    {
      var row = deleteRows[i];
      row.parentNode.removeChild(row);
    }
    
    // Hide the summary till we get some data.
    if (this.summary)
    {
      this.summary.style.display = 'none';
    }
  }
}

/* Food data table. Composes DataTable */
var FoodTable = function(tableId)
{
  // Simple data table with no filters.
  this.table = new DataTable(tableId, []);
}

FoodTable.prototype =
{
  /* Sets the journal entries and repopulates the food table */
  setJournalEntries: function(journalEntries)
  {
    this.entries = journalEntries;
    this.populateFoodTable();
  },
  
  /* Populates the daily food table */
  populateFoodTable: function()
  {
    var foodTotal = {};
    var servingsTotal = 0;
    var caloriesTotal = 0;
    
    // Iterate through entries.
    for (var i = 0; i < this.entries.length; i++)
    {
      var entry = this.entries[i];
      // Only examine food entries with calorieItems
      if (entry.type.toLowerCase() == 'food' && entry.calorieItems)
      {
        // Check the items for each entry.
        for (var j = 0; j < entry.calorieItems.length; j++)
        {
          var item = entry.calorieItems[j];
          var servings = parseInt(item.value);
          var calories = parseInt(item.measure);
          // Already have an existing total, add to the total.
          if (foodTotal[item.name])
          {
            foodTotal[item.name].servings += servings;
            foodTotal[item.name].calories += calories;
          }
          // Start a new food item.
          else
          {
            foodTotal[item.name] = {};
            foodTotal[item.name].name = item.name;
            foodTotal[item.name].servings = servings;
            foodTotal[item.name].calories = calories;
          }
          // Total the servings and calories.
          servingsTotal += servings;
          caloriesTotal += calories;
        }
      }
    }
    
    // Convert the object to an array so we can display the data.
    var foodArray = [];
    for (var foodName in foodTotal)
    {
      foodArray[foodArray.length] = foodTotal[foodName];
    }
    
    // Display the data.
    this.table.displayData(foodArray, this.fillFoodTableRow);
    
    // Update the totals in the summary row.
    /*var servingsTotalEl = YAHOO.util.Dom.getElementsByClassName('servings', 'td', this.table.summary)[0];
    servingsTotalEl.innerHTML = servingsTotal;
    var caloriesTotalEl = YAHOO.util.Dom.getElementsByClassName('calories', 'td', this.table.summary)[0];
    caloriesTotalEl.innerHTML = caloriesTotal;*/
  },
  
  /* Fills a food table row */
  fillFoodTableRow: function(row, foodItem)
  {
    var categoryEl = YAHOO.util.Dom.getElementsByClassName('category', 'td', row)[0];
    categoryEl.innerHTML = foodItem.name;
    var servingsEl = YAHOO.util.Dom.getElementsByClassName('servings', 'td', row)[0];
    servingsEl.innerHTML = foodItem.servings;
    var caloriesEl = YAHOO.util.Dom.getElementsByClassName('calories', 'td', row)[0];
    caloriesEl.innerHTML = foodItem.calories;
  }
}


/* Food data table. Composes DataTable */
var JournalFoodTable = function(tableId)
{
  // Simple data table with no filters.
  this.table = new DataTable(tableId, []);
}

JournalFoodTable.prototype =
{
  /* Sets the journal entries and repopulates the food table */
  setJournalEntries: function(journalEntries)
  {
    this.entries = journalEntries;
    this.populateFoodTable();
  },
  
  /* Populates the daily food table */
  populateFoodTable: function()
  {
    var journalTotal = {};
    var servingsTotal = 0;
    var caloriesTotal = 0;
    
    if(this.entries)
    {
	    for(var i=0; i< this.entries.length; i++)
	    {
	    	var entry = this.entries[i];
	    	
	    	// Only examine food entries with calorieItems
	      	if (entry.type.toLowerCase() == 'food' && entry.metrics)
	      	{
	        	// Check the items for each entry.
	        	for (var j = 0; j < entry.metrics.length; j++)
	        	{
	        		var item = entry.metrics[j];
	          		var measure = parseInt(item.value);
	          		
	          		// Already have an existing total, add to the total.
	          		if(journalTotal[item.id])
	          		{
	          			if(measure)
	          			{
	          				journalTotal[item.id].measure += measure;
	          			}
	          		}
	          		// Start a new food item.
	          		else
	          		{
	            		journalTotal[item.id] = {};
	            		journalTotal[item.id].name = item.name;
	            		if(measure)
	          			{
	            			journalTotal[item.id].measure = measure;
	            		}
	            		else
	            		{
	            			journalTotal[item.id].measure = 0;
	            		}
	          		}
	        	}
	        }
	    }
	}
    
    // Convert the object to an array so we can display the data.
    var foodArray = [];
    for (var metricId in journalTotal)
    {
      foodArray[foodArray.length] = journalTotal[metricId];
    }
    
    // Display the data.
    this.table.displayData(foodArray, this.fillFoodTableRow);
    
    // Update the totals in the summary row.
    /*var servingsTotalEl = YAHOO.util.Dom.getElementsByClassName('servings', 'td', this.table.summary)[0];
    servingsTotalEl.innerHTML = servingsTotal;
    var caloriesTotalEl = YAHOO.util.Dom.getElementsByClassName('calories', 'td', this.table.summary)[0];
    caloriesTotalEl.innerHTML = caloriesTotal;*/
  },
  
  /* Fills a food table row */
  fillFoodTableRow: function(row, foodItem)
  {
    var categoryEl = YAHOO.util.Dom.getElementsByClassName('category', 'td', row)[0];
    categoryEl.innerHTML = foodItem.name;
    var servingsEl = YAHOO.util.Dom.getElementsByClassName('servings', 'td', row)[0];
    servingsEl.innerHTML = '';
    var caloriesEl = YAHOO.util.Dom.getElementsByClassName('calories', 'td', row)[0];
    caloriesEl.innerHTML = foodItem.measure;
  }
}


/* Food data table. Composes DataTable */
var JournalExerciseTable = function(tableId)
{
  // Simple data table with no filters.
  this.table = new DataTable(tableId, []);
}

JournalExerciseTable.prototype =
{
  /* Sets the journal entries and repopulates the food table */
  setJournalEntries: function(journalEntries)
  {
    this.entries = journalEntries;
    this.populateExerciseTable();
  },
  
  /* Populates the daily food table */
  populateExerciseTable: function()
  {
    totalMin = 0;
    if(this.entries)
    {
	    for(var i=0; i< this.entries.length; i++)
	    {
	    	var entry = this.entries[i];
	    	
	    	// Only examine food entries with calorieItems
	      	if (entry.type.toLowerCase() == 'exercise' && entry.activities)
	      	{
	      		if(entry.getTotalMinutes())
	      		{
	        		totalMin += entry.getTotalMinutes();
	        	}
	        }
	    }
	}
    
    var exerciseArray = [];
    
    exerciseArray[exerciseArray.length] = totalMin;
    
    
    // Display the data.
    this.table.displayData(exerciseArray, this.fillExerciseTableRow);
  },
  
  /* Fills a food table row */
  fillExerciseTableRow: function(row, totalMinutes)
  {
    var categoryEl = YAHOO.util.Dom.getElementsByClassName('category', 'td', row)[0];
    categoryEl.innerHTML = 'Total Minutes';
    var servingsEl = YAHOO.util.Dom.getElementsByClassName('servings', 'td', row)[0];
    servingsEl.innerHTML = '';
    var caloriesEl = YAHOO.util.Dom.getElementsByClassName('calories', 'td', row)[0];
    caloriesEl.innerHTML = totalMinutes;
  }
}

/* Filter widget */
var Filter = function(filterId)
{
  this.SELECTED_CLASS = 'selected';
  this.INACTIVE_CLASS = 'inactive';

  /* Get the container element and individual filters */
  this.el = YAHOO.util.Dom.get(filterId);
  this.filters = this.el.getElementsByTagName('a');
  
  /* Create a custom event for a filter change */
  this.onchangefilter = new YAHOO.util.CustomEvent('changeFilter', this);
  
  /* Assign click events for each filter. Determine the currently selected filter */
  this.selectedIndex = 0;
  for (var i = 0; i < this.filters.length; i++)
  {
    var filter = this.filters[i];
    if (YAHOO.util.Dom.hasClass(filter, this.SELECTED_CLASS))
    {
      this.selectedIndex = i;
    }
    YAHOO.util.Event.addListener(filter, 'click', this.changeFilter, i, this);
  }
}

Filter.prototype =
{
  /* Retrieves the value of the selected filter */
  getFilter: function()
  {
    return this.filters[this.selectedIndex].innerHTML;
  },
  
  /* Event handler for a filter being clicked */
  changeFilter: function(e, filterIndex)
  {
    var filter = this.filters[filterIndex];
    
    /* Ignore inactive filters */
    if (!YAHOO.util.Dom.hasClass(filter, this.INACTIVE_CLASS))
    {
      /* Fire the custom event and select the filter */
      this.onchangefilter.fire(filter.innerHTML);
      this.selectFilter(filterIndex);
    }

    /* Disable default link behavior */
    YAHOO.util.Event.stopEvent(e);
  },
  
  /* Deselects the currently selected filter and selects the filter at index */
  selectFilter: function(index)
  {
    var currFilter = this.filters[this.selectedIndex];
    YAHOO.util.Dom.removeClass(currFilter, this.SELECTED_CLASS);

    var newFilter = this.filters[index];
    YAHOO.util.Dom.addClass(newFilter, this.SELECTED_CLASS);

    this.selectedIndex = index;
  },
  
  /* Enables or disables a filter button */
  activateFilter: function(value, active)
  {
    /* Find the filter with the given value */
    for (var i = 0; i < this.filters.length; i++)
    {
      var filter = this.filters[i];
      if (filter.innerHTML == value)
      {
        if (active)
        {
          YAHOO.util.Dom.removeClass(filter, this.INACTIVE_CLASS);
        }
        else
        {
          YAHOO.util.Dom.addClass(filter, this.INACTIVE_CLASS)
        }
        return;
      }
    }
  }
}

/* Checkbox-based filter for journals */
var JournalFilter = function(checkboxId, journalId, filterClassName)
{
  /* Make sure the checkbox exists */
  this.checkbox = YAHOO.util.Dom.get(checkboxId);
  this.jnTable = YAHOO.util.Dom.get(checkboxId + "dailyTotalTable");
  this.jnTitle = YAHOO.util.Dom.get(checkboxId + "Title");
  
  if (!this.checkbox)
  {
    return;
  }
  
  this.journal = YAHOO.util.Dom.get(journalId);

  /* Get the elements that match the filterClassName */
  this.filterEls = YAHOO.util.Dom.getElementsByClassName(filterClassName, '*', this.journal);
  this.displayType = [];
  
  /* Get the original display values for the filter elements */
  for (var i = 0; i < this.filterEls.length; i++)
  {
    this.displayType[i] = getDefaultDisplayType(this.filterEls[i]);
    // Assume all filter elements are at least display block.
    if (this.displayType[i] == 'inline')
    {
      this.displayType[i] = 'block';
    }
  }
  
  /* Add event handler for clicking the checkbox or its label */
  YAHOO.util.Event.addListener(this.checkbox, 'change', this.changeFilter, this, true);
  YAHOO.util.Event.addListener(this.checkbox, 'click', this.changeFilter, this, true);
}

JournalFilter.prototype =
{
  /* Event handler for a change in the checkbox value */
  changeFilter: function(e)
  {
    /* Iterate through each filter element and show it if the checkbox is checked */
    for (var i = 0; i < this.filterEls.length; i++)
    {
      this.filterEls[i].style.display = (this.checkbox.checked) ? this.displayType[i] : 'none';
    }
    try{
    	this.jnTable.style.display = (this.checkbox.checked) ? 'block' : 'none';
    	this.jnTitle.style.display = (this.checkbox.checked) ? 'block' : 'none';
    	globalMonthlyJournal.displayEntries();
    }catch(e){
    } 
  }
}

/* Pagination widget */
var PageNav = function(pageNavId)
{
  /* Get the container element and individual controls */
  this.el = YAHOO.util.Dom.get(pageNavId);
  this.pageNum = YAHOO.util.Dom.getElementsByClassName('pageNum', 'input', this.el)[0];
  this.total = YAHOO.util.Dom.getElementsByClassName('total', 'span', this.el)[0];
  this.prevBtn = YAHOO.util.Dom.getElementsByClassName('prev', 'a', this.el)[0];
  this.nextBtn = YAHOO.util.Dom.getElementsByClassName('next', 'a', this.el)[0];
  
  /* Create a custom event for a page change */
  this.onchangepage = new YAHOO.util.CustomEvent('changePage', this);
  
  /* Assign event handlers for the controls */
  YAHOO.util.Event.addListener(this.prevBtn, 'click', this.movePrev, this, true);
  YAHOO.util.Event.addListener(this.nextBtn, 'click', this.moveNext, this, true);
  
  YAHOO.util.Event.addListener(this.pageNum, 'change', this.changePage, this, true);

  /* Initialize a default total */
  this.setTotal(1);
  this.setPage(1);
}

PageNav.prototype =
{
  /* Sets the total number of pages */
  setTotal: function(total)
  {
    this.total.innerHTML = total;
    this.totalValue = parseInt(total);
    
    /* Fix the page number and enable/disable the buttons based on the new total */
    this.getPage();
  },

  /* Gets the page number from the input box */
  /* Validates that the page number is valid and corrects the value if not */
  getPage: function()
  {
    var page = this.pageNum.value;
    if (isNaN(page))
    {
      page = 1;
    }
    else
    {
      page = parseInt(page);
      
      if (page < 1)
      {
        page = 1;
      }
      else if (page > this.totalValue)
      {
        page = this.totalValue;
      }
    }
    this.setPage(page);
    return page;
  },
  
  /* Sets the page number in the input box */
  setPage: function(page)
  {
    this.pageNum.value = page;
    /* Enable/disable the buttons based on the page */
    this.checkBtns();
  },
  
  /* Event handler for previous button click */
  movePrev: function(e)
  {
    var newPage = this.getPage() - 1;
    /* Ignore attempts to go out of bounds */
    if (newPage > 0)
    {
      /* Update page number display, fire custom event */
      this.setPage(newPage);
      this.onchangepage.fire(newPage);
    }

    /* Disable default link behavior */
    YAHOO.util.Event.stopEvent(e);
  },
  
  /* Event handler for next button click */
  moveNext: function(e)
  {
    var newPage = this.getPage() + 1;
    /* Ignore attempts to go out of bounds */
    if (newPage <= this.totalValue)
    {
      /* Update page number display, fire custom event */
      this.setPage(newPage);
      this.onchangepage.fire(newPage);
    }

    /* Disable default link behavior */
    YAHOO.util.Event.stopEvent(e);
  },
  
  /* Event handler for page input box change */
  changePage: function(e)
  {
    var page = this.getPage();
    /* Fire custom event */
    this.onchangepage.fire(page);
  },
  
  /* Enable/disable the buttons based on the current page */
  checkBtns: function()
  {
    var page = this.pageNum.value;

    this.activateBtn(this.prevBtn, (page > 1));
    this.activateBtn(this.nextBtn, (page < this.totalValue));
  },
  
  /* Enables or disables a button */
  activateBtn: function(button, active)
  {
    if (active)
    {
      button.style.visibility = 'visible';
    }
    else
    {
      button.style.visibility = 'hidden';
    }
  }
}

/* Patient pagination */
/* Composes a PageNav object */
var PatientNav = function(pageNavClass, url, nurseId, patientId)
{
  this.LOAD_METHOD = 'get_available_patients';
  this.SERVLET = 'MainServlet';

  this.url = url;
  this.nurseId = nurseId;
  this.patientId = patientId;

  var navEls = YAHOO.util.Dom.getElementsByClassName(pageNavClass, 'div');
  if (navEls.length == 0)
  {
    return;
  }
  
  /* Initialize pagination widget */
  this.pageNav = new PageNav(navEls[0]);
  /* Assign an event handler for a page change */
  this.pageNav.onchangepage.subscribe(this.changePage, this);
  
  this.loadPatients();
}

PatientNav.prototype =
{
  /* Requests patient data by AJAX */
  loadPatients: function()
  {
    //var requestString = formatXmlRequest(this.LOAD_METHOD, {sortby: 'All', nurse_id: this.nurseId});
    //var request = YAHOO.util.Connect.asyncRequest('POST', this.SERVLET, {success: this.loadSuccess, argument: [this]}, requestString);
    
    this.loadSuccess([this]);
  },
  
  /* Loads the patient data upon successful retrieval via AJAX */
  loadSuccess: function(obj)
  {
    var me = obj[0];//obj.argument[0];
    var users = xmlAvailablePatients.getElementsByTagName('USERLIST')[0];//obj.responseXML.getElementsByTagName('USERLIST')[0];
    
    // Set the total pages
    me.pageNav.setTotal(users.childNodes.length);

    // Parse the xml into data objects.
    me.patients = [];
    for (var i = 0; i < users.childNodes.length; i++)
    {
      me.patients[i] = new XmlDataObject(users.childNodes[i], {id: 'PEOPLEID', firstName: 'FIRSTNAME', lastName: 'LASTNAME'});
    }

    // Sort by last name then first name.
    me.patients.sort(function(a, b)
    {
      var aname = (a.lastName + a.firstName).toLowerCase();
      var bname = (b.lastName + b.firstName).toLowerCase();
      return (aname < bname) ? -1 : (aname > bname) ? 1 : 0;
    });

    // Set the page based on the current patient ID.
    for (var i = 0; i < me.patients.length; i++)
    {
      if (me.patients[i].id == me.patientId)
      {
        me.pageNav.setPage(i + 1);
      }
    }
  },

  /* Event handler for a page change. */
  changePage: function(eventName, args, me)
  {
    me.showPatient(args[0]);
  },
  
  /* Redirects to the page for the patient at index */
  showPatient: function(index)
  {
    window.location = this.url + this.patients[index - 1].id;
  }
}

/* Date Pagination widget */
var DateNav = function(dateNavId, setSize, currDate, disableDhtmlDates)
{
  /* Get the container element and individual controls */
  this.el = YAHOO.util.Dom.get(dateNavId);

  this.calendar = new PopupYUICalendar(
    YAHOO.util.Dom.getElementsByClassName('calendar', 'a', this.el)[0],
    YAHOO.util.Dom.getElementsByClassName('calWidget', 'div', this.el)[0]
  );

  this.prevSetBtn = YAHOO.util.Dom.getElementsByClassName('prevSet', 'a', this.el)[0];
  this.prevBtn = YAHOO.util.Dom.getElementsByClassName('prev', 'a', this.el)[0];
  this.nextBtn = YAHOO.util.Dom.getElementsByClassName('next', 'a', this.el)[0];
  this.nextSetBtn = YAHOO.util.Dom.getElementsByClassName('nextSet', 'a', this.el)[0];
  
  this.setSize = setSize;
  this.disableDhtmlDates = disableDhtmlDates;
  
  /* Create a custom event for a date change */
  this.onchangedate = new YAHOO.util.CustomEvent('changeDate', this);
  
  /* Assign event handlers for the controls */
  this.calendar.onchangedate.subscribe(this.calendarSelected, this);
  
  YAHOO.util.Event.addListener(this.prevSetBtn, 'click', this.movePrevSet, this, true);
  YAHOO.util.Event.addListener(this.prevBtn, 'click', this.movePrev, this, true);
  YAHOO.util.Event.addListener(this.nextBtn, 'click', this.moveNext, this, true);
  YAHOO.util.Event.addListener(this.nextSetBtn, 'click', this.moveNextSet, this, true);

  /* Initialize the date */
  this.setDate(currDate);
}

DateNav.prototype =
{
  /* Sets the date in the calendar widget */
  setDate: function(currDate)
  {
    this.calendar.setDate(currDate);
    this.currDate = currDate;
    this.updateButtons();
  },
  
  /* Utility method to shift the date by a given number of days */
  shiftDate: function(numDays)
  {
    var newDate = DateUtil.addDays(this.currDate, numDays);
    // Only update the date display if we haven't disabled it.
    if (!this.disableDhtmlDates)
    {
      this.setDate(newDate);
    }
    this.onchangedate.fire(newDate);
  },
  
  /* Event handler for previous set button click */
  movePrevSet: function(e)
  {
    this.shiftDate(-1 * this.setSize);

    /* Disable default link behavior */
    YAHOO.util.Event.stopEvent(e);
  },
  
  /* Event handler for previous button click */
  movePrev: function(e)
  {
    this.shiftDate(-1);

    /* Disable default link behavior */
    YAHOO.util.Event.stopEvent(e);
  },
  
  /* Event handler for next button click */
  moveNext: function(e)
  {
    this.shiftDate(1);

    /* Disable default link behavior */
    YAHOO.util.Event.stopEvent(e);
  },
  
  /* Event handler for next button click */
  moveNextSet: function(e)
  {
    this.shiftDate(this.setSize);

    /* Disable default link behavior */
    YAHOO.util.Event.stopEvent(e);
  },

  /* Event handler for calendar selection. */
  calendarSelected: function(eventName, args, me)
  {
    var newDate = args[0];
     
    if (!me.disableDhtmlDates)
    {
      me.currDate = newDate;
      me.updateButtons();
    }
    me.onchangedate.fire(newDate);
  },
  
  /* Updates the button text based on the date. */
  updateButtons: function()
  {
    var prevSetStartDate = DateUtil.addDays(this.currDate, -2 * this.setSize + 1);
    var prevSetEndDate = DateUtil.addDays(this.currDate, -1 * this.setSize);
    var nextSetStartDate = DateUtil.addDays(this.currDate, 1);
    var nextSetEndDate = DateUtil.addDays(this.currDate, this.setSize);
    
    var prevSetText = this.formatSetText(prevSetStartDate, prevSetEndDate);
    var nextSetText = this.formatSetText(nextSetStartDate, nextSetEndDate);
    
    this.prevSetBtn.innerHTML = prevSetText;
    this.prevSetBtn.setAttribute('title', prevSetText);
    this.nextSetBtn.innerHTML = nextSetText;
    this.nextSetBtn.setAttribute('title', nextSetText);
  },
  
  /* Formats the button text for next and previous set buttons. */
  formatSetText: function(startDate, endDate)
  {
    return startDate.getDate() + ' ' + DateUtil.getMonthShortString(startDate) + ' - ' + endDate.getDate() + ' ' + DateUtil.getMonthShortString(endDate);
  }
}

/* Implementation of YUI calendar as a popup */
var PopupYUICalendar = function(buttonId, calendarId)
{
  this.button = YAHOO.util.Dom.get(buttonId);

  var calContainer = YAHOO.util.Dom.get(calendarId);
  this.calendar = new YAHOO.widget.Calendar(calContainer, {title: 'Select a Date', close: true});
  this.calendar.render();
  
  /* Create a custom event for a date change */
  this.onchangedate = new YAHOO.util.CustomEvent('changeDate', this);
  
  /* Assign event handlers for the controls */
  YAHOO.util.Event.addListener(this.button, 'click', this.changeDate, this, true);

  this.calendar.selectEvent.subscribe(this.calendarSelected, this);
}

PopupYUICalendar.prototype =
{
  /* Sets the date in the calendar widget */
  setDate: function(theDate)
  {
    this.calendar.cfg.setProperty('selected', DateUtil.getDateMMDDYYYYSlashed(theDate), false);
    this.calendar.cfg.setProperty('pagedate', (theDate.getMonth() + 1) + '/' + theDate.getFullYear().toString(), false);
    this.calendar.render();
  },

  /* Event handler for calendar button click */
  changeDate: function(e)
  {
    this.calendar.show();

    /* Disable default link behavior */
    YAHOO.util.Event.stopEvent(e);
  },

  /* Event handler for calendar selection. */
  calendarSelected: function(eventName, args, me)
  {
    me.calendar.hide();
    
    var dateParts = args[0][0];
    var newDate = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]);
     
    me.onchangedate.fire(newDate);
  }
}

/* Time selection widget */
var TimeSelector = function(hourId, minuteId, meridianId)
{
  /* Get the controls */
  this.hour = YAHOO.util.Dom.get(hourId);
  this.minute = YAHOO.util.Dom.get(minuteId);
  this.meridian = YAHOO.util.Dom.get(meridianId);
  
  /* Create a custom event for a time change */
  this.onchangetime = new YAHOO.util.CustomEvent('changeTime', this);

  /* Assign event handlers for the controls */
  YAHOO.util.Event.addListener(this.hour, 'change', this.changeTime, this, true);
  YAHOO.util.Event.addListener(this.minute, 'change', this.changeTime, this, true);
  YAHOO.util.Event.addListener(this.meridian, 'change', this.changeTime, this, true);
  
  /* Determine the supported values for minutes */
  /* This allows the minutes to be selected in 5, 10, 15 minute ranges, etc. */
  this.minuteOptions = [];
  for (var i = 0; i < this.minute.options.length; i++)
  {
    this.minuteOptions[i] = parseInt(this.minute.options[i].value);
  }
  
  /* Make sure the options are in ascending order */
  this.minuteOptions.sort(this.compareByInt);
}

TimeSelector.prototype =
{
  /* Sets the time in the controls */
  setTime: function(theTime)
  {
    var time12Hour = DateUtil.get12HourTime(theTime);
    
    /* Find the greatest minute option that matches the actual minute */
    var roundedMinute = 0;
    for (var i = 0; i < this.minuteOptions.length; i++)
    {
      var minuteOption = this.minuteOptions[i];
      if (time12Hour.minutes >= minuteOption)
      {
        roundedMinute = minuteOption;
      }
      else
      {
        break;
      }
    }

    setSelectValue(this.hour, time12Hour.hours.toString());
    setSelectValue(this.minute, roundedMinute.toString());
    setSelectValue(this.meridian, time12Hour.meridian);
  },
  
  /* Gets the time from the controls */
  getTime: function()
  {
    var hour = parseInt(getSelectValue(this.hour));
    var minute = parseInt(getSelectValue(this.minute));
    var meridian = getSelectValue(this.meridian);
    
    if (meridian.toLowerCase() == 'pm')
    {
      if (hour < 12)
      {
        hour += 12;
      }
    }
    else if (hour == 12)
    {
      hour = 0;
    }
    
    var theDate = new Date();
    theDate.setHours(hour);
    theDate.setMinutes(minute);
    theDate.setSeconds(0);
    
    return theDate;
  },
  
  /* Event handler for change in the controls */
  changeTime: function(e)
  {
    this.onchangetime.fire(this.getTime());
  },
  
  /* Comparison function for comparing by integer */
  compareByInt: function(a, b)
  {
    var aInt = parseInt(a);
    var bInt = parseInt(b);
    return (aInt - bInt);
  }
}

var DateUtil = {};

/* Date utility */
DateUtil.MONTHS_SHORT = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
DateUtil.MONTHS_LONG = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
DateUtil.WEEK_DAYS_SHORT = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
DateUtil.WEEK_DAYS_LONG = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];  

DateUtil.getMonthShortString = function(currDate)
{
  return DateUtil.MONTHS_SHORT[currDate.getMonth()];
}

DateUtil.getMonthLongString = function(currDate)
{
  return DateUtil.MONTHS_LONG[currDate.getMonth()];
}

DateUtil.getWeekDayShortString = function(currDate)
{
  return DateUtil.WEEK_DAYS_SHORT[currDate.getDay()];
}

DateUtil.getWeekDayLongString = function(currDate)
{
  return DateUtil.WEEK_DAYS_LONG[currDate.getDay()];
}

DateUtil.getDateShortString = function(currDate)
{
  return currDate.getDate() + ' ' + DateUtil.getMonthShortString(currDate) + ' ' + currDate.getFullYear();
}

DateUtil.getDateLongString = function(currDate)
{
  return DateUtil.getWeekDayLongString(currDate) + ', ' + DateUtil.getMonthLongString(currDate) + ' ' + currDate.getDate() + ', ' + currDate.getFullYear();
}

DateUtil.getDateYYYYMMDD = function(currDate)
{
  var month = currDate.getMonth() + 1;
  month = (month < 10) ? '0' + month.toString() : month.toString();
  
  var theDate = currDate.getDate();
  theDate = (theDate < 10) ? '0' + theDate.toString() : theDate.toString();
  
  return currDate.getFullYear().toString() + month + theDate;
}

DateUtil.getDateYYYYMMDDDashed = function(currDate)
{
  var month = currDate.getMonth() + 1;
  month = (month < 10) ? '0' + month.toString() : month.toString();
  
  var theDate = currDate.getDate();
  theDate = (theDate < 10) ? '0' + theDate.toString() : theDate.toString();
  
  return currDate.getFullYear().toString() + '-' + month + '-' + theDate;
}

DateUtil.getDateMMDDYYYYSlashed = function(currDate)
{
  return (currDate.getMonth() + 1) + '/' + currDate.getDate().toString() + '/' + currDate.getFullYear().toString();
}

DateUtil.get12HourTime = function(currDate)
{
  var amPm = 'AM';
  var hour = currDate.getHours();
  if (hour > 12)
  {
    amPm = 'PM';
    hour -= 12;
  }
  else if (hour == 12)
  {
    amPm = 'PM';
  }
  else if (hour == 0)
  {
    hour = 12;
  }

  return { hours: hour, minutes: currDate.getMinutes(), meridian: amPm };
}

DateUtil.get12HourTimeString = function(currDate)
{
  var time12Hour = DateUtil.get12HourTime(currDate);

  var minutes = time12Hour.minutes;
  minutes = (minutes < 10) ? '0' + minutes.toString() : minutes.toString();
  
  return time12Hour.hours + ':' + minutes + ' ' + time12Hour.meridian;
}

DateUtil.addDays = function(currDate, numDays)
{
  return new Date(currDate.valueOf() + numDays * 24 * 60 * 60 * 1000);
}
DateUtil.setDate = function(strDBDate)
{
	var myDate=new Date();
	var aDBDate = strDBDate.split("-");
	myDate.setFullYear(aDBDate[0],parseInt(aDBDate[1])-1,aDBDate[2]);
	return myDate;
}

/* Base data object for loading properties from an XML node */
/*
  Pass in a map of key-value pairs where the key is the property name and the value is the tag name to use for retrieving data from the XML node.
  For example:
  {
    id: 'ID',   // Property this.id will contain the value from the node <ID></ID>
    name: 'NAME',  // Property this.name will contain the value from the node <NAME></NAME>
    createdDate: 'CREATEDDATE' // Property this.createdDate will contain the value from the node <CREATEDDATE></CREATEDDATE>
  }
  
  Supports more complex XML by passing an array for the value where the first item in the array is the tag name and the second item is another map.
  For example:
  {
    id: 'ID',
    name: 'NAME',
    address: ['ADDRESS',    // Property this.address is a complex object found within node <ADDRESS></ADDRESS>
      {
        street: 'STREET',   // Property this.address.street found within node <ADDRESS><STREET></STREET></ADDRESS>
        city: 'CITY',   // Property this.address.city found within node <ADDRESS><CITY></CITY></ADDRESS>
        state: 'STATE',   // Property this.address.state found within node <ADDRESS><STATE></STATE></ADDRESS>
        zipCode: 'ZIPCODE'    // Property this.address.zipCode found within node <ADDRESS><ZIPCODE></ZIPCODE></ADDRESS>  
      }],
    createdDate: 'CREATEDDATE'
  }
  
  If the XML has multiple <ADDRESS></ADDRESS> nodes, then property this.address will be an array of addresses instead of a single instance.
*/
var XmlDataObject = function(xmlNode, map)
{
  this.parseMap(this, xmlNode, map);
}

XmlDataObject.prototype =
{
  /* Recursive method to parse an XML node with multiple levels of depth into a js data object */
  parseMap: function(obj, xmlNode, map)
  {
    // Loop through the mappings.
    for (key in map)
    {
      var value = map[key];
      
      // If the key is mapped to a string, just get the data value.
      if (YAHOO.lang.isString(value))
      {
        obj[key] = getXmlNodeValue(xmlNode, value)
      }
      // If the key is mapped to an array, the property is a complex object.
      else if (YAHOO.lang.isArray(value))
      {
        // First element in the array is the node name.
        var nodeList = xmlNode.getElementsByTagName(value[0]);
        
        // Second element in the array is a map for the complex object.
        var subMap = value[1];
        
        // If there's only one node, just map the complex object to the property.
        if (nodeList.length == 1)
        {
          var subObj = obj[key] = {};
          this.parseMap(subObj, nodeList[0], subMap);
        }
        // If there's multiple nodes, make the property a collection and map each node as a complex object.
        else if (nodeList.length > 1)
        {
          var subObj = obj[key] = [];
          for (var i = 0; i < nodeList.length; i++)
          {
            subObj[i] = {};
            this.parseMap(subObj[i], nodeList[i], subMap);
          }
        }
      }
    }
  },

  /* Convenience method. Useful for debugging */
  toString: function()
  {
    var str = '';
    for (key in this)
    {
      str += key + ': ' + this[key] + "\n";
    }
    return str;
  }
}

/* Patient data object */
/* Extends XmlDataObject */
/* For use with XML returned from get_available_patients */
var Patient = function(xmlNode)
{
  this.LOAD_METHOD = 'get_patient_information_popup';
  this.SERVLET = 'MainServlet';
  this.contact = [];
  
  Patient.superclass.constructor.call(this, xmlNode,
  {
    id: 'PEOPLEID',
    firstName: 'FIRSTNAME',
    lastName: 'LASTNAME',
    diagnosis: 'DIAGNOSIS',
    lastReviewDate: 'LAST-REVIEW-DATE',
    flagCount: 'FLAG-COUNT',
    category: 'CATEGORY',
    resolutionStatus: 'RESOLUTION-STATUS',
    reviewedStatus: 'REVIEWED-STATUS',
    contactedStatus: 'CONTACTED-STATUS',
    scheduleStatus: 'SCHEDULE-STATUS',
    activeStatus: 'STATUS',
    preferredCallTime: 'PREFER-TIME-CALL',
    dob:'DATE-OF-BIRTH',
    diagnosis: 'CONDITION',
    primaryContact:'PRIMARY-CONTACT',
    secondaryContact:'SECONDARY-CONTACT'
  });

 this.contact[0] = this.primaryContact;
 this.contact[1] = this.secondaryContact;
    
  /* Set the status */
  if (this.diagnosis == 1)
  {
    this.status = new SetupStatus();
    this.status.complete = (this.resolutionStatus == 1);
  }
  else if (this.flagCount > 0)
  {
    this.status = (this.flag == 1) ? new StatusFlag() : new StatusNoResponse();
    this.status.count = this.flagCount;
    this.status.complete = (this.resolutionStatus == 1);
  }
  else if (this.scheduleStatus == 1)
  {
    this.status = new StatusReview();
    this.status.complete = (this.resolutionStatus == 1);
  }
  else
  {
    this.status = false;
  }
  /*do not call this method as all information loaded in frist call*/
  //this.loadPatientDetails();
}

YAHOO.lang.extend(Patient, XmlDataObject,
{
  /* TODO: This would be more efficient if all the extra patient data came with the original XML */
  /* Retrieves additional patient information via AJAX */
  loadPatientDetails: function()
  {
    var requestString = formatXmlRequest(this.LOAD_METHOD, {people_id: this.id});
    var request = YAHOO.util.Connect.asyncRequest('POST', this.SERVLET, {success: this.loadSuccess, argument: [this]}, requestString);
  },
  
  loadSuccess: function(obj)
  {
    var me = obj.argument[0];
    var userDetails = obj.responseXML.getElementsByTagName('PATIENT-INFORMATION')[0];
    
    me.contact = [];
    me.contact[0] = getXmlNodeValue(userDetails, 'PRIMARY-CONTACT');
    me.contact[1] = getXmlNodeValue(userDetails, 'SECONDARY-CONTACT');
    me.preferredCallTime = getXmlNodeValue(userDetails, 'PREFER-TIME-CALL'); 
    me.dob = getXmlNodeValue(userDetails, 'DATE-OF-BIRTH');
  },
  
  /* Convenience method for the full name */
  getFullName: function()
  {
    //return this.lastName + ', ' + this.firstName;
    return this.firstName;
  },
  
  getLastReviewDate: function()
  {
    var dateFragments = this.lastReviewDate.split('-');
    if (dateFragments.length < 3)
    {
      return '';
    }
    
    return new Date(dateFragments[0], dateFragments[1] - 1, dateFragments[2]);
  },
  
  getDob: function()
  {
    if (!this.dob)
    {
      return '';
    }
    
    var dateFragments = this.dob.split('-');
    if (dateFragments.length < 3)
    {
      return '';
    }
    
    return new Date(dateFragments[0], dateFragments[1] - 1, dateFragments[2]);
  },
  
  /* Convenience method to find the first alpha character in the name */
  getAlpha: function()
  {
    var re = /[a-zA-Z]/;
    var matches = this.getFullName().match(re);
    if (matches)
    {
      return matches[0];
    }
    else
    {
      return false;
    }
  },
  
  getFirstNameAlpha: function()
  {
      var re = /[a-zA-Z]/;
      var matches = this.firstName.match(re);
      if (matches)
      {
        return matches[0];
      }
      else
      {
        return false;
      }
  },
  
  getLastNameAlpha: function()
  {
      var re = /[a-zA-Z]/;
      var matches = this.lastName.match(re);
      if (matches)
      {
        return matches[0];
      }
      else
      {
        return false;
      }
  }
});

/* Journal entry data object */
/* Extends XmlDataObject */
/* For use with XML returned from get_daily_journal */
var JournalEntry = function(xmlNode)
{
  JournalEntry.superclass.constructor.call(this, xmlNode,
  {
    id: 'ID',
    type: 'TYPE',
    subType: 'SUB-TYPE',
    color: 'COLOR',
    description: 'DESCRIPTION',
    date: 'DATE',
    time: 'TIME',
    iconName: 'ICON-NAME',
    voice: 'VOICE',
    attachmentId:'ATTACHMENTID',
    voiceUrl: 'VOICE-URL',
    status: 'STATUS',
    source: 'SOURCE',
    metrics: ['MEAL-TRACKER',
      {
      	id: 'ID',
      	respid: 'RESPID',
        name: 'METRIC',
        value: 'VALUE'
      }],
    calorieItems: ['ITEM',
      {
        id: 'ID',
        name: 'NAME',
        value: 'VALUE',
        measure: 'MEASURE'
      }],
    activities: ['PROTOCOL',
      {
        id: 'ID',
        respid: 'RESPID',
        name: 'NAME',
        displayName: 'DISPLAY-NAME',
        value: 'VALUE'
      }]
  });
  
  // Ensure activities is an array and consolidate the activity name.
  if (this.activities)
  {
    if (!this.activities.length)
    {
      this.activities = [this.activities];
    }
    
    for (var i = 0; i < this.activities.length; i++)
    {
      var activity = this.activities[i];
      if (activity.displayName == '')
      {
        activity.displayName = activity.name;
      }
    }
  }
  
  // Ensure metrics is an array and consolidate the metric name.
  if (this.metrics)
  {
  	if (!this.metrics.length)
    {
      this.metrics = [this.metrics];
    }
  }
}

YAHOO.lang.extend(JournalEntry, XmlDataObject,
{
  getDate: function()
  {
    var dateFragments = this.date.split('-');
    if (dateFragments.length < 3)
    {
      return '';
    }
    
    var timeFragments = this.time.split(':');
    return new Date(dateFragments[0], dateFragments[1] - 1, dateFragments[2], timeFragments[0], timeFragments[1], timeFragments[2]);
  },
  
  getDatePortion: function()
  {
    return new Date(this.getDate().toDateString());
  },
  
  hasVoice: function()
  {
    var voice = this.voice.toLowerCase();
    return (voice == '1' || voice == 'yes' || voice == 'true');
  },
  
  getCalorieItemById: function(id)
  {
    id = id.toLowerCase();
    for (var i = 0; i < this.calorieItems.length; i++)
    {
      var item = this.calorieItems[i];
      if (item.id.toLowerCase() == id)
      {
        return item;
      }
    }
    return null;
  },
  
  getActivityById: function(id)
  {
    for (var i = 0; i < this.activities.length; i++)
    {
      var activity = this.activities[i];
      if (activity.id == id)
      {
        return activity;
      }
    }
    return null;
  },
  
  getMetricById: function(id)
  {
    for (var i = 0; i < this.metrics.length; i++)
    {
      var metric = this.metrics[i];
      if (metric.id == id)
      {
        return metric;
      }
    }
    return null;
  },
  
  getTotalServings: function()
  {
    var result = 0;
    if (this.calorieItems)
    {
      for (var i = 0; i < this.calorieItems.length; i++)
      {
        result += parseInt(this.calorieItems[i].value);
      }
    }
    return result;
  },
  
  getTotalCalories: function()
  {
    var result = 0;
    if (this.calorieItems)
    {
      for (var i = 0; i < this.calorieItems.length; i++)
      {
        result += parseInt(this.calorieItems[i].measure);
      }
    }
    return result;
  },
  
  getTotalMinutes: function()
  {
    var result = 0;
    if (this.activities)
    {
      // Ensure that activities is an array.
      var activities = (this.activities.length) ? this.activities : [this.activities];
      for (var i = 0; i < activities.length; i++)
      {
        result += parseInt(this.activities[i].value);
      }
    }
    return result;
  },
  
  getFullDescription: function()
  {
    var desc = '';
    var jnDesc = "";
    var valDesc = "";
    var type = this.type.toLowerCase();
    if (type == 'food')
    {
      jnDesc += this.description; 
      /*var MTValFlag = false;
      var calValFlag = false;
      
      if(this.mealTracker)
      {
      	if(this.mealTracker.value == "" || this.mealTracker.value == "0")
      	{
      		MTValFlag = false;
      	}
      	else
      	{
      		MTValFlag = true;
      	}
      }
      
      if(this.calorieItems)
      {
      	if(this.getTotalCalories() == "" || this.getTotalCalories() == "0")
      	{
      		calValFlag = false;
      	}
      	else
      	{
      		calValFlag = true;
      	}
      }
      
      if (MTValFlag || calValFlag)
      {
       	valDesc += ' (';
      }

      if (MTValFlag)
      {
        	valDesc += this.mealTracker.metric + ': ' + this.mealTracker.value;
      }
      
      if(MTValFlag || calValFlag)
      {
        		valDesc += ', ';
      }
            
      if(calValFlag)
      {
        	valDesc += 'Calories: ' + this.getTotalCalories();
      }
      
      if (MTValFlag || calValFlag)
      {
        	valDesc += ')';
      }*/
      
      if (this.metrics)
      {
	  	for (var i = 0; i < this.metrics.length; i++)
	    {
	    	var metric = this.metrics[i];
	        if(metric.value != "0")
	        {
	        	valDesc += metric.value + " ";
	          	valDesc += metric.name;
	          	
	          	if (i < this.metrics.length - 1)
	          	{
	            	valDesc += ', ';
	          	}
	        }
	 	}
	  }
    }
    else if (type == 'exercise')
    {
      var subType = this.subType.toLowerCase();
      jnDesc += this.description;
        if (this.activities)
    	{
	        for (var i = 0; i < this.activities.length; i++)
	        {
	          var activity = this.activities[i];
	          if(activity.value != "0" && activity.value != "")
	          {
	          	valDesc += activity.displayName;
	          	valDesc += ' (' + activity.value + ' mins), ';
	          }
	        }
	    }
      	if(valDesc != "")
	  	{
	  		valDesc = valDesc.substring(0, valDesc.length - 2)
	 	}
    }
    else if (type == 'life')
    {
      jnDesc += this.description;
    }
  
  	jnDesc = Trim(jnDesc);
  	exDesc = Trim(valDesc);
  
  	if(jnDesc != "" && valDesc != "")
  	{
		desc = jnDesc + ": " + valDesc;
  	}
  	else
  	{
	  	desc = jnDesc + valDesc;
  	}

    return desc;
  }
});

/* Actions Taken Convenience Class */
var ActionsTaken = function()
{
  this.actions = [];
  this.complete = false;
}

/* Static constants. Available actions */
ActionsTaken.REVIEW = 1;
ActionsTaken.CONTACT = 2;

ActionsTaken.prototype =
{
  addAction: function(action)
  {
    this.actions[this.actions.length] = action;
  },
  
  hasAction: function(action)
  {
    for (var i = 0; i < this.actions.length; i++)
    {
      if (this.actions[i] == action)
      {
        return true;
      }
    }
    return false;
  },
  
  render: function(el)
  {
    if (this.actions.length > 0)
    {
      // Wrap the actions in a container so we can target them as a whole.
      var containerDiv = document.createElement('div');
      var actionCounter = 0;
      
      if (this.hasAction(ActionsTaken.REVIEW))
      {
        this.renderReview(containerDiv);
        actionCounter++;
      }
      
      if (this.hasAction(ActionsTaken.CONTACT))
      {
        this.renderContact(containerDiv);
        actionCounter++;
      }
 
      // Set the style to determine the container width.
      YAHOO.util.Dom.addClass(containerDiv, 'actionsContainer' + actionCounter);
      
      // Clear the floats.
      var clearDiv = document.createElement('div');
      clearDiv.appendChild(document.createComment(' for IE '));
      YAHOO.util.Dom.addClass(clearDiv, 'clear');
      containerDiv.appendChild(clearDiv);

      el.appendChild(containerDiv);
      return containerDiv;
    }
    else
    {
      return this.renderNoAction(el);
    }
  },
  
  renderReview: function(el)
  {
    var actionDiv = this.complete
      ? this.getActionDiv("actionReviewComplete", "Reviewed and Resolved")
      : this.getActionDiv("actionReview", "Reviewed");

    el.appendChild(actionDiv);
    return actionDiv;
  },
  
  renderContact: function(el)
  {
    var actionDiv = this.complete
      ? this.getActionDiv("actionContactComplete", "Contacted and Resolved")
      : this.getActionDiv("actionContact", "Contacted");

    el.appendChild(actionDiv);
    return actionDiv;
  },
  
  renderNoAction: function(el)
  {
    var actionDiv = this.complete
      ? this.getActionDiv("actionNoneComplete", "No Action Taken and Resolved")
      : this.getActionDiv("actionNone", "No Action Taken");

    el.appendChild(actionDiv);
    return actionDiv;
  },
  
  getActionDiv: function(attrClass, attrTitle)
  {
    var actionDiv = document.createElement('div');
    actionDiv.appendChild(document.createComment(' for IE '));
    YAHOO.util.Dom.addClass(actionDiv, attrClass);
    actionDiv.setAttribute('title', attrTitle);
    return actionDiv;
  }
}

/* Status base class (abstract) */
var Status = function()
{
  this.complete = false;
}

Status.prototype =
{
  /* Used to compare and sort statuses */
  getRank: function()
  {
    return 0;
  },

  getClassName: function()
  {
    return "statusEmpty";
  },
  
  getTitle: function()
  {
    return "Unknown Status";
  },

  render: function(el)
  {
    var statusDiv = document.createElement('div');
    statusDiv.appendChild(document.createComment(' for IE '));
    YAHOO.util.Dom.addClass(statusDiv, this.getClassName());
    statusDiv.setAttribute('title', this.getTitle());
    el.appendChild(statusDiv);
    return statusDiv;
  }
}

/* Status for flagged patient */
var StatusFlag = function()
{
  this.count = 1;
}

YAHOO.lang.extend(StatusFlag, Status,
{
  /* Used to compare and sort statuses */
  getRank: function()
  {
    var additive = (this.count > 9) ? 9 : (this.count - 1);
    return this.complete ? (50 + additive) : (60 + additive);
  },

  getClassName: function()
  {
    var className = 'statusFlag';
    className += (this.count > 9) ? 'Plus' : this.count;
    if (this.complete)
    {
      className += 'Complete';
    }
    return className;
  },
  
  getTitle: function()
  {
    var title = this.count + ' Flag';
    if (this.count > 1)
    {
      title += 's';
    }
    
    if (this.complete)
    {
      title += ' Resolved';
    }
    return title;
  }
});

/* Status for a patient missing responses */
var StatusNoResponse = function()
{
  this.count = 1;
}

YAHOO.lang.extend(StatusNoResponse, Status,
{
  /* Used to compare and sort statuses */
  getRank: function()
  {
    var additive = (this.count > 9) ? 9 : (this.count - 1);
    return this.complete ? (30 + additive) : (40 + additive);
  },

  getClassName: function()
  {
    var className = 'statusNoResponse';
    className += (this.count > 9) ? 'Plus' : this.count;
    if (this.complete)
    {
      className += 'Complete';
    }
    return className;
  },
  
  getTitle: function()
  {
    var title = 'No Response for ' + this.count + ' Day';
    if (this.count > 1)
    {
      title += 's';
    }
    
    if (this.complete)
    {
      title += ' Resolved';
    }
    return title;
  }
});

/* Status for patient requiring review */
var StatusReview = function() { }

YAHOO.lang.extend(StatusReview, Status,
{
  /* Used to compare and sort statuses */
  getRank: function()
  {
    return this.complete ? 20 : 25;
  },

  getClassName: function()
  {
   if (this.complete)
   {
     return 'statusReviewComplete';
   }
   else
   {
     return 'statusReview';
   }
  },
  
  getTitle: function()
  {
    if (this.complete)
    {
      return 'Review Complete';
    }
    else 
    {
      return 'Review Scheduled';
    }
  }
});

/* Status for patient requiring setup */
var StatusSetup = function() { }

YAHOO.lang.extend(StatusSetup, Status,
{
  /* Used to compare and sort statuses */
  getRank: function()
  {
    return this.complete ? 10 : 15;
  },

  getClassName: function()
  {
    if (this.complete)
    {
      return 'statusSetupComplete';
    }
    else
    {
      return 'statusSetup';
    }
  },
  
  getTitle: function()
  {
    if (this.complete)
    {
      return 'Setup Complete';
    }
    else 
    {
      return 'Setup Required';
    }
  }
});

/* Popup module */
/* Composes YUI Panel and adds different collision detection and positioning functionality */
var Popup = function(popupId)
{
  // Number of pixels to offset the popup when aligning to the left or right. i.e. distance of the arrow from the edge.
  this.SIDE_OFFSET = 17; // 17 is the actual distance for the arrow.
  this.SIDE_OFFSET = 0;  // Zero provides the most clearance.
  // Number of milliseconds to delay before hiding the popup.
  this.HIDE_DELAY = 500;
  
  this.element = YAHOO.util.Dom.get(popupId);
  
  // Track the panel display class.
  this.currClass = this.element.className;
  if (this.currClass.match(/Small/))
  {
    this.isSmallPopup = true;
  }

  // Create a YUI panel.
  this.panel = new YAHOO.widget.Panel(popupId,
  {
    visible: false,
    close: false,
    underlay: 'none',
    effect: {effect:YAHOO.widget.ContainerEffect.FADE,duration:0.25}
  });
  this.panel.render(document.body);
  
  // Avoid disappearing if the user hovers over the panel.
  YAHOO.util.Event.addListener(this.element, 'mouseover', this.cancelHide, this, true);
  // Hide the panel if the user is no longer hovered over it.
  YAHOO.util.Event.addListener(this.element, 'mouseout', this.hide, this, true);
}

Popup.prototype =
{
  // Positions the popup relative to alignToEl
  // Includes collision detection to see if the panel should be offset up or down, left or right.
  show: function(alignToEl)
  {
    // Cancel any attempt to hide.
    this.cancelHide();

    var el = YAHOO.util.Dom.get(alignToEl);
    
    // Determine whether to display above or below el.
    var flagDown = this.collidesTop(el) || !this.collidesBottom(el);
    
    // Determine whether to display left or right.
    var flagRight = this.collidesLeft(el) || !this.collidesRight(el);
    
    // Calculate position and class name.
    var x, y;
    var elRegion = YAHOO.util.Dom.getRegion(el);
    var newClassName = 'popup';
    if (flagDown)
    {
      y = elRegion.bottom;
      newClassName += 'Down';
    }
    else
    {
      y = elRegion.top - this.element.offsetHeight;
      newClassName += 'Up';
    }
    
    if (flagRight)
    {
      x = elRegion.right - this.SIDE_OFFSET;
      newClassName += 'Left'; // Indicates side the arrow is on.
    }
    else
    {
      x = elRegion.left - this.element.offsetWidth + this.SIDE_OFFSET;
      newClassName += 'Right'; // Indicates side the arrow is on.
    }

    if (this.isSmallPopup)
    {
      newClassName += 'Small';
    }

    // Move the panel.    
    this.panel.moveTo(x, y);

    // Change the classname to match the position of the popup.
    YAHOO.util.Dom.removeClass(this.element, this.currClass);
    YAHOO.util.Dom.addClass(this.element, newClassName);
    this.currClass = newClassName;

    this.panel.show();
  },
  
  // Hide the panel.
  hide: function()
  {
    // Wait to hide in case user moused out accidentally.
    this.timer = setTimeout(this.hidePanel.bind(this), this.HIDE_DELAY);
  },
  
  hidePanel: function()
  {
    this.panel.hide();
  },
  
  cancelHide: function()
  {
    clearTimeout(this.timer);
  },
  
  // Collision detection. Does the popup hit the top of the window?
  collidesTop: function(el)
  {
    var elTop = YAHOO.util.Dom.getRegion(el).top;
    var viewportTop = YAHOO.util.Dom.getDocumentScrollTop();
    
    return (elTop - this.element.offsetHeight < viewportTop);
  },
  
  // Collision detection. Does the popup hit the bottom of the window?
  collidesBottom: function(el)
  {
    var elBottom = YAHOO.util.Dom.getRegion(el).bottom;
    var viewportBottom = YAHOO.util.Dom.getDocumentScrollTop() + YAHOO.util.Dom.getViewportHeight();
    
    return (elBottom + this.element.offsetHeight > viewportBottom);
  },
  
  // Collision detection. Does the popup hit the left edge of the window?
  collidesLeft: function(el)
  {
    var elRegion = YAHOO.util.Dom.getRegion(el);
    var viewportLeft = YAHOO.util.Dom.getDocumentScrollLeft();
    
    return ((elRegion.left - this.element.offsetWidth + this.SIDE_OFFSET) < viewportLeft) ;
  },
  
  // Collision detection. Does the popup hit the right edge of the window?
  collidesRight: function(el)
  {
    var elRegion = YAHOO.util.Dom.getRegion(el);
    var viewportRight = YAHOO.util.Dom.getDocumentScrollLeft() + YAHOO.util.Dom.getViewportWidth();
    
    return ((elRegion.right + this.element.offsetWidth - this.SIDE_OFFSET) > viewportRight);
  }
}

// Specialized use of Popup for showing and hiding the popup when hovering over a series of elements.
var HoverPopup = function(targetEl, popup)
{
  // The element that shows the popup on hover.
  this.targetEl = YAHOO.util.Dom.get(targetEl);
  
  // A global popup to use for the hover.
  this.popup = popup;
  
  YAHOO.util.Event.addListener(this.targetEl, 'mouseover', this.showPopup, this, true);
  YAHOO.util.Event.addListener(this.targetEl, 'mouseout', this.hidePopup, this, true);
}

HoverPopup.prototype =
{
  showPopup: function(e)
  {
    this.updatePopup();
    this.popup.show(this.targetEl);
  },
  
  hidePopup: function()
  {
    this.popup.hide();
  },
  
  updatePopup: function()
  {
    // To be overriden by subclasses.
  }
}

// Specialized use of Popup for hovering over a patient's name.
var PatientHoverPopup = function(targetEl, popup, patient)
{
  PatientHoverPopup.superclass.constructor.call(this, targetEl, popup);

  // The patient data object.
  this.patient = patient;
}


YAHOO.lang.extend(PatientHoverPopup, HoverPopup,
{
  updatePopup: function()
  {
    var button = YAHOO.util.Dom.getElementsByClassName('buttonPrefWide', 'a', this.popup.element)[0];
    var url = (this.patient.status instanceof StatusSetup) ? 'PatientProfilePrint.jsp?pplid=' : 'PatientGraphPrint.jsp?pplid=';
    button.setAttribute('href', url + this.patient.id);
    
    if (this.patient.contact)
    {
      var primaryContact = YAHOO.util.Dom.getElementsByClassName('primaryContact', 'td', this.popup.element)[0];
      primaryContact.innerHTML = formatPhone(this.patient.contact[0]);
      
      var secondaryContact = YAHOO.util.Dom.getElementsByClassName('secondaryContact', 'td', this.popup.element)[0];
      secondaryContact.innerHTML = formatPhone(this.patient.contact[1]);
    }
    
    if (this.patient.preferredCallTime)
    {
      var preferredCallTime = YAHOO.util.Dom.getElementsByClassName('preferredCallTime', 'td', this.popup.element)[0];
      preferredCallTime.innerHTML = this.patient.preferredCallTime;
    }
    
    var patientDob = this.patient.getDob ? this.patient.getDob() : '';
    if (patientDob != '')
    {
      var dob = YAHOO.util.Dom.getElementsByClassName('dob', 'td', this.popup.element)[0];
      dob.innerHTML = DateUtil.getDateShortString(patientDob);
    }
    
    if (this.patient.diagnosis)
    {
      var diagnosis = YAHOO.util.Dom.getElementsByClassName('diagnosis', 'td', this.popup.element)[0];
      diagnosis.innerHTML = this.patient.diagnosis;
    }
    
    if (this.patient.id)
    {
          var zumeLifeId = YAHOO.util.Dom.getElementsByClassName('zumeLifeId', 'td', this.popup.element)[0];
          zumeLifeId.innerHTML = this.patient.id;
    }
  }
});

var ReminderHoverPopup = function(targetEl, popup)
{
  //var targetEl = YAHOO.util.Dom.get('rs_'+pid);
  //var popup = YAHOO.util.Dom.get(popupname);
  
  ReminderHoverPopup.superclass.constructor.call(this, targetEl, popup);
  // The reminder  object.
  this.remobj = targetEl;  
}
YAHOO.lang.extend(ReminderHoverPopup, HoverPopup,
{
  updatePopup: function()
  {
    var htm_reminder = YAHOO.util.Dom.getElementsByClassName('reminder', 'div', this.popup.element)[0];
    var htm_startdate = YAHOO.util.Dom.getElementsByClassName('rstartdate', 'div', this.popup.element)[0];
    var htm_enddate = YAHOO.util.Dom.getElementsByClassName('renddate', 'div', this.popup.element)[0];
    var htm_type = YAHOO.util.Dom.getElementsByClassName('rtype', 'div', this.popup.element)[0];
    var htm_weeks = YAHOO.util.Dom.getElementsByClassName('rweeks', 'div', this.popup.element)[0];
    var htm_times = YAHOO.util.Dom.getElementsByClassName('rtimes', 'div', this.popup.element)[0];
    
    if(this.remobj.attributes['reminder'].value == 'on')
    {
    	htm_reminder.innerHTML = 'Reminder for: '+this.remobj.attributes['itemName'].value;
    	htm_times.innerHTML = 'Reminder Times: '+this.remobj.attributes['reminderTimes'].value;
    	htm_startdate.innerHTML = 'Start Date: '+this.remobj.attributes['startDate'].value;
    	if(this.remobj.attributes['endDate'].value=='null')
    	htm_enddate.innerHTML = 'End Date: ';
    	else
    	htm_enddate.innerHTML = 'End Date: '+this.remobj.attributes['endDate'].value;
    	
    	if(this.remobj.attributes['repeatType'].value=='ED')
    	{
    		htm_type.innerHTML = 'Daily: repeat every '+this.remobj.attributes['repeatNum'].value+ ' day';
    		htm_weeks.innerHTML = '';
    	}
    	if(this.remobj.attributes['repeatType'].value=='EW')
    	{
    		htm_type.innerHTML = 'Weekly: repeat every '+this.remobj.attributes['repeatNum'].value+ ' week, on';
    	    htm_weeks.innerHTML = Capitalize(this.remobj.attributes['weekDays'].value);
    	}
    }
    else
    {
    	htm_reminder.innerHTML = 'No-Reminder';
    	htm_times.innerHTML = '';
    	htm_type.innerHTML = '';
    	htm_weeks.innerHTML = '';
    	htm_startdate.innerHTML = '';
    	htm_enddate.innerHTML = '';
    	
    }
    
  }
});
// Specialized use of Popup for hovering over a status.
var StatusHoverPopup = function(targetEl, popup, patient)
{
  StatusHoverPopup.superclass.constructor.call(this, targetEl, popup);

  // The patient data object.
  this.patient = patient;  
}

YAHOO.lang.extend(StatusHoverPopup, HoverPopup,
{
  updatePopup: function()
  {
    var button = YAHOO.util.Dom.getElementsByClassName('buttonPrefWide', 'a', this.popup.element)[0];
    button.setAttribute('href', 'PatientGraphPrint.jsp?pplid=' + this.patient.id);
    
    var status = YAHOO.util.Dom.getElementsByClassName('status', 'span', this.popup.element)[0];
    status.innerHTML = (this.patient.status.complete) ? 'Resolved' : 'Unresolved';
  }
});

// Specialized use of Popup for hovering over actions taken.
var ActionsHoverPopup = function(targetEl, popup, form, patient)
{
  ActionsHoverPopup.superclass.constructor.call(this, targetEl, popup);

  // The patient data object.
  this.patient = patient;  
  this.form = form;
}

YAHOO.lang.extend(ActionsHoverPopup, HoverPopup,
{
  updatePopup: function()
  {
    var button = YAHOO.util.Dom.getElementsByClassName('buttonPrefWide', 'a', this.popup.element)[0];
    YAHOO.util.Event.removeListener(button, 'click');
    YAHOO.util.Event.addListener(button, 'click', this.displayDialog, this, true);
    
    // Add rows to the actions table for each action taken.
    var actionsTable = YAHOO.util.Dom.getElementsByClassName('actions', 'table', this.popup.element)[0];
    this.deleteRows(actionsTable);
    
    var actionCount = 0;

    /* Reviewed */
    if (this.patient.actions.hasAction(ActionsTaken.REVIEW))
    {
      var tableCell = this.createActionRow(actionsTable);
      this.patient.actions.renderReview(tableCell);

      var desc = ' Reviewed';      
      if (this.patient.actions.complete)
      {
        desc += ' and Resolved';
      }
      
      this.appendDescription(tableCell, desc);
      actionCount++;
    }

    /* Contacted */
    if (this.patient.actions.hasAction(ActionsTaken.CONTACT))
    {
      var tableCell = this.createActionRow(actionsTable);
      this.patient.actions.renderContact(tableCell);

      var desc = 'Contacted';      
      if (this.patient.actions.complete)
      {
        desc += ' and Resolved';
      }
      
      this.appendDescription(tableCell, desc);
      actionCount++;
    }
    
    /* Only Resolved */
    if (this.patient.actions.complete)
    {
    	var tableCell = this.createActionRow(actionsTable);
	this.patient.actions.renderNoAction(tableCell);
	
    	var desc = 'Resolved'; 
    	this.appendDescription(tableCell, desc);
        actionCount++;
        
    }
    /* No actions taken */
    if (actionCount == 0)
    {
      var tableCell = this.createActionRow(actionsTable);
      this.patient.actions.renderNoAction(tableCell);
      this.appendDescription(tableCell, 'No Action Taken');
    }
  },
  
  /* Event handler for Edit Actions button */
  displayDialog: function(e)
  {
    this.hidePopup();
    this.form.setPatient(this.patient);
    this.form.dialog.show();
  },
  
  /* Deletes all the rows in a table */
  deleteRows: function(tableEl)
  {
    // Save the rows in a separate array because if we loop through table.rows directly, the collection changes with each deletion.
    var deleteRows = [];
    for (var i = 0; i < tableEl.rows.length; i++)
    {
      deleteRows[deleteRows.length] = tableEl.rows[i];
    }
    
    for (var i = 0; i < deleteRows.length; i++)
    {
      var row = deleteRows[i];
      row.parentNode.removeChild(row);
    }
  },
  
  /* Creates a row for displaying a single action */
  createActionRow: function(tableEl)
  {
    var tableRow = tableEl.insertRow(tableEl.rows.length);
    return tableRow.insertCell(tableRow.cells.length);
  },
  
  /* Appends a description to the cell for an action. Wraps the description in a span */
  appendDescription: function(tableCellEl, desc)
  {
    var descSpan = document.createElement('span');
    descSpan.innerHTML = desc;
    tableCellEl.appendChild(descSpan);
  }
});

var TableDataHoverPopup = function(targetEl, popup, displayData)
{
  TableDataHoverPopup.superclass.constructor.call(this, targetEl, popup);
  
  this.displayData = displayData;
}

YAHOO.lang.extend(TableDataHoverPopup, HoverPopup,
{
  updatePopup: function()
  {
    var body = YAHOO.util.Dom.getElementsByClassName('mid', 'div', this.popup.element)[0];
    body.innerHTML = this.displayData;
  }
});

var JournalEntryHoverPopup = function(targetEl, popup, form, journalEntry)
{
  JournalEntryHoverPopup.superclass.constructor.call(this, targetEl, popup);

  // The journal entry data object.
  this.journalEntry = journalEntry;  
  this.form = form;
  // Get a handle to the listing table element.
  var listingTableEl = YAHOO.util.Dom.getElementsByClassName('listing', 'table', this.popup.element)[0];
  this.listingTable = new DataTable(listingTableEl, []);
  var meallistingTableEl = YAHOO.util.Dom.getElementsByClassName('meallisting', 'table', this.popup.element)[0];
  this.meallistingTable = new DataTable(meallistingTableEl, []);
}

YAHOO.lang.extend(JournalEntryHoverPopup, HoverPopup,
{
  updatePopup: function()
  {
    var button = YAHOO.util.Dom.getElementsByClassName('buttonPref', 'a', this.popup.element)[0];
    //YAHOO.util.Event.removeListener(button, 'click');
    
    var type = this.journalEntry.type.toLowerCase();
    var jSource = this.journalEntry.source.toLowerCase();
    //button.setAttribute("disabled","true");
    switch (type)
    {
        case 'food':
          if (journalForm.options.hasFoodJournal || (journalForm.options.hasMealTracker )||(journalForm.options.hasCalorieEstimator))
          {
           YAHOO.util.Event.addListener(button, 'click', this.displayDialog, this, true);
          }
          break;
        case 'exercise':
          if (journalForm.options.hasExerciseJournal || (journalForm.options.hasActivityTracker))
          {
           YAHOO.util.Event.addListener(button, 'click', this.displayDialog, this, true);
          }
          break;
       case 'life':
          if (journalForm.options.hasLifeJournal)
          {
           YAHOO.util.Event.addListener(button, 'click', this.displayDialog, this, true);
          }
          break;
    }    

    var headerEl = this.popup.element.getElementsByTagName('h2')[0];
    var theDate = this.journalEntry.getDate();
    headerEl.innerHTML = theDate.getDate() + ' ' + DateUtil.getMonthShortString(theDate) + ', <span>' + DateUtil.get12HourTimeString(theDate) + '</span>';

    var descEl = YAHOO.util.Dom.getElementsByClassName('description', 'td', this.popup.element)[0];
    descEl.innerHTML = this.journalEntry.getFullDescription();
	//For meal tracking
	var meallistingTable
	var mealheaderNameEl = YAHOO.util.Dom.getElementsByClassName('name', 'th', this.meallistingTable.header)[0];
    var mealheaderValueEl = YAHOO.util.Dom.getElementsByClassName('value', 'th', this.meallistingTable.header)[0];
    var mealheaderMeasureEl = YAHOO.util.Dom.getElementsByClassName('measure', 'th', this.meallistingTable.header)[0];
	
    // Get the table header and summary rows.
    var headerNameEl = YAHOO.util.Dom.getElementsByClassName('name', 'th', this.listingTable.header)[0];
    var headerValueEl = YAHOO.util.Dom.getElementsByClassName('value', 'th', this.listingTable.header)[0];
    var headerMeasureEl = YAHOO.util.Dom.getElementsByClassName('measure', 'th', this.listingTable.header)[0];

    var totalValueEl = YAHOO.util.Dom.getElementsByClassName('value', 'th', this.listingTable.summary)[0];
    var totalMeasureEl = YAHOO.util.Dom.getElementsByClassName('measure', 'th', this.listingTable.summary)[0];

    // Update the table header and summary rows.
    var entryType = this.journalEntry.type.toLowerCase();
    if (entryType == 'food')
    {
      if (this.journalEntry.metrics)
      {
      	this.meallistingTable.table.style.display = '';
		
        mealheaderNameEl.innerHTML = 'Metric';
        mealheaderValueEl.innerHTML = '';
        mealheaderValueEl.innerHTML = 'Measure';

        // Fill in the item details.
        this.meallistingTable.displayData(this.journalEntry.metrics, this.fillFoodMealDataRow);
      }
      else
      {
      	this.meallistingTable.table.style.display = 'none';
      }
      if (this.journalEntry.calorieItems)
      {
        this.listingTable.table.style.display = '';
		
        headerNameEl.innerHTML = 'Food';
        headerValueEl.innerHTML = 'Servings';
        headerMeasureEl.innerHTML = 'Calories';
        
        totalValueEl.innerHTML = this.journalEntry.getTotalServings();
        totalMeasureEl.innerHTML = this.journalEntry.getTotalCalories();

        // Fill in the item details.
        this.listingTable.displayData(this.journalEntry.calorieItems, this.fillFoodDataRow);
      }
      else
      {
        this.listingTable.table.style.display = 'none';
      }
    }
    else if (entryType == 'life')
    {
        this.listingTable.table.style.display = 'none';
        this.meallistingTable.table.style.display = 'none';
    }
    else if (entryType == 'exercise')
    {
      if (this.journalEntry.activities)
      {
        this.listingTable.table.style.display = '';
		this.meallistingTable.table.style.display = 'none';

        headerNameEl.innerHTML = 'Activity';
        headerValueEl.innerHTML = '';
        headerMeasureEl.innerHTML = 'Minutes';
        
        totalValueEl.innerHTML = '';
        totalMeasureEl.innerHTML = this.journalEntry.getTotalMinutes();

        // Fill in the item details.
        this.listingTable.displayData(this.journalEntry.activities, this.fillExerciseDataRow);
      }
      else
      {
        this.listingTable.table.style.display = 'none';
        this.meallistingTable.table.style.display = 'none';
      }
    }
  },
  
  fillFoodMealDataRow: function(row, metric)
  {
    var nameEl = YAHOO.util.Dom.getElementsByClassName('name', 'td', row)[0];
    nameEl.innerHTML = metric.name;      
    var valueEl = YAHOO.util.Dom.getElementsByClassName('value', 'td', row)[0];
    valueEl.innerHTMl = '';      
    var measureEl = YAHOO.util.Dom.getElementsByClassName('measure', 'td', row)[0];
    measureEl.innerHTML = metric.value; 
  },
  
  fillFoodDataRow: function(row, calorieItem)
  {
    var nameEl = YAHOO.util.Dom.getElementsByClassName('name', 'td', row)[0];
    nameEl.innerHTML = calorieItem.name;
    var valueEl = YAHOO.util.Dom.getElementsByClassName('value', 'td', row)[0];
    valueEl.innerHTML = calorieItem.value;
    var measureEl = YAHOO.util.Dom.getElementsByClassName('measure', 'td', row)[0];
    measureEl.innerHTML = calorieItem.measure;
  },
  
  fillExerciseDataRow: function(row, activity)
  {
    var nameEl = YAHOO.util.Dom.getElementsByClassName('name', 'td', row)[0];
    nameEl.innerHTML = activity.displayName;      
    var valueEl = YAHOO.util.Dom.getElementsByClassName('value', 'td', row)[0];
    valueEl.innerHTMl = '';      
    var measureEl = YAHOO.util.Dom.getElementsByClassName('measure', 'td', row)[0];
    measureEl.innerHTML = activity.value; 
  },
  
  /* Event handler for Edit button */
  displayDialog: function(e)
  {
    this.hidePopup();
    this.form.setJournalEntry(this.journalEntry);
    this.form.dialog.show();
    
  }
});

/* Dialog box. Composes a YUI panel */
/*
  Accepts a callbacks object containing callback methods for:
  initialize - Called when initializing the Dialog
  show - Called when the Dialog is shown
  hide - Called when the Dialog is hidden
  onSubmit - Called when the form is submitted. Passes the dialog box form as the first argument to the callback.
*/
var Dialog = function(dialogId, callbacks)
{
  // Create the panel.
  this.panel = new YAHOO.widget.Panel(dialogId,
  {
    visible: false,
    close: false,
    underlay: 'none',
    modal: true,
    fixedcenter: true,
    draggable : false,
    effect: {effect:YAHOO.widget.ContainerEffect.FADE,duration:0.25}
  });
  this.panel.render(document.body);
  
  // Add shortcut access to the DOM element.
  this.element = this.panel.element;
  
  this.callbacks = callbacks;
  
  // Get the form.
  this.form = this.panel.element.getElementsByTagName('form')[0];
  
  // Get the buttons.
  this.closeBtn = YAHOO.util.Dom.getElementsByClassName('close', 'a', this.panel.element)[0];
  this.cancelBtn = YAHOO.util.Dom.getElementsByClassName('buttonCancel', 'input', this.panel.element)[0];
  this.submitBtn = YAHOO.util.Dom.getElementsByClassName('submit', 'input', this.panel.element)[0];

  // Assign event handlers.
  YAHOO.util.Event.addListener(this.closeBtn, 'click', this.hide, this, true);
  YAHOO.util.Event.addListener(this.cancelBtn, 'click', this.hide, this, true);
  YAHOO.util.Event.addListener(this.submitBtn, 'click', this.onSubmit, this, true);
  
  /* Create a custom event for a cancel */
  this.oncancel = new YAHOO.util.CustomEvent('cancel', this);
  
  /* Create a custom event for a submit */
  this.onsubmit = new YAHOO.util.CustomEvent('submit', this);
  
  /* Run the initialize callback if any */
  if (this.callbacks.initialize)
  {
    this.callbacks.initialize.call(this);
  }
}

Dialog.prototype =
{
  show: function()
  {
    if (this.callbacks.show)
    {
      this.callbacks.show.call(this);
    }
    this.panel.show();
  },
  
  hide: function(e)
  {
    /* Fire custom event */
    this.oncancel.fire();

    if (this.callbacks.hide)
    {
      this.callbacks.hide.call(this);
    }
    this.panel.hide();

    /* Disable default link behavior */
    YAHOO.util.Event.stopEvent(e);
  },
  
  onSubmit: function(e)
  {
    var returnVal = true;

    /* Fire custom event */
    returnVal = returnVal && this.onsubmit.fire(this.form);

    if (this.callbacks.onSubmit)
    {
      returnVal = returnVal && this.callbacks.onSubmit.call(this, this.form);
    }

    if (returnVal)
    {
      this.panel.hide();
    }

    /* Disable default link behavior */
    YAHOO.util.Event.stopEvent(e);
  }
}

/* Check all checkbox widget. Manages an array of checkbox items with a check all checkbox. */
var CheckAllCheckbox = function(checkAllId, checkItemIds)
{
  this.checkAll = YAHOO.util.Dom.get(checkAllId);
  YAHOO.util.Event.addListener(this.checkAll, 'click', this.clickCheckAll, this, true);
  
  this.checkItems = [];
  for (var i = 0; i < checkItemIds.length; i++)
  {
    var checkItem = YAHOO.util.Dom.get(checkItemIds[i]);
    this.checkItems[i] = checkItem;
    YAHOO.util.Event.addListener(checkItem, 'click', this.clickItem, i, this);    
  }
}

CheckAllCheckbox.prototype =
{
  /* Event handler for check all checkbox. */
  /* Checks all of the checkbox items if check all is checked. Unchecks all items if check all is unchecked. */
  clickCheckAll: function(e)
  {
    for (var i = 0; i < this.checkItems.length; i++)
    {
      this.checkItems[i].checked = this.checkAll.checked;
    }
  },
  
  /* Event handler for check items. Updates the check all box. */
  clickItem: function(e, itemIndex)
  {
    this.updateCheckAll();
  },
  
  /* Checks the check all checkbox if all items are checked. Unchecks the check all checkbox otherwise. */
  updateCheckAll: function()
  {
    var allChecked = true;
    for (var i = 0; i < this.checkItems.length; i++)
    {
      if (!this.checkItems[i].checked)
      {
        allChecked = false;
        break;
      }
    }
    this.checkAll.checked = allChecked;
  }
}

/* HSQ Form*/
var HSQForm = function(formId,pplid)
{
  this.LOAD_METHOD = '';
  this.SAVE_METHOD = 'SAVE_EDIT_HSQ';
  this.SERVLET = 'MainServlet';
  this.AUTHOR_TYPE = 'NURSE';
  this.DELETE='';
  this.form = YAHOO.util.Dom.get(formId);
  this.dialog = new Dialog(formId, {});
  this.PID = "-1";
  this.peopleid = pplid; 
	/* Assign an event handler for a dialog submit. */
  	this.dialog.onsubmit.subscribe(this.onsubmit, this);

  // Get the form elements.
  this.Name 	= YAHOO.util.Dom.get('hsqName');
  this.Desc 	= YAHOO.util.Dom.get('hsqDesc');
  this.Ans1 	= YAHOO.util.Dom.get('hsqAns1');
  this.Ans2 	= YAHOO.util.Dom.get('hsqAns2');
  this.Ans3 	= YAHOO.util.Dom.get('hsqAns3');
  this.Ans4 	= YAHOO.util.Dom.get('hsqAns4');
  this.Ans5 	= YAHOO.util.Dom.get('hsqAns5');
  this.btnDelete 	= YAHOO.util.Dom.get('btnDelete');
  
  YAHOO.util.Event.addListener(this.btnDelete, 'click', this.DeleteHSQ, this, true);
  
}
HSQForm.prototype =
{
	DeleteHSQ:function()
	{
		this.DELETE="DELETE";
		this.saveForm();
	},
	initializeForm: function(pid,name,desc,ans1,ans2,ans3,ans4,ans5)
	{
		this.PID = pid;
		this.Name.value = name;
      	this.Desc.value = desc;
      	this.Ans1.value = ans5;
      	this.Ans2.value = ans4;
      	this.Ans3.value = ans3;
      	this.Ans4.value = ans2;
      	this.Ans5.value = ans1;
	},
  
 /* Validates the form */
  isFormValid: function()
  {
	  
  	if(this.Name.value=="")
  	{
  		alert("Name can not be empty");
  		this.Name.focus();
  		return false;
  	}
  	else
  	{
  		if(this.Name.value.length>25)
  		{
  			alert("Name can not be more then 25 characters");
  			this.Name.focus();
  			return false;
  		}
  	}
  	if(this.Desc.value=="")
  	{
  		alert("Question can not be empty");
  		this.Desc.focus();
  		return false;
  	}
  	else
  	{
  		if(this.Desc.value.length>100)
  		{
  			alert("Question can not be more then 100 characters");
  			this.Desc.focus();
  			return false;
  		}
  	}
  	if(this.Ans1.value=="" && this.Ans2.value=="" && this.Ans3.value=="" && this.Ans4.value=="" && this.Ans5.value=="")
  	{
  		alert("All answers can not be empty");
  		this.Ans1.focus();
  		return false;
  	}
  	else
  	{
  		if(this.Ans1.value.length>25||this.Ans2.value.length>25||this.Ans3.value.length>25||this.Ans4.value.length>25||this.Ans5.value.length>25)
  		{
  			alert("Answer can not be more then 25 characters");
  			this.Desc.focus();
  			return false;
  		}
  	}
  	   
  	return true;
  	
  },
   /* Saves the form */
  saveForm: function()
  {
		// Validate the form first.
	    if (!this.isFormValid()){
	      return false;
	    }
	
    // Create the request string.
    var requestString = formatXmlRequest(this.SAVE_METHOD,
    {
      pid: this.PID,
      peopleid: this.peopleid,
      name: this.Name.value,
      desc: this.Desc.value,
      ans1: this.Ans1.value,
      ans2: this.Ans2.value,
      ans3: this.Ans3.value,
      ans4: this.Ans4.value,
      ans5: this.Ans5.value,
      action:this.DELETE,
    });
    
    // Post the AJAX.
    var request = YAHOO.util.Connect.asyncRequest('POST', this.SERVLET,
    {
      success: this.reportSuccess,
      failure: this.reportFailure,
      argument: [this]
    }, requestString);
    
    return true;
  },
  
  /* The AJAX failed. Tell the user */
  reportFailure: function(obj)
  {
    alert('Unable to save new schedule. Please try again later.');
  },
  
  /* The AJAX succeeded. Reload the page to show the new review date. */ 
  reportSuccess: function(obj)
  {
    // refresh the page.
    window.location.reload(false);
  },
  
  /* Event handler for a dialog submit. */
  onsubmit: function(eventName, args, me)
  {
  	return me.saveForm();
  }
	
}

/* Reminder Form*/
var ReminderForm = function(formId)
{
  this.LOAD_METHOD = 'getpeopledata';
  this.SAVE_METHOD = 'SAVE_EDIT_REVIEW_SCHE';
  this.SERVLET = 'MainServlet';
  this.AUTHOR_TYPE = 'NURSE';
  
  this.form = YAHOO.util.Dom.get(formId);
  this.dialog = new Dialog(formId, {});
  this.PID = "";
  
  this.ReminderType = "";
  this.ReminderNum = "";
  this.StartDate = "";
  this.EndDate = "";
  this.WeekDays = "";
  this.ReminderTimes = "";
  this.rsobj;
  
  /* Assign an event handler for a dialog submit. */
  this.dialog.onsubmit.subscribe(this.onsubmit, this);

  // Get the form elements.
  this.reminderCheckbox = YAHOO.util.Dom.get('reminder');
  this.reminderTypeEDRadio = YAHOO.util.Dom.get('rtype_ed');
  this.reminderTypeEWRadio = YAHOO.util.Dom.get('rtype_ew');
  this.reminderNumEDInput = YAHOO.util.Dom.get('rdtypevalue');
  this.reminderNumEWInput = YAHOO.util.Dom.get('rwtypevalue');
  this.divStartDate = YAHOO.util.Dom.get('divStartDate');
  this.divEndDate = YAHOO.util.Dom.get('divEndDate');
  this.reminderItemName= YAHOO.util.Dom.get('reminderItemName');
  
  YAHOO.util.Event.addListener(this.reminderTypeEDRadio, 'click', this.changeFrequency, this, true);
  YAHOO.util.Event.addListener(this.reminderTypeEDRadio, 'change', this.changeFrequency, this, true);
  YAHOO.util.Event.addListener(this.reminderTypeEWRadio, 'click', this.changeFrequency, this, true);
  YAHOO.util.Event.addListener(this.reminderTypeEWRadio, 'change', this.changeFrequency, this, true);
  
  // Get the form elements.
  this.calendar1 = new PopupYUICalendar(
    YAHOO.util.Dom.getElementsByClassName('calendar', 'a', this.form)[0],
    YAHOO.util.Dom.getElementsByClassName('calWidget', 'div', this.form)[0]
  );
  this.calendar2 = new PopupYUICalendar(
    YAHOO.util.Dom.getElementsByClassName('calendar', 'a', this.form)[1],
    YAHOO.util.Dom.getElementsByClassName('calWidget', 'div', this.form)[1]
  );
  
  this.calendar1.onchangedate.subscribe(this.calendarSelected1, this);
  this.calendar2.onchangedate.subscribe(this.calendarSelected2, this);
  
  //this.dayLabels = YAHOO.util.Dom.getElementsByClassName('dayLabels', 'tr', this.form)[0];
  //this.daySelection = YAHOO.util.Dom.getElementsByClassName('daySelection', 'tr', this.form)[0];
  //this.dateSelection = YAHOO.util.Dom.getElementsByClassName('dateSelection', 'tr', this.form)[0];
  
  this.inputReminders = [];
  this.inputReminders[0] = YAHOO.util.Dom.get('time-field-messages');
  for(var i=1;i<10;i++)
  {
  	this.inputReminders[i] = YAHOO.util.Dom.get('time-field'+i); 
  }
  
  var checkboxDays = ['rsun', 'rmon', 'rtue', 'rwed', 'rthu', 'rfri', 'rsat'];
  this.dayCheckboxes = [];
  for (var i = 0; i < checkboxDays.length; i++)
  {
    this.dayCheckboxes[i] = YAHOO.util.Dom.get(checkboxDays[i]);
  }
  
  this.allDaysCheckbox = new CheckAllCheckbox('rall', this.dayCheckboxes);
  
  //this.monthDate = YAHOO.util.Dom.get('monthDate');
  
  // Preset form value by getting data via AJAX.
  //this.initializeForm();
}
ReminderForm.prototype =
{
	initializeForm: function(obj,pid,itemName,reminder,repeatType,repeatNum,startDate,endDate,weekDays,reminderTimes)
	{
	  this.rsobj = obj;
	  this.PID = pid;
	  this.ReminderType = repeatType;
	  this.ReminderNum = repeatNum;
	  if(this.ReminderNum=="")
	  	this.ReminderNum = 1;
	  this.reminderItemName.innerHTML = itemName;
	  if(startDate==""||startDate=="null") 
	  	this.StartDate = new Date();
	  else
	  	this.StartDate = DateUtil.setDate(startDate);
	  
	  if(endDate==""||endDate=="null") 
	  	this.EndDate = null;
	  else
	  	this.EndDate = DateUtil.setDate(endDate);
	  
	  this.WeekDays = weekDays;
	  this.ReminderTimes = reminderTimes;

		//Reset Reminder time values
		for(var i=1;i<this.inputReminders.length;i++)
		{
			this.inputReminders[i].value = "";
		}
		for (var i = 0; i < this.dayCheckboxes.length; i++)
	    {
	      var checkbox = this.dayCheckboxes[i];
	      checkbox.checked = false;
	    }
	  
	  //PENDING: set start and end dates
	  this.calendar1.setDate(this.StartDate);
	  this.divStartDate.innerHTML = DateUtil.getDateShortString(this.StartDate);
	  
	  if(this.EndDate!=null)
	  {
	  	this.calendar2.setDate(this.EndDate);
	  	this.divEndDate.innerHTML = DateUtil.getDateShortString(this.EndDate);
	  
	  }
	  if(reminder=='on')
	  	this.reminderCheckbox.checked = true;
	  else
	  	this.reminderCheckbox.checked = false;
	  	
	  if(this.ReminderType.toUpperCase()=='ED')
	  {
	  	this.reminderCheckbox.checked = true;
	  	this.reminderTypeEDRadio.checked = true;
	  	setSelectValue(this.reminderNumEDInput, this.ReminderNum);
	  }
	  else if(this.ReminderType.toUpperCase()=='EW')
	  {
	  	this.reminderCheckbox.checked = true;
	  	this.reminderTypeEWRadio.checked = true;
	  	setSelectValue(this.reminderNumEWInput, this.ReminderNum);
		for (var i = 0; i < this.dayCheckboxes.length; i++)
	    {
	      var checkbox = this.dayCheckboxes[i];
	      if (this.WeekDays.indexOf(checkbox.value) > -1)
	      {
	        checkbox.checked = true;
	      }
	    }
	  }
	  else 
	  {
	  	this.reminderCheckbox.checked = true;
	  	this.reminderTypeEDRadio.checked = true;
	  	this.reminderTypeEWRadio.checked = false;
	  	this.reminderNumEDInput.value = "1";
	  	this.reminderNumEWInput.value = "";
	  	setSelectValue(this.reminderNumEDInput, this.ReminderNum);
	  }
      
	  var reminders = this.ReminderTimes.split(",")
	  for(var i=0;i<reminders.length;i++)
	  {
	  	if(i<=(this.inputReminders.length-2))
	  		this.inputReminders[i+1].value = Trim(reminders[i]);
	  }
      this.changeFrequency();
    
      this.allDaysCheckbox.updateCheckAll();
	  
	},
	
  /* Event handler for a change in the reminder frequency */
  changeFrequency: function(e)
  {
    if (this.reminderTypeEDRadio.checked)
    {
      this.ReminderType = 'ED';
      this.reminderNumEDInput.disabled = false;
      this.reminderNumEWInput.disabled = true;
      this.allDaysCheckbox.checkAll.disabled = true;
      	for (var i = 0; i < this.dayCheckboxes.length; i++)
	    {
	      var checkbox = this.dayCheckboxes[i];
	      checkbox.disabled = true;
	    }
	    
    }
    else
    {
      this.ReminderType = 'EW';
      this.reminderNumEDInput.disabled = true;
      this.reminderNumEWInput.disabled = false;
      this.allDaysCheckbox.checkAll.disabled = false;
      	for (var i = 0; i < this.dayCheckboxes.length; i++)
	    {
	      var checkbox = this.dayCheckboxes[i];
	      checkbox.disabled = false;
	    }
    }
  },
  /* Event handler for calendar selection. */
  calendarSelected1: function(eventName, args, me)
  {
    me.StartDate = args[0];
    me.divStartDate.innerHTML = DateUtil.getDateShortString(me.StartDate);
  },
  calendarSelected2: function(eventName, args, me)
  {
    me.EndDate = args[0];
    me.divEndDate.innerHTML = DateUtil.getDateShortString(me.EndDate);
  },

  /* Validates the form */
  isFormValid: function()
  {
    if (this.reminderCheckbox.checked)
    {
        if(this.ReminderType.toUpperCase()=='ED')
		{
			/*
	    	if(!isNumericValue(Trim(this.ReminderNum),0,32))
		  	{
		  		alert("Please select repeat count between 1 and 31");	
      			return false;
		  	}
		  	*/
		  	if(Trim(this.ReminderTimes)=="")
		  	{
		  		alert("Please add atleast one reminder time");	
      			return false;
		  	}
		  	return true;
		}
		else if(this.ReminderType.toUpperCase()=='EW')
	    {
	    	/*
	    	if(!isNumericValue(Trim(this.ReminderNum),0,9))
		  	{
		  		alert("Please select repeat count between 1 and 8");	
      			return false;
		  	}
		  	*/
		  	if(Trim(this.WeekDays)=="")
		  	{
		  		alert("Please select atleast one week day");	
      			return false;
		  	}
		  	if(Trim(this.ReminderTimes)=="")
		  	{
		  		alert("Please add atleast one reminder time");	
      			return false;
		  	}
		  	return true;
		}
		else
		{
			alert("Please select frequency or uncheck the reminder checkbox!");	
      		return false;
		}
    
    }
    else
    {
    	this.ReminderType = "";
    	this.ReminderTimes = "";
    	this.WeekDays = "";
    	this.ReminderNum = "";
    	alert("No Reminder set");	
      	return true;
    }
  },
  
  /* Saves the form */
  saveForm: function()
  {
	    this.ReminderTimes="";
		for(var i=1;i<this.inputReminders.length;i++)
		{
			if(Trim(this.inputReminders[i].value) != "")
			{
				this.ReminderTimes += this.inputReminders[i].value + ", ";
			}
		}
	    this.WeekDays = "";
	    
	    if(this.ReminderType.toUpperCase()=='ED')
		{
		  	this.ReminderNum = getSelectValue(this.reminderNumEDInput) ;
		}
		else if(this.ReminderType.toUpperCase()=='EW')
	    {
	    	this.ReminderNum = getSelectValue(this.reminderNumEWInput);
	    	for (var i = 0; i < this.dayCheckboxes.length; i++)
	      	{
	        	var checkbox = this.dayCheckboxes[i];
	        	if (checkbox.checked)
	        	{
	        		this.WeekDays += checkbox.value + ", ";
	        	}
	      	}
	    }
	    else
	    {
	    	this.ReminderNum = "";
	    }
    
    	// Validate the form first.
	    if (!this.isFormValid())
	    {
	      return false;
	    }
	
	  	// save values to Reminder Schedule obj as attributes
	  	this.rsobj.attributes['repeatType'].value = this.ReminderType;
	  	this.rsobj.attributes['repeatNum'].value = this.ReminderNum;
	  	this.rsobj.attributes['startDate'].value = DateUtil.getDateYYYYMMDDDashed(this.StartDate);
	  	if(this.EndDate==null || this.EndDate=='undefined'||this.EndDate==''||this.EndDate=='null')
	  		this.rsobj.attributes['endDate'].value = '';
	  	else
	  		this.rsobj.attributes['endDate'].value = DateUtil.getDateYYYYMMDDDashed(this.EndDate);
	  	this.rsobj.attributes['weekDays'].value = this.WeekDays;
	  	this.rsobj.attributes['reminderTimes'].value = this.ReminderTimes;
		if(this.reminderCheckbox.checked)
		this.rsobj.attributes['reminder'].value = 'on';
		else
		this.rsobj.attributes['reminder'].value = 'off';
    	return true;
  },
  
  /* Event handler for a dialog submit. */
  onsubmit: function(eventName, args, me)
  {
    return me.saveForm();
  }

}

/* Edit Review Form */
var ReviewForm = function(formId, patientId, nurseId, currDate)
{
  this.LOAD_METHOD = 'getpeopledata';
  this.SAVE_METHOD = 'SAVE_EDIT_REVIEW_SCHE';
  this.SERVLET = 'MainServlet';
  this.AUTHOR_TYPE = 'NURSE';
  
  this.form = YAHOO.util.Dom.get(formId);
  this.dialog = new Dialog(formId, {});
  this.patientId = patientId;
  this.nurseId = nurseId;
  this.currDate = currDate;

  /* Assign an event handler for a dialog submit. */
  this.dialog.onsubmit.subscribe(this.onsubmit, this);

  // Get the form elements.
  this.statusCheckbox = YAHOO.util.Dom.get('reviewStatus');
  
  this.frequencySelect = YAHOO.util.Dom.get('reviewFrequency');
  YAHOO.util.Event.addListener(this.frequencySelect, 'change', this.changeFrequency, this, true);
  
  this.dayLabels = YAHOO.util.Dom.getElementsByClassName('dayLabels', 'tr', this.form)[0];
  this.daySelection = YAHOO.util.Dom.getElementsByClassName('daySelection', 'tr', this.form)[0];
  this.dateSelection = YAHOO.util.Dom.getElementsByClassName('dateSelection', 'tr', this.form)[0];
  
  var checkboxDays = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
  this.dayCheckboxes = [];
  for (var i = 0; i < checkboxDays.length; i++)
  {
    this.dayCheckboxes[i] = YAHOO.util.Dom.get(checkboxDays[i]);
  }
  
  this.allDaysCheckbox = new CheckAllCheckbox('all', this.dayCheckboxes);
  
  this.monthDate = YAHOO.util.Dom.get('monthDate');
  
  // Preset form value by getting data via AJAX.
  this.initializeForm();
}

ReviewForm.prototype =
{
  /* Loads the patient data to preset form values. */
  initializeForm: function()
  {
    //var requestString = formatXmlRequest(this.LOAD_METHOD, { peopleid: this.patientId });
    //var request = YAHOO.util.Connect.asyncRequest('POST', this.SERVLET, { success: this.updateForm, argument: [this] }, requestString);
    this.updateForm([this]);
  },
  
  /* Presets the form values with AJAX data */
  updateForm: function(obj)
  {
    var me = obj[0];//obj.argument[0];
    var data = new XmlDataObject(xmlPplData,
    {
      id: 'PEOPLE_ID',
      name: 'PEOPLENAME',
      reviewFrequency: 'REVIEW_FREQUENCY',
      reviewDays: 'REVIEW_DAYS_IN_WEEK',
      resolutionStatus: 'RESOLUTION_STATUS'
    });
  
    var nameEl = YAHOO.util.Dom.get('reviewName');
    nameEl.innerHTML = data.name;
    
    me.statusCheckbox.checked = (data.resolutionStatus == 1);
    me.statusCheckbox.disabled = (data.resolutionStatus == 1);

    var reviewFrequency = data.reviewFrequency;
    // Treat ED (every day) as EW (every week) with all days selected.    
    if (data.reviewFrequency.toLowerCase() == 'ed')
    {
      reviewFrequency = 'ew';
    }

    setSelectValue(me.frequencySelect, reviewFrequency);
    me.changeFrequency();
    
    for (var i = 0; i < me.dayCheckboxes.length; i++)
    {
      var checkbox = me.dayCheckboxes[i];
      if (data.reviewFrequency.toLowerCase() == 'ed' || data.reviewDays.indexOf(checkbox.value) > -1)
      {
        checkbox.checked = true;
      }
    }
    
    me.allDaysCheckbox.updateCheckAll();
  },
  
  /* Displays the weekly day selection fields */
  showDaySelection: function()
  {
    // IE doesn't support display table-row
    this.dayLabels.style.display = '';
    this.daySelection.style.display = '';
    this.dateSelection.style.display = 'none';
  },
  
  /* Displays the monthly date selection fields */
  showDateSelection: function()
  {
    this.dayLabels.style.display = 'none';
    this.daySelection.style.display = 'none';
    // IE doesn't support display table-row
    this.dateSelection.style.display = '';
  },

  /* Event handler for a change in the review frequency */
  changeFrequency: function(e)
  {
    if (getSelectValue(this.frequencySelect).toLowerCase() == 'em')
    {
      this.showDateSelection();
    }
    else
    {
      this.showDaySelection();
    }
  },
  
  /* Validates the form */
  isFormValid: function()
  {
    if (getSelectValue(this.frequencySelect).toLowerCase() == 'em')
    {
      return true;
    }

    // Make sure at least one day is checked.
    for (var i = 0; i < this.dayCheckboxes.length; i++)
    {
      if (this.dayCheckboxes[i].checked)
      {
        return true;
      }
    }
    return false;
  },
  
  /* Saves the form */
  saveForm: function()
  {
    // Validate the form first.
    if (!this.isFormValid())
    {
      alert('Please select at least one day.');
      return false;
    }
    
    var reviewDays = '';
    var frequency = getSelectValue(this.frequencySelect);
    if (frequency.toLowerCase() == 'em')
    {
      reviewDays = getSelectValue(this.monthDate);
    }
    else
    {
      var allChecked = true;
      // Construct a string for the review days.
      for (var i = 0; i < this.dayCheckboxes.length; i++)
      {
        var checkbox = this.dayCheckboxes[i];
        if (checkbox.checked)
        {
          reviewDays += checkbox.value + ',';
        }
        else
        {
          allChecked = false;
        }
      }
      reviewDays = reviewDays.substring(0, reviewDays.length - 1);
      
      // See if we really mean ED (every day)
      if (allChecked && frequency.toLowerCase() == 'ew')
      {
        frequency = 'ED';
      }
    }

    // Construct a string for the date.
    var currDateString = this.currDate.getFullYear() + '-' + (this.currDate.getMonth() + 1) + '-' + this.currDate.getDate();

    // Create the request string.
    var requestString = formatXmlRequest(this.SAVE_METHOD,
    {
      author_id: this.nurseId,
      author_type: this.AUTHOR_TYPE,
      patient_id: this.patientId,
      resolved_status: (this.statusCheckbox.checked) ? 1 : 0,
      review_frequency: frequency,
      review_day: reviewDays,
      user_current_date: currDateString
    });
    
    // The current date has underscores for some reason.
    requestString = requestString.replace(/USER-CURRENT-DATE/g, 'USER_CURRENT_DATE');
    
    // Post the AJAX.
    var request = YAHOO.util.Connect.asyncRequest('POST', this.SERVLET,
    {
      success: this.updateReviewDisplay,
      failure: this.reportFailure,
      argument: [this]
    }, requestString);
    
    return true;
  },
  
  /* The AJAX failed. Tell the user */
  reportFailure: function(obj)
  {
    alert('Unable to save new schedule. Please try again later.');
  },
  
  /* The AJAX succeeded. Reload the page to show the new review date. */ 
  updateReviewDisplay: function(obj)
  {
    // refresh the page.
    window.location.reload(false);
  },

  /* Event handler for a page change. */
  changePage: function(eventName, args, me)
  {
    me.showPatient(args[0]);
  },

  /* Event handler for a dialog submit. */
  onsubmit: function(eventName, args, me)
  {
    return me.saveForm();
  }
}

/* Edit Actions form */
var EditActionsForm = function(formId, nurseId)
{
  this.LOAD_METHOD = 'getpeopledata';
  this.SAVE_METHOD = 'save_edit_action';
  this.SERVLET = 'MainServlet';
  this.AUTHOR_TYPE = 'NURSE';
  
  this.form = YAHOO.util.Dom.get(formId);
  this.dialog = new Dialog(formId, {});
  this.nurseId = nurseId;

  /* Assign an event handler for a dialog submit. */
  this.dialog.onsubmit.subscribe(this.onsubmit, this);

  // Get the form elements.
  this.actionFirstName = YAHOO.util.Dom.getElementsByClassName('actionFirstName', 'span', this.form)[0];
  this.actionLastName = YAHOO.util.Dom.getElementsByClassName('actionLastName', 'span', this.form)[0];
  this.actionComplete = YAHOO.util.Dom.get('actionComplete');
  this.actionReview = YAHOO.util.Dom.get('actionReview');
  this.actionContact = YAHOO.util.Dom.get('actionContact');
  
  this.frequencySelect = YAHOO.util.Dom.get('actionFrequency');
  YAHOO.util.Event.addListener(this.frequencySelect, 'change', this.changeFrequency, this, true);
  
  this.dayLabels = YAHOO.util.Dom.getElementsByClassName('dayLabels', 'tr', this.form)[0];
  this.daySelection = YAHOO.util.Dom.getElementsByClassName('daySelection', 'tr', this.form)[0];
  this.dateSelection = YAHOO.util.Dom.getElementsByClassName('dateSelection', 'tr', this.form)[0];
  
  var checkboxDays = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
  this.dayCheckboxes = [];
  for (var i = 0; i < checkboxDays.length; i++)
  {
    this.dayCheckboxes[i] = YAHOO.util.Dom.get(checkboxDays[i]);
  }
  
  this.allDaysCheckbox = new CheckAllCheckbox('all', this.dayCheckboxes);
  
  this.monthDate = YAHOO.util.Dom.get('monthDate');
  
  this.note = YAHOO.util.Dom.get('actionNote');
}

EditActionsForm.prototype =
{
  /* Sets the patient for the form. */
  setPatient: function(patient)
  {
    this.patient = patient;
    this.initializeForm();
  },

  /* Loads the patient data to preset form values. */
  initializeForm: function()
  {
    var requestString = formatXmlRequest(this.LOAD_METHOD, { peopleid: this.patient.id });
    var request = YAHOO.util.Connect.asyncRequest('POST', this.SERVLET, { success: this.updateForm, argument: [this] }, requestString);
  },
  
  /* Presets the form values with AJAX data */
  updateForm: function(obj)
  {
    var me = obj.argument[0];
    var data = new XmlDataObject(obj.responseXML,
    {
      id: 'PEOPLE_ID',
      name: 'PEOPLENAME',
      reviewFrequency: 'REVIEW_FREQUENCY',
      reviewDays: 'REVIEW_DAYS_IN_WEEK',
      resolutionStatus: 'RESOLUTION_STATUS'
    });
    
    me.actionFirstName.innerHTML = me.patient.firstName;
    me.actionLastName.innerHTML = me.patient.lastName;

    me.actionComplete.checked = me.patient.actions.complete;
    me.actionComplete.disabled = me.patient.actions.complete;
    me.actionReview.checked = me.patient.actions.hasAction(ActionsTaken.REVIEW);
    me.actionContact.checked = me.patient.actions.hasAction(ActionsTaken.CONTACT);
    
    if(me.note)me.note.value = '';

    var reviewFrequency = data.reviewFrequency;
    // Treat ED (every day) as EW (every week) with all days selected.    
    if (data.reviewFrequency.toLowerCase() == 'ed')
    {
      reviewFrequency = 'ew';
    }

    setSelectValue(me.frequencySelect, reviewFrequency);
    me.changeFrequency();
    
    for (var i = 0; i < me.dayCheckboxes.length; i++)
    {
      var checkbox = me.dayCheckboxes[i];
      if (data.reviewFrequency.toLowerCase() == 'ed' || data.reviewDays.indexOf(checkbox.value) > -1)
      {
        checkbox.checked = true;
      }
    }
    
    me.allDaysCheckbox.updateCheckAll();
  },
  
  /* Displays the weekly day selection fields */
  showDaySelection: function()
  {
    // IE doesn't support display table-row
    this.dayLabels.style.display = '';
    this.daySelection.style.display = '';
    this.dateSelection.style.display = 'none';
  },
  
  /* Displays the monthly date selection fields */
  showDateSelection: function()
  {
    this.dayLabels.style.display = 'none';
    this.daySelection.style.display = 'none';
    // IE doesn't support display table-row
    this.dateSelection.style.display = '';
  },

  /* Event handler for a change in the review frequency */
  changeFrequency: function(e)
  {
    if (getSelectValue(this.frequencySelect).toLowerCase() == 'em')
    {
      this.showDateSelection();
    }
    else
    {
      this.showDaySelection();
    }
  },
  
  /* Validates the form */
  isFormValid: function()
  {
    if (getSelectValue(this.frequencySelect).toLowerCase() == 'em')
    {
      return true;
    }

    // Make sure at least one day is checked.
    for (var i = 0; i < this.dayCheckboxes.length; i++)
    {
      if (this.dayCheckboxes[i].checked)
      {
        return true;
      }
    }
    return false;
  },
  
  /* Saves the form */
  saveForm: function()
  {
    // Validate the form first.
    if (!this.isFormValid())
    {
      alert('Please select at least one day.');
      return false;
    }
    
    var actionsTaken = '';
    if (this.actionReview.checked)
    {
      actionsTaken += 'Reviewed,';
    }
    
    if (this.actionContact.checked)
    {
      actionsTaken += 'Contacted,';
    }
    
    if (actionsTaken.length > 0)
    {
      actionsTaken = actionsTaken.substring(0, actionsTaken.length - 1);
    }
    
    var reviewDays = '';
    var frequency = getSelectValue(this.frequencySelect);
    if (frequency.toLowerCase() == 'em')
    {
      reviewDays = getSelectValue(this.monthDate);
    }
    else
    {
      var allChecked = true;
      // Construct a string for the review days.
      for (var i = 0; i < this.dayCheckboxes.length; i++)
      {
        var checkbox = this.dayCheckboxes[i];
        if (checkbox.checked)
        {
          reviewDays += checkbox.value + ',';
        }
        else
        {
          allChecked = false;
        }
      }
      reviewDays = reviewDays.substring(0, reviewDays.length - 1);
      
      // See if we really mean ED (every day)
      if (allChecked && frequency.toLowerCase() == 'ew')
      {
        frequency = 'ED';
      }
    }

    // Create the request string.
    var requestString = formatXmlRequest(this.SAVE_METHOD,
    {
      author_id: this.nurseId,
      author_type: this.AUTHOR_TYPE,
      patient_id: this.patient.id,
      resolution_type: this.actionComplete.checked ? 'Resolved' : '',
      action_taken: actionsTaken,
      review_frequency: frequency,
      review_day: reviewDays,
      note: this.note.value
    });
    
    // Post the AJAX.
    var request = YAHOO.util.Connect.asyncRequest('POST', this.SERVLET,
    {
      success: this.updateReviewDisplay,
      failure: this.reportFailure,
      argument: [this]
    }, requestString);
    
    return true;
  },
  
  /* The AJAX failed. Tell the user */
  reportFailure: function(obj)
  {
    alert('Unable to save actions. Please try again later.');
  },
  
  /* The AJAX succeeded. Reload the page to show the actions. */ 
  updateReviewDisplay: function(obj)
  {
    // refresh the page.
    window.location.reload(false);
  },

  /* Event handler for a dialog submit. */
  onsubmit: function(eventName, args, me)
  {
    return me.saveForm();
  }
}

/* Edit Journal Entry form */
var EditJournalForm = function(formId, patientId, defaultDate)
{
  this.LOAD_METHOD = 'get_journal_options';
  this.SAVE_METHOD =
  {
    FOOD: 'save_food_journal',
    EXERCISE: 'save_exercise_journal',
    LIFE: 'save_exercise_journal'
  };
  
  this.DELETE_METHOD = 'delete_journal';
  
  this.SERVLET = 'MainServlet';
  
  this.form = YAHOO.util.Dom.get(formId);
  this.dialog = new Dialog(formId, {});
  this.patientId = patientId;
  
  var currdatetime = new Date();
  
  this.defaultDate = currdatetime;
  this.selectedQDate = currdatetime;
  
  this.defaultDate.setDate(defaultDate.getDate());	
  this.defaultDate.setFullYear(defaultDate.getFullYear());	
  this.defaultDate.setMonth(defaultDate.getMonth());	
  
  this.selectedQDate.setDate(defaultDate.getDate());	
  this.selectedQDate.setFullYear(defaultDate.getFullYear());	
  this.selectedQDate.setMonth(defaultDate.getMonth());	


  // Get the form elements.
  this.calendar = new PopupYUICalendar(
    YAHOO.util.Dom.getElementsByClassName('calendar', 'a', this.form)[0],
    YAHOO.util.Dom.getElementsByClassName('calWidget', 'div', this.form)[0]
  );
  
  this.timeSelector = new TimeSelector(
    YAHOO.util.Dom.getElementsByClassName('hour', 'select', this.form)[0],
    YAHOO.util.Dom.getElementsByClassName('minute', 'select', this.form)[0],
    YAHOO.util.Dom.getElementsByClassName('meridian', 'select', this.form)[0]
  );
  
  this.journalPicker = YAHOO.util.Dom.get('journalPicker');
  this.journalSelect = this.journalPicker.getElementsByTagName('select')[0];
  
  this.deleteButton = YAHOO.util.Dom.getElementsByClassName('delete', 'input', this.form)[0];
  this.journalDate = YAHOO.util.Dom.getElementsByClassName('journalDate', 'span', this.form)[0];
  //this.MetricCode = YAHOO.util.Dom.getElementsByClassName('mtCode', 'span', this.form)[0];
  
  //this.MetricCode.innerHTML = metricVal;
  
  this.exerciseJournal = new ExerciseJournalSubForm('exerciseJournal');
  this.lifeJournal = new LifeJournalSubForm('lifeJournal');
  this.activityTracker = new ActivityTrackerSubForm('activityTracker');
  this.foodJournal = new FoodJournalSubForm('foodJournal');
  //this.mealTracker = new MealTrackerSubForm('mealTracker');
  this.mealTrackerDynamic = new MealTrackerDynamicSubForm('mealTrackerDynamic');
  this.calorieStrategy = new CalorieEstimator();
  this.calorieEstimator = new CalorieEstimatorSubForm('calorieEstimator', this.calorieStrategy.estimateCalories.bind(this.calorieStrategy));
  
  /* Assign event handlers for the controls */
  this.dialog.onsubmit.subscribe(this.onsubmit, this);
  this.calendar.onchangedate.subscribe(this.calendarSelected, this);
  this.timeSelector.onchangetime.subscribe(this.timeChanged, this);
  YAHOO.util.Event.addListener(this.journalSelect, 'change', this.journalTypeChanged, this, true);
  YAHOO.util.Event.addListener(this.deleteButton, 'click', this.onDelete, this, true);
  
  // Load the patient journal options via AJAX.
  this.loadJournalOptions();
}

EditJournalForm.prototype =
{
  /* Sets the journal entry for the form */
  setJournalEntry: function(journalEntry)
  {
    this.entry = journalEntry;
    this.updateForm();
  },
  
  /* Updates the form fields based on the journal entry */
  updateForm: function()
  {
    // New journal entry
    if (this.entry.id == -1)
    {
      var newDate = this.defaultDate;//new Date();
      this.calendar.setDate(newDate);
      this.timeSelector.setTime(newDate);
      this.journalDate.innerHTML = DateUtil.getDateShortString(newDate);

      this.foodJournal.clearForm();
      this.mealTrackerDynamic.clearForm();
      this.calorieEstimator.clearForm();
      this.exerciseJournal.clearForm();
      this.lifeJournal.clearForm();
      this.activityTracker.clearForm();
      
      if (this.options.hasLifeJournal)
      {
        this.showJournal('life');
        setSelectValue(this.journalSelect, 'life');
      }
      else if (this.options.hasFoodJournal || this.options.hasMealTracker || this.options.hasCalorieEstimator)
      {
        this.showJournal('food');
        setSelectValue(this.journalSelect, 'food');
      }
      else
      {
        this.showJournal('exercise');
        setSelectValue(this.journalSelect, 'exercise');
      }
      
      //this.journalPicker.style.display = (this.journalSelect.options.length > 1) ? 'block' : 'none';
      this.deleteButton.style.display = 'none';
    }
    else
    {
      var theDate = this.entry.getDate();
      this.calendar.setDate(theDate);
      this.timeSelector.setTime(theDate);
      this.journalDate.innerHTML = DateUtil.getDateShortString(theDate);

      this.hideAllForms();
      var type = this.entry.type.toLowerCase();
      switch (type)
      {
        case 'food':
          if (this.options.hasFoodJournal)
          {
            this.foodJournal.setJournalEntry(this.entry);
            this.foodJournal.displayForm(true);
          }
        
          if (this.options.hasMealTracker && this.entry.metrics)
          {
            this.mealTrackerDynamic.setJournalEntry(this.entry);
            this.mealTrackerDynamic.displayForm(true);
            //this.MetricCode.innerHTML = this.entry.mealTracker.metric;
          }
          
          if (this.options.hasCalorieEstimator && this.entry.calorieItems)
          {
            this.calorieEstimator.setJournalEntry(this.entry);
            this.calorieEstimator.displayForm(true);
          }
          break;
        case 'exercise':
          if (this.options.hasExerciseJournal)
          {
            this.exerciseJournal.setJournalEntry(this.entry);
            this.exerciseJournal.displayForm(true);
          }
          
          if (this.options.hasActivityTracker && this.entry.activities)
          {
            this.activityTracker.setJournalEntry(this.entry);
            this.activityTracker.displayForm(true);
          }
          break;
         case 'life':
          if (this.options.hasLifeJournal)
          {
            this.lifeJournal.setJournalEntry(this.entry);
            this.lifeJournal.displayForm(true);
          }
          break;
      }

      this.journalPicker.style.display = 'none';
      this.deleteButton.style.display = 'block';
    }
  },
  
  /* Loads the journal options for the patient */
  loadJournalOptions: function()
  {
    var requestString = formatXmlRequest(this.LOAD_METHOD, { user_id: this.patientId });
    
    //var request = YAHOO.util.Connect.asyncRequest('POST', this.SERVLET, {success: this.loadSuccess, argument: [this]}, requestString);
    this.loadSuccess([this]);
    // TODO: For now, just retrieve from a static XML file.
    //var request = YAHOO.util.Connect.asyncRequest('POST', 'journal_options.xml', {success: this.loadSuccess, failure: this.loadSuccess, argument: [this]}, '');
  },
  
  /* Event handler for a successful request for journal options */
  loadSuccess: function(obj)
  {
    var me = obj[0];//obj.argument[0];
    //obj.responseXML
    var data = new XmlDataObject(xmlJournalOptions,
    {
      lifeJournal: 'LIFE-JOURNAL',
      foodJournal: 'FOOD-JOURNAL',
      mealTracker: 'MEAL-TRACKER',
      calorieEstimator: 'CALORIE-ESTIMATOR',
      metricList:['METRIC',
      	{
      		protocolId: 'ID',
      		protocolName: 'DISPLAYVAL'
      	}
      ],
      exerciseList: ['JOURNAL',
        {
          type: 'TYPE',
          subType: 'SUB-TYPE',
          color: 'COLOR',
          iconName: 'ICON-NAME',
          status: 'STATUS',
          protocolId: 'ID',
          protocolName: 'NAME',
          protocolDisplayName: 'DISPLAY-NAME'
        }
      ]
    });
    
    // Make sure the metric list is an array.
    if (!data.metricList)
    {
      data.metricList = [];
    }
    else if (!data.metricList.length)
    {
      data.metricList = [ data.metricList ];
    }
    
    // Make sure the exercise list is an array.
    if (!data.exerciseList)
    {
      data.exerciseList = [];
    }
    else if (!data.exerciseList.length)
    {
      data.exerciseList = [ data.exerciseList ];
    }

    // Load the options.
    me.options =
    {
      hasLifeJournal: (data.lifeJournal.toLowerCase() == 'yes' || data.lifeJournal.toLowerCase() == 'true' || data.lifeJournal == 1),
      hasFoodJournal: (data.foodJournal.toLowerCase() == 'yes' || data.foodJournal.toLowerCase() == 'true' || data.foodJournal == 1),
      hasMealTracker: (data.mealTracker.toLowerCase() == 'yes' || data.mealTracker.toLowerCase() == 'true' || data.mealTracker == 1),
      hasCalorieEstimator: (data.calorieEstimator.toLowerCase() == 'yes' || data.calorieEstimator.toLowerCase() == 'true' || data.calorieEstimator == 1),
      hasExerciseJournal: false,
      hasActivityTracker: false,
      exerciseJournalId : 0,
      foodJournalId : 0,
      lifeJournalId : 11
    };


	// Check the Metric list to determine which metric options are enabled.
    // Collect the list of metrics for Meal tracker.
    var metrics = [];
    for (var i = 0; i < data.metricList.length; i++)
    {
      var metric = data.metricList[i];
      
      me.options.hasMealTracker = true;
      metrics[metrics.length] = metric;
    }
    
    // Fill the activity tracker table.
    if (me.options.hasMealTracker)
    {
      me.mealTrackerDynamic.loadFields(metrics);
    }
	
    // Check the exercise list to determine which exercise options are enabled.
    // Collect the list of activities for activity tracker.
    var activities = [];
    for (var i = 0; i < data.exerciseList.length; i++)
    {
      var exercise = data.exerciseList[i];
      var exerciseSubType = exercise.subType.toLowerCase();
      if (exerciseSubType == 'exercise_jn')
      {
        me.options.hasExerciseJournal = true;
        me.options.exerciseJournalId = exercise.protocolId;
      }
      else if (exerciseSubType == 'exercise')
      {
        me.options.hasActivityTracker = true;
        activities[activities.length] = exercise;
      }
    }
    
    // Fill the activity tracker table.
    if (me.options.hasActivityTracker)
    {
      me.activityTracker.loadFields(activities);
    }

    // Add journal type selections.
    if (me.options.hasFoodJournal || me.options.hasMealTracker || me.options.hasCalorieEstimator)
    {
      me.addJournalSelectType('food', 'Food');
    }
    if (me.options.hasLifeJournal )
    {
      me.addJournalSelectType('life', 'Life');
    }

    if (me.options.hasExerciseJournal || me.options.hasActivityTracker)
    {
      me.addJournalSelectType('exercise', 'Exercise');
    }
  },
  
  /* Adds a journal type to the journal select box */
  addJournalSelectType: function(value, name)
  {
    var option = document.createElement('option');
    option.value = value;
    option.innerHTML = name;
    this.journalSelect.appendChild(option);
  },
  
  /* Displays the form fields for the specified journal type */
  showJournal: function(journalType)
  {
    this.hideAllForms();
    switch (journalType)
    {
      case 'exercise':
        this.exerciseJournal.displayForm(this.options.hasExerciseJournal);
        this.activityTracker.displayForm(this.options.hasActivityTracker);
        break;
      case 'life':
        this.lifeJournal.displayForm(true);
        break;
      case 'food':
      default:
        this.foodJournal.displayForm(this.options.hasFoodJournal);
        this.mealTrackerDynamic.displayForm(this.options.hasMealTracker);
        this.calorieEstimator.displayForm(this.options.hasCalorieEstimator);
        break;
    }
  },
  
  /* Hides all journal forms */
  hideAllForms: function()
  {
    this.lifeJournal.displayForm(false);
    this.exerciseJournal.displayForm(false);
    this.activityTracker.displayForm(false);
    this.foodJournal.displayForm(false);
    this.mealTrackerDynamic.displayForm(false);
    this.calorieEstimator.displayForm(false);
  },

  /* Event handler for calendar selection. */
  calendarSelected: function(eventName, args, me)
  {
    me.date = args[0];
    me.journalDate.innerHTML = DateUtil.getDateShortString(me.date);
  },
  
  /* Event handler for time selection */
  timeChanged: function(eventName, args, me)
  {
    me.time = args[0];
  },
  
  // Event handler for a change in the journal type selection.
  journalTypeChanged: function(e)
  {
    this.showJournal(this.journalSelect.value);
  },

  /* Validates the form and returns an array of error messages. */
  getErrors: function()
  {
    var result = [];
    var errorCnt = 0;

    // We're entering a new journal.
    if (this.entry.id == -1)
    {
      switch (getSelectValue(this.journalSelect))
      {
        case 'food':
          if (this.options.hasFoodJournal)
          {
          	var tempResult = this.foodJournal.getErrors();
            result = result.concat(this.foodJournal.getErrors());
            if(tempResult.length > 0)
            {
            	errorCnt++;
            }
            
          }
          
          if (this.options.hasMealTracker)
          {
          	var tempResult = this.mealTrackerDynamic.getErrors();
          	if( tempResult.length == this.mealTrackerDynamic.textFields.length)
            {
            	result = result.concat(this.mealTrackerDynamic.getErrors());
            	errorCnt++;
            }
          }
          
          if (this.options.hasCalorieEstimator)
          {
            result = result.concat(this.calorieEstimator.getErrors());
            var tempResult = this.calorieEstimator.getErrors();
            if(tempResult.length > 0)
            {
            	errorCnt++;
            }
          }
          break;
        case 'exercise':
          if (this.options.hasExerciseJournal)
          {
            result = result.concat(this.exerciseJournal.getErrors());
            var tempResult = this.exerciseJournal.getErrors();
            if(tempResult.length > 0)
            {
            	errorCnt++;
            }
          }
          
          if (this.options.hasActivityTracker)
          {
            var tempResult = this.activityTracker.getErrors();
          	if( tempResult.length == this.activityTracker.textFields.length)
            {
            	result = result.concat(this.activityTracker.getErrors());
            	errorCnt++;
            }
          } 
          break;
         case 'life':
          if (this.options.hasLifeJournal)
          {
            result = result.concat(this.lifeJournal.getErrors());
            var tempResult = this.lifeJournal.getErrors();
            if(tempResult.length > 0)
            {
            	errorCnt++;
            }
          }
          break;
      }
    }
    else
    {
      switch (this.entry.type.toLowerCase())
      {
        case 'food':
          if (this.options.hasFoodJournal)
          {
            result = result.concat(this.foodJournal.getErrors());
            var tempResult = this.foodJournal.getErrors();
            if(tempResult.length > 0)
            {
            	errorCnt++;
            }
          }
          
          if (this.options.hasMealTracker && this.entry.metrics)
          {
          	var tempResult = this.mealTrackerDynamic.getErrors();
          	if( tempResult.length == this.mealTrackerDynamic.textFields.length)
            {
            	result = result.concat(this.mealTrackerDynamic.getErrors());
            	errorCnt++;
            }
          }
          
          if (this.options.hasCalorieEstimator && this.entry.calorieItems)
          {
            result = result.concat(this.calorieEstimator.getErrors());
            var tempResult = this.calorieEstimator.getErrors();
            if(tempResult.length > 0)
            {
            	errorCnt++;
            }
          }
          break;
        case 'exercise':
          if (this.options.hasExerciseJournal)
          {
            result = result.concat(this.exerciseJournal.getErrors());
            var tempResult = this.exerciseJournal.getErrors();
            if(tempResult.length > 0)
            {
            	errorCnt++;
            }
          }
          
          if (this.options.hasActivityTracker && this.entry.activities)
          {
          	var tempResult = this.activityTracker.getErrors();
          	if( tempResult.length == this.activityTracker.textFields.length)
            {
            	result = result.concat(this.activityTracker.getErrors());
            	errorCnt++;
            }
          } 
          break;
         case 'life':
          if (this.options.hasLifeJournal)
          {
            result = result.concat(this.lifeJournal.getErrors());
            var tempResult = this.lifeJournal.getErrors();
            if(tempResult.length > 0)
            {
            	errorCnt++;
            }
          }
          break;
      }
    }
    
    if(errorCnt < 2)
    {	
    	result = [];
    }
    return result;
  },
  
  
  /* Saves the form */
  saveForm: function()
  {
    // Validate the form first.
    var errors = this.getErrors();
    if (errors.length > 0)
    {
      var errorStr = '';
      for (var i = 0; i < errors.length; i++)
      {
        errorStr += errors[i] + "\n";
      }
      alert(errorStr);
      return false;
    }
    
    hrs = this.timeSelector.hour.value;
    min = this.timeSelector.minute.value;
    mer = this.timeSelector.meridian.value;
    
    if(mer.toLowerCase() == "pm")
	{
		hrs = parseInt(hrs) + 12;
		if(hrs == "24" || hrs == "00")
		{
			hrs = "12";
		}		
	}
	else
	{
		if(hrs == "12")
		{
			hrs = "00";
		}
	}
	
	if(hrs.length < 2)
	{
		hrs = "0" + hrs;
	}
	
	if(min.length < 2)
	{
		min = "0" + min;
	}
	
	var selectedDate = "";
	var monthval = "";
	var dateval = "";
	if(this.entry.id == "-1")
	{
		var selectedDateCal = this.defaultDate;
	
		monthval = selectedDateCal.getMonth() + 1;
		if(monthval <10)
		{
			monthval = "0" + monthval;
		}
		
		dateval = selectedDateCal.getDate();
		if(dateval <10)
		{
			dateval = "0" + dateval;
		}
		selectedDate = selectedDateCal.getFullYear() + "-" + monthval + "-" + dateval;
		this.selectedQDate = selectedDateCal.getFullYear() + "" + monthval + "" + dateval;
	}
	else
	{
		selectedDate = this.entry.date;
		this.selectedQDate = selectedDate.replace("-","");
		this.selectedQDate = this.selectedQDate.replace("-","");
	}
	
	
	if(this.date != null)
	{
		monthval = this.date.getMonth() + 1;
		if(monthval <10)
		{
			monthval = "0" + monthval;
		}
		
		dateval = this.date.getDate();
		if(dateval <10)
		{
			dateval = "0" + dateval;
		}
		selectedDate = this.date.getFullYear() + "-" + monthval + "-" + dateval;
		this.selectedQDate = this.date.getFullYear() + "" + monthval + "" + dateval;
	}
	
	
		
	var jDateTime = new Date();
	
	jHr = jDateTime.getHours();
	jMin = jDateTime.getMinutes();
	jSec = jDateTime.getSeconds();
	
	if(jHr < 10)
	{
		jHr = "0" + jHr;
	}
	
	if(jMin < 10)
	{
		jMin = "0" + jMin;
	}
	
	if(jSec < 10)
	{
		jSec = "0" + jSec;
	}
	
	var jmonthval = jDateTime.getMonth() + 1;
	if(jmonthval <10)
	{
		jmonthval = "0" + jmonthval;
	}
	
	var jdateval = jDateTime.getDate();
	if(jdateval <10)
	{
		jdateval = "0" + jdateval;
	}
	
	var jTime = jDateTime.getFullYear() + "-" + jmonthval + "-" + jdateval + " " +jHr + ":" + jMin + ":" + jSec;
    
    var reqStrParams = 	'<USER-ID>'+this.patientId+'</USER-ID>';
    
    if (this.entry.id == -1)
    {       	
    	if(this.journalSelect.value == 'food')
    	{
    		reqStrParams +=	'<JOURNAL>';
		        reqStrParams +=	'<ID>-1</ID>'+
				        		'<TYPE>FOOD</TYPE>'+
				        		'<SUB-TYPE>FOOD_JN</SUB-TYPE>'+
				        		'<DESCRIPTION><![CDATA['+ this.foodJournal.description.value +']]></DESCRIPTION>'+
				        		'<DATE>'+ selectedDate +'</DATE>'+
								'<TIME>'+ hrs + ":" + min + ":00"+'</TIME>'+
				        		'<VOICE-URL></VOICE-URL>'+
				        		'<STATUS>ACTIVE</STATUS>'+
						        '<JTIME>'+ jTime +'</JTIME>';
    	 	if(this.options.hasMealTracker)
    	 	{
    	 	
    	 		reqStrParams += 	'<MEAL-TRACKER>';
    	 		
    	 		for (var i = 1; i < this.mealTrackerDynamic.textFields.length; i++)
			    {
			      var field = this.mealTrackerDynamic.textFields[i];
			      
			      
			      reqStrParams +=	'<METRIC>'+
			      					'<METRICID>'+ field.id.substr(6,field.id.length) +'</METRICID>'+
			      					'<VALUE><![CDATA['+field.value+']]></VALUE>'+
			      					'<ID>-1</ID>'+
			      					'</METRIC>';
					        		
			    }
			    
			    reqStrParams += 	'</MEAL-TRACKER>';
    	 		/*reqStrParams +=	'<MEAL-TRACKER>'+
						        '<METRIC>'+ this.mealTrackerDynamic +'</METRIC>'+
						        '<VALUE>'+this.mealTrackerDynamic.textFields[0].value+'</VALUE>'+
						        '<ID>-1</ID>'+
						        '</MEAL-TRACKER>';*/
    	 	}
    	 	if(this.options.hasCalorieEstimator)
    	 	{
    	 		reqStrParams +=	'<DETAILS>'+
          						'<ITEM>'+
            					'<ID>MEAT</ID>'+
            					'<VALUE>'+this.calorieEstimator.textFields[0].value+'</VALUE>'+
            					'<MEASURE>'+this.calorieEstimator.calorieDisplays[0].firstChild.data+'</MEASURE>'+
          						'</ITEM>'+
          						'<ITEM>'+
            					'<ID>GRAINS</ID>'+
            					'<VALUE>'+this.calorieEstimator.textFields[1].value+'</VALUE>'+
            					'<MEASURE>'+this.calorieEstimator.calorieDisplays[1].firstChild.data+'</MEASURE>'+
          						'</ITEM>'+
          						'<ITEM>'+
            					'<ID>DAIRY</ID>'+
            					'<VALUE>'+this.calorieEstimator.textFields[2].value+'</VALUE>'+
            					'<MEASURE>'+this.calorieEstimator.calorieDisplays[2].firstChild.data+'</MEASURE>'+
          						'</ITEM>'+
          						'<ITEM>'+
            					'<ID>FRUITS</ID>'+
            					'<VALUE>'+this.calorieEstimator.textFields[3].value+'</VALUE>'+
            					'<MEASURE>'+this.calorieEstimator.calorieDisplays[3].firstChild.data+'</MEASURE>'+
          						'</ITEM>'+
          						'<ITEM>'+
            					'<ID>FATS</ID>'+
            					'<VALUE>'+this.calorieEstimator.textFields[4].value+'</VALUE>'+
            					'<MEASURE>'+this.calorieEstimator.calorieDisplays[4].firstChild.data+'</MEASURE>'+
          						'</ITEM>'+
          						'<ITEM>'+
						        '<ID>VEGETABLES</ID>'+
						        '<VALUE>'+this.calorieEstimator.textFields[5].value+'</VALUE>'+
						        '<MEASURE>'+this.calorieEstimator.calorieDisplays[5].firstChild.data+'</MEASURE>'+
						        '</ITEM>'+
						        '<ITEM>'+
						        '<ID>SWEETS</ID>'+
						        '<VALUE>'+this.calorieEstimator.textFields[6].value+'</VALUE>'+
						        '<MEASURE>'+this.calorieEstimator.calorieDisplays[6].firstChild.data+'</MEASURE>'+
						        '</ITEM>'+
						        '<TOTAL>'+
						        '<VALUE>'+this.calorieEstimator.servingsTotal.firstChild.data+'</VALUE>'+
						        '<MEASURE>'+this.calorieEstimator.caloriesTotal.firstChild.data+'</MEASURE>'+
						        '</TOTAL>'+
						        '</DETAILS>';
    	 	}
    	 	
    	 	reqStrParams +=	'</JOURNAL>';
    	 	
    	 	var requestString = formatXmlRequestStr(this.SAVE_METHOD.FOOD, reqStrParams);
    	}
    	else if(this.journalSelect.value == 'life')
    	{
    		if(this.options.hasLifeJournal)
    		{
    			reqStrParams += '<JOURNAL>'+
				        		'<ID>-1</ID>'+
				        		'<TYPE>LIFE</TYPE>'+
				        		'<SUB-TYPE>LIFE_JN</SUB-TYPE>'+
				       			'<DATE>'+ selectedDate +'</DATE>'+
				        		'<TIME>'+ hrs + ":" + min + ":00"+'</TIME>'+
				        		'<STATUS>ACTIVE</STATUS>'+
				        		'<PROTOCOL>'+
				          		'<ID>'+ this.options.lifeJournalId +'</ID>'+
				          		'<VALUE><![CDATA['+ this.lifeJournal.description.value +']]></VALUE>'+
				          		'<JTIME>'+ jTime +'</JTIME>'+
				        		'</PROTOCOL>'+
				      			'</JOURNAL>';
    		}
    		var requestString = formatXmlRequestStr(this.SAVE_METHOD.LIFE, reqStrParams);
    		
    	}
    	else if(this.journalSelect.value == 'exercise')
    	{	      			
    	
    		if(this.options.hasExerciseJournal)
    		{
    			reqStrParams += '<JOURNAL>'+
				        		'<ID>-1</ID>'+
				        		'<TYPE>EXERCISE</TYPE>'+
				        		'<SUB-TYPE>EXERCISE_JN</SUB-TYPE>'+
				       			'<DATE>'+ selectedDate +'</DATE>'+
				        		'<TIME>'+ hrs + ":" + min + ":00"+'</TIME>'+
				        		'<STATUS>ACTIVE</STATUS>'+
				        		'<PROTOCOL>'+
				          		'<ID>'+ this.options.exerciseJournalId +'</ID>'+
				          		'<VALUE><![CDATA['+ this.exerciseJournal.description.value +']]></VALUE>'+
				          		'<JTIME>'+ jTime +'</JTIME>'+
				        		'</PROTOCOL>'+
				      			'</JOURNAL>';
    		}
    	    if(this.options.hasActivityTracker)
    		{
    			for (var i = 1; i < this.activityTracker.textFields.length; i++)
			    {
			      var field = this.activityTracker.textFields[i];
			      
			      reqStrParams += 	'<JOURNAL>'+
					        		'<ID>-1</ID>'+
					        		'<TYPE>EXERCISE</TYPE>'+
					        		'<SUB-TYPE>EXERCISE</SUB-TYPE>'+
					       			'<DATE>'+ selectedDate +'</DATE>'+
					        		'<TIME>'+ hrs + ":" + min + ":00"+'</TIME>'+
					        		'<STATUS>ACTIVE</STATUS>'+
					        		'<PROTOCOL>'+
					          		'<ID>'+ field.id.substr(8,field.id.length) +'</ID>'+
					          		'<VALUE><![CDATA['+ field.value +']]></VALUE>'+
					          		'<JTIME>'+ jTime +'</JTIME>'+
					        		'</PROTOCOL>'+
					      			'</JOURNAL>';
			    }
    		}
    	
    		var requestString = formatXmlRequestStr(this.SAVE_METHOD.EXERCISE, reqStrParams);
    		
    	}
    	else
    	{
    		//do nothing
    	}
    }
    else
    {
    	if(this.entry.type  == 'FOOD')
    	{
    		reqStrParams +=	'<JOURNAL>';
	
	        reqStrParams +=	'<ID>'+this.entry.id+'</ID>'+
				        		'<TYPE>FOOD</TYPE>'+
				        		'<SUB-TYPE>FOOD_JN</SUB-TYPE>'+
				        		'<DESCRIPTION><![CDATA['+ this.foodJournal.description.value +']]></DESCRIPTION>'+
				        		'<DATE>'+ selectedDate +'</DATE>'+
								'<TIME>'+ hrs + ":" + min + ":00"+'</TIME>'+
				        		'<VOICE-URL></VOICE-URL>'+
				        		'<STATUS>ACTIVE</STATUS>'+
						        '<JTIME>'+ jTime +'</JTIME>';
    	 	
    	 	if(this.options.hasMealTracker)
    	 	{
    	 	
    	 		reqStrParams += 	'<MEAL-TRACKER>';
    	 		
    	 		for (var i = 1; i < this.mealTrackerDynamic.textFields.length; i++)
			    {
			      var field = this.mealTrackerDynamic.textFields[i];
			      
			      var protId = field.id.substr(6,field.id.length);
		      	  var responseId = "";
		      
				  for(var j = 0; j<this.entry.metrics.length; j++)
				  {
				  	if(protId == this.entry.metrics[j].id)
				    {
				    	responseId = this.entry.metrics[j].respid;
				      	break;
				    }
				  }
			      
			      reqStrParams +=	'<METRIC>'+
			      					'<METRICID>'+ protId +'</METRICID>'+
			      					'<VALUE><![CDATA['+field.value+']]></VALUE>'+
			      					'<ID>'+responseId+'</ID>'+
			      					'</METRIC>';
					        		
			    }
			    
			    reqStrParams += 	'</MEAL-TRACKER>';
    	 	
    	 		/*reqStrParams +=	'<MEAL-TRACKER>'+
						        '<METRIC>'+this.mealTrackerDynamic.entry.mealTrackerDynamic.metric+'</METRIC>'+
						        '<VALUE>'+this.mealTrackerDynamic.textFields[0].value+'</VALUE>'+
						        '<ID>'+this.mealTrackerDynamic.entry.mealTrackerDynamic.id+'</ID>'+
						        '</MEAL-TRACKER>';*/
    	 	}
    	 	
    	 	if(this.options.hasCalorieEstimator)
    	 	{
    	 		reqStrParams +=	'<DETAILS>'+
          						'<ITEM>'+
            					'<ID>MEAT</ID>'+
            					'<VALUE>'+this.calorieEstimator.textFields[0].value+'</VALUE>'+
            					'<MEASURE>'+this.calorieEstimator.calorieDisplays[0].firstChild.data+'</MEASURE>'+
          						'</ITEM>'+
          						'<ITEM>'+
            					'<ID>GRAINS</ID>'+
            					'<VALUE>'+this.calorieEstimator.textFields[1].value+'</VALUE>'+
            					'<MEASURE>'+this.calorieEstimator.calorieDisplays[1].firstChild.data+'</MEASURE>'+
          						'</ITEM>'+
          						'<ITEM>'+
            					'<ID>DAIRY</ID>'+
            					'<VALUE>'+this.calorieEstimator.textFields[2].value+'</VALUE>'+
            					'<MEASURE>'+this.calorieEstimator.calorieDisplays[2].firstChild.data+'</MEASURE>'+
          						'</ITEM>'+
          						'<ITEM>'+
            					'<ID>FRUITS</ID>'+
            					'<VALUE>'+this.calorieEstimator.textFields[3].value+'</VALUE>'+
            					'<MEASURE>'+this.calorieEstimator.calorieDisplays[3].firstChild.data+'</MEASURE>'+
          						'</ITEM>'+
          						'<ITEM>'+
            					'<ID>FATS</ID>'+
            					'<VALUE>'+this.calorieEstimator.textFields[4].value+'</VALUE>'+
            					'<MEASURE>'+this.calorieEstimator.calorieDisplays[4].firstChild.data+'</MEASURE>'+
          						'</ITEM>'+
          						'<ITEM>'+
						        '<ID>VEGETABLES</ID>'+
						        '<VALUE>'+this.calorieEstimator.textFields[5].value+'</VALUE>'+
						        '<MEASURE>'+this.calorieEstimator.calorieDisplays[5].firstChild.data+'</MEASURE>'+
						        '</ITEM>'+
						        '<ITEM>'+
						        '<ID>SWEETS</ID>'+
						        '<VALUE>'+this.calorieEstimator.textFields[6].value+'</VALUE>'+
						        '<MEASURE>'+this.calorieEstimator.calorieDisplays[6].firstChild.data+'</MEASURE>'+
						        '</ITEM>'+
						        '<TOTAL>'+
						        '<VALUE>'+this.calorieEstimator.servingsTotal.firstChild.data+'</VALUE>'+
						        '<MEASURE>'+this.calorieEstimator.caloriesTotal.firstChild.data+'</MEASURE>'+
						        '</TOTAL>'+
						        '</DETAILS>';
    	 	}
    	 	
    	 	reqStrParams +=	'</JOURNAL>';
    	 	
    	 	var requestString = formatXmlRequestStr(this.SAVE_METHOD.FOOD, reqStrParams);
    	}
    	else if(this.entry.type == 'LIFE')
    	{
    		if(this.entry.subType == 'LIFE_JN')
    		{
    			reqStrParams += '<JOURNAL>'+
				        		'<ID>'+this.entry.id+'</ID>'+
				        		'<TYPE>LIFE</TYPE>'+
				        		'<SUB-TYPE>LIFE_JN</SUB-TYPE>'+
				       			'<DATE>'+ selectedDate +'</DATE>'+
				        		'<TIME>'+ hrs + ":" + min + ":00"+'</TIME>'+
				        		'<STATUS>ACTIVE</STATUS>'+
				        		'<PROTOCOL>'+
				          		'<ID>'+ this.options.lifeJournalId +'</ID>'+
				          		'<VALUE><![CDATA['+ this.lifeJournal.description.value +']]></VALUE>'+
				          		'<JTIME>'+ jTime +'</JTIME>'+
				        		'</PROTOCOL>'+
				      			'</JOURNAL>';
    		}
    		var requestString = formatXmlRequestStr(this.SAVE_METHOD.LIFE, reqStrParams);
    	}
    	else if(this.entry.type == 'EXERCISE')
    	{
    		if(this.entry.subType == 'EXERCISE_JN')
    		{
    			reqStrParams += '<JOURNAL>'+
				        		'<ID>'+this.entry.id+'</ID>'+
				        		'<TYPE>EXERCISE</TYPE>'+
				        		'<SUB-TYPE>EXERCISE_JN</SUB-TYPE>'+
				       			'<DATE>'+ selectedDate +'</DATE>'+
				        		'<TIME>'+ hrs + ":" + min + ":00"+'</TIME>'+
				        		'<STATUS>ACTIVE</STATUS>'+
				        		'<PROTOCOL>'+
				          		'<ID>'+ this.options.exerciseJournalId +'</ID>'+
				          		'<VALUE><![CDATA['+ this.exerciseJournal.description.value +']]></VALUE>'+
				          		'<JTIME>'+ jTime +'</JTIME>'+
				        		'</PROTOCOL>'+
				      			'</JOURNAL>';
    		}
    		
			for (var i = 1; i < this.activityTracker.textFields.length; i++)
		    {
		      	var field = this.activityTracker.textFields[i];
		     	 
		      	var protId = field.id.substr(8,field.id.length);
		      	var responseId = "";
		      
			    for(var j = 0; j<this.entry.activities.length; j++)
			    {
			    	if(protId == this.entry.activities[j].id)
			      	{
			      		responseId = this.entry.activities[j].respid;
			      		break;
			      	}
			    }
		        
				reqStrParams += 	'<JOURNAL>'+
					        		'<ID>'+responseId+'</ID>'+
					        		'<TYPE>EXERCISE</TYPE>'+
					        		'<SUB-TYPE>EXERCISE</SUB-TYPE>'+
					       			'<DATE>'+ selectedDate +'</DATE>'+
					        		'<TIME>'+ hrs + ":" + min + ":00"+'</TIME>'+
					        		'<STATUS>ACTIVE</STATUS>'+
					        		'<PROTOCOL>'+
					          		'<ID>'+ protId +'</ID>'+
					          		'<VALUE><![CDATA['+ field.value +']]></VALUE>'+
					          		'<JTIME>'+ jTime +'</JTIME>'+
					        		'</PROTOCOL>'+
					      			'</JOURNAL>';
			}
    	
    		var requestString = formatXmlRequestStr(this.SAVE_METHOD.EXERCISE, reqStrParams);
    	}
    	else
    	{
    		//do nothing
    	}
    }
    
    var request = YAHOO.util.Connect.asyncRequest('POST', this.SERVLET,
    {
      success: this.updateJournalDisplay,
      failure: this.reportFailure,
      argument: [this]
    }, requestString);
    
    return true;
  },
  
  /* The AJAX failed. Tell the user */
  reportFailure: function(obj)
  {
    alert('Unable to save changes. Please try again later.');
  },
  
  /* The AJAX succeeded. Reload the page to show the new review date. */ 
  updateJournalDisplay: function(obj)
  {
    // refresh the page.
    var formobj = this.argument[0];
    window.location.href = "http://"+window.location.host + window.location.pathname + "?pplid="+formobj.patientId+"&date="+formobj.selectedQDate;
    //window.location.reload(false);
  },
  
  /* Event handler for a dialog submit. */
  onsubmit: function(eventName, args, me)
  {
    return me.saveForm();
  },
  
  onDelete:function()
  {
	var reqStrParams = "";
	if(this.entry.type  == 'FOOD')
	{
		reqStrParams +=	'<JOURNAL>'+
							'<JID>'+this.entry.id+'</JID>'+
						'</JOURNAL>';
						
	
		if(this.options.hasMealTracker)
    	{
			for (var i = 1; i < this.mealTrackerDynamic.textFields.length; i++)
		    {
		      var field = this.mealTrackerDynamic.textFields[i];
		      
		      var protId = field.id.substr(6,field.id.length);
	      	  var responseId = "";
	      
	      		if(this.entry.metrics)
	      		{
				  for(var j = 0; j<this.entry.metrics.length; j++)
				  {
				  	if(protId == this.entry.metrics[j].id)
				    {
				    	responseId = this.entry.metrics[j].respid;
				      	break;
				    }
				  }
			      
			      reqStrParams +=	'<JOURNAL>'+
					    			'<JID>'+responseId+'</JID>'+
					    			'</JOURNAL>';
				}        		
		    }
		}
						
	 	
	 	var requestString = formatXmlRequestStr(this.DELETE_METHOD, reqStrParams);
	}
	else if(this.entry.type == 'LIFE')
	{
		if(this.entry.subType == 'LIFE_JN')
		{
			reqStrParams += '<JOURNAL>'+
			        		'<JID>'+this.entry.id+'</JID>'+
			      			'</JOURNAL>';
		}
		var requestString = formatXmlRequestStr(this.DELETE_METHOD, reqStrParams);
	}
	else if(this.entry.type == 'EXERCISE')
	{
		if(this.entry.subType == 'EXERCISE_JN')
		{
			reqStrParams += '<JOURNAL>'+
			        		'<JID>'+this.entry.id+'</JID>'+
			      			'</JOURNAL>';
		}
		
		for (var i = 1; i < this.activityTracker.textFields.length; i++)
	    {
	      	var field = this.activityTracker.textFields[i];
	     	 
	      	var protId = field.id.substr(8,field.id.length);
	      	var responseId = "";
	      
		    for(var j = 0; j< this.entry.activities.length; j++)
		    {
		    	if(protId == this.entry.activities[j].id)
		      	{
		      		responseId = this.entry.activities[j].respid;
		      		break;
		      	}
		    }
	        
			reqStrParams += 	'<JOURNAL>'+
				        		'<JID>'+responseId+'</JID>'+
				      			'</JOURNAL>';
		}
	
		var requestString = formatXmlRequestStr(this.DELETE_METHOD, reqStrParams);
	}
	else
	{
		//do nothing
	}
    
    var request = YAHOO.util.Connect.asyncRequest('POST', this.SERVLET,
    {
      success: this.updateJournalDisplay,
      failure: this.reportFailure,
      argument: [this]
    }, requestString);
    
    return true;
  }
}

/* Base class for form handling with simple validation */
var Form = function(formId)
{
  this.form = YAHOO.util.Dom.get(formId);
  this.textFields = [];
  this.selectFields = [];
  this.selectDefaults = [];
  this.validators = [];
}

Form.prototype =
{
  /* Clears the form fields */
  clearForm: function()
  {
    FormUtils.clearTextFields(this.textFields);
    FormUtils.selectDefaults(this.selectFields, this.selectDefaults);
    // TODO Implement for checkboxes and radio buttons.
  },
  
  /* True if the form is valid. Validates the form fields using validators */
  isFormValid: function()
  {
    for (var i = 0; i < this.validators.length; i++)
    {
      if (!this.validators[i].isValid())
      {
        return false;
      }
    }
    return true;
  },
  
  /* Returns an array of error messages for invalid form fields. */
  getErrors: function()
  {
    var result = [];
    for (var i = 0; i < this.validators.length; i++)
    {
      var errorMessage = this.validators[i].getError();
      if (errorMessage != '')
      {
        result[result.length] = errorMessage;
        
      }
    }
    return result;
  }
}

/* Subclass of form. Base class for edit journal mini forms. */
var JournalSubForm = function(formId)
{
  JournalSubForm.superclass.constructor.call(this, formId);
}

YAHOO.lang.extend(JournalSubForm, Form,
{
  setJournalEntry: function(journalEntry)
  {
    this.entry = journalEntry;
    this.updateForm();
  },
  
  updateForm: function()
  {
    // To be overridden by subclasses.
  },
  
  displayForm: function(isDisplayed)
  {
    this.form.style.display = isDisplayed ? '' : 'none';
  }
});

/* Mini form handling for the exercise journal */
var ExerciseJournalSubForm = function(formId)
{
  ExerciseJournalSubForm.superclass.constructor.call(this, formId);
  
  this.description = YAHOO.util.Dom.get('exerciseDetails');
  
  this.textFields = [ this.description ];
  this.validators = [ new FormUtils.RequiredValidator(this.description, 'Please enter details for the exercise journal.') ];
}

YAHOO.lang.extend(ExerciseJournalSubForm, JournalSubForm,
{
  updateForm: function()
  {
    this.description.value = this.entry.description;
  }
});

/* Mini form handling for the life journal */
var LifeJournalSubForm = function(formId)
{
  LifeJournalSubForm.superclass.constructor.call(this, formId);
  
  this.description = YAHOO.util.Dom.get('lifeDetails');
  
  this.textFields = [ this.description ];
  this.validators = [ new FormUtils.RequiredValidator(this.description, 'Please enter details for the life journal.') ];
}

YAHOO.lang.extend(LifeJournalSubForm, JournalSubForm,
{
  updateForm: function()
  {
    this.description.value = this.entry.description;
  }
});

/* Mini form handling for the activity tracker */
var ActivityTrackerSubForm = function(formId)
{
  ActivityTrackerSubForm.superclass.constructor.call(this, formId);
  
  this.table = new DataTable(this.form, []);
}

YAHOO.lang.extend(ActivityTrackerSubForm, JournalSubForm,
{
  updateForm: function()
  {
    for (var i = 0; i < this.textFields.length; i++)
    {
      var field = this.textFields[i];
      var matches = field.id.match(/activity(\d+)/);
      if (matches)
      {
        var activity = this.entry.getActivityById(matches[1]);
        if (activity)
        {
          field.value = activity.value;
        }
        else
        {
          field.value = 0;
        }
      }
    }
  },
  
  /* Loads the activities into the form table */
  loadFields: function(activities)
  {
    this.table.displayData(activities, this.fillActivityDataRow);
  
    var fields = YAHOO.util.Dom.getElementsByClassName('minute', 'input', this.form);
    var activities = YAHOO.util.Dom.getElementsByClassName('exercise', 'td', this.form);
    
    this.textFields = [];
    this.validators = [];
    for (var i = 0; i < fields.length; i++)
    {
      var field = fields[i];
      this.textFields[i] = field;
      this.validators[i] = new FormUtils.IntValidator(field, 'Please enter a whole number for activity "' + activities[i].innerHTML + '".');
    }
  },
  
  /* Fills a data row for the exercise activity table */
  fillActivityDataRow: function(row, activity)
  {
    var exerciseEl = YAHOO.util.Dom.getElementsByClassName('exercise', 'td', row)[0];
    exerciseEl.innerHTML = (activity.protocolDisplayName != null && activity.protocolDisplayName != '') ? activity.protocolDisplayName : activity.protocolName;
    
    var minuteEl = YAHOO.util.Dom.getElementsByClassName('minute', 'input', row)[0];
    minuteEl.id = 'activity' + activity.protocolId;
    minuteEl.name = 'activity' + activity.protocolId;
  }
});

/* Mini form handling for the food journal */
var FoodJournalSubForm = function(formId)
{
  FoodJournalSubForm.superclass.constructor.call(this, formId);
  
  this.description = YAHOO.util.Dom.get('foodDetails');
  
  this.textFields = [ this.description ]
  this.validators = [ new FormUtils.RequiredValidator(this.description, 'Please enter details for the food journal.') ];
}

YAHOO.lang.extend(FoodJournalSubForm, JournalSubForm,
{
  updateForm: function()
  {
    this.description.value = this.entry.description;
  }
});

/* Mini form handling for the meal tracker */
var MealTrackerSubForm = function(formId)
{
  MealTrackerSubForm.superclass.constructor.call(this, formId);
  
  this.tracker = YAHOO.util.Dom.get('mealTrackerCount');
  
  this.textFields = [ this.tracker ]
  this.validators = [ new FormUtils.FloatValidator(this.tracker, 'Please enter a number value for meal tracker.') ];
}

YAHOO.lang.extend(MealTrackerSubForm, JournalSubForm,
{
  updateForm: function()
  {
    this.tracker.value = this.entry.mealTracker.value;
  }
});

var MealTrackerDynamicSubForm = function(formId)
{
  MealTrackerDynamicSubForm.superclass.constructor.call(this, formId);
  
  this.table = new DataTable(this.form, []);
}

YAHOO.lang.extend(MealTrackerDynamicSubForm, JournalSubForm,
{
  updateForm: function()
  {
    for (var i = 0; i < this.textFields.length; i++)
    {
      var field = this.textFields[i];
      var matches = field.id.match(/metric(\d+)/);
      if (matches)
      {
        var metric = this.entry.getMetricById(matches[1]);
        if (metric)
        {
          field.value = metric.value;
        }
        else
        {
          field.value = 0;
        }
      }
    }
  },
  
  /* Loads the activities into the form table */
  loadFields: function(metrics)
  {
    this.table.displayData(metrics, this.fillMetricDataRow);
  
    var fields = YAHOO.util.Dom.getElementsByClassName('measure', 'input', this.form);
    var metrics = YAHOO.util.Dom.getElementsByClassName('metric', 'td', this.form);
    
    this.textFields = [];
    this.validators = [];
    for (var i = 0; i < fields.length; i++)
    {
      var field = fields[i];
      this.textFields[i] = field;
      this.validators[i] = new FormUtils.IntValidator(field, 'Please enter a whole number for metric "' + metrics[i].innerHTML + '".');
    }
  },
  
  /* Fills a data row for the exercise activity table */
  fillMetricDataRow: function(row, metric)
  {
    var metricEl = YAHOO.util.Dom.getElementsByClassName('metric', 'td', row)[0];
    metricEl.innerHTML = metric.protocolName;
    
    var measureEl = YAHOO.util.Dom.getElementsByClassName('measure', 'input', row)[0];
    measureEl.id = 'metric' + metric.protocolId;
    measureEl.name = 'metric' + metric.protocolId;
  }
});

var CalorieEstimatorSubForm = function(formId, calorieEstimatorCallback)
{
  CalorieEstimatorSubForm.superclass.constructor.call(this, formId);
  
  this.calorieEstimator = calorieEstimatorCallback;
  
  this.textFields = []
  this.validators = [];
  this.calorieDisplays = [];

  var table = YAHOO.util.Dom.get('calorieEstimator');
  var rows = table.getElementsByTagName('tr');
  var fieldCounter = 0;
  for (var i = 0; i < rows.length; i++)
  {
    var row = rows[i];

    // Get the total elements from the summary row.
    if (YAHOO.util.Dom.hasClass(row, 'summary'))
    {
      this.servingsTotal = YAHOO.util.Dom.getElementsByClassName('servings', 'td', row)[0];
      this.caloriesTotal = YAHOO.util.Dom.getElementsByClassName('calories', 'td', row)[0];
      continue;
    }
  
    var fields = YAHOO.util.Dom.getElementsByClassName('serving', 'input', row);
    if (fields.length > 0)
    {
      var field = fields[0];
      var foodGroup = YAHOO.util.Dom.getElementsByClassName('food', 'td', row)[0].innerHTML;

      this.textFields[fieldCounter] = field;
      this.validators[fieldCounter] = new FormUtils.IntValidator(field, 'Please enter a whole number for "' + foodGroup + '".');
      this.calorieDisplays[fieldCounter] = YAHOO.util.Dom.getElementsByClassName('calories', 'td', row)[0];
      
      YAHOO.util.Event.addListener(field, 'change', this.updateCalorieDisplay, fieldCounter, this);
      fieldCounter++;
    }
  }
}

YAHOO.lang.extend(CalorieEstimatorSubForm, JournalSubForm,
{
  updateForm: function()
  {
    for (var i = 0; i < this.calorieDisplays.length; i++)
    {
      var field = this.textFields[i];
      var calorieDisplay = this.calorieDisplays[i];
      
      var calorieItem = this.entry.getCalorieItemById(field.id);

      if (calorieItem)
      {
        field.value = calorieItem.value;
        calorieDisplay.innerHTML = calorieItem.measure;
      }
      else
      {
        field.value = 0;
        calorieDisplay.innerHTML = 0;
      }
    }
    
    this.updateTotals();
  },
  
  updateTotals: function()
  {
    var servings = 0;
    var calories = 0;
    for (var i = 0; i < this.calorieDisplays.length; i++)
    {
      servings += this.getServings(i);
      calories += this.getCalories(i);
    }
    
    this.servingsTotal.innerHTML = servings;
    this.caloriesTotal.innerHTML = calories;
  }, 
  
  clearForm: function()
  {
    CalorieEstimatorSubForm.superclass.clearForm.call(this);
    for (var i = 0; i < this.calorieDisplays.length; i++)
    {
      this.calorieDisplays[i].innerHTML = 0;
    }

    this.servingsTotal.innerHTML = 0;
    this.caloriesTotal.innerHTML = 0;
  },
  
  getServings: function(index)
  {
    var field = this.textFields[index];
    var servings = parseInt(field.value);
    return isNaN(servings) ? 0: servings; 
  },
  
  getCalories: function(index)
  {
    return parseFloat(this.calorieDisplays[index].innerHTML);
  },
  
  getFoodGroup: function(index)
  {
    return this.textFields[index].id;
  },
  
  /* Event handler for a change in the servings entries */
  updateCalorieDisplay: function(e, fieldIndex)
  {
    var calorieDisplay = this.calorieDisplays[fieldIndex];
    var foodGroup = this.getFoodGroup(fieldIndex);
    var servings = this.getServings(fieldIndex);
    calorieDisplay.innerHTML = this.calorieEstimator(servings, foodGroup);
    
    this.updateTotals();
  }
});

/* Calorie Estimator strategy object */
var CalorieEstimator = function()
{
  this.CALORIE_MULTIPLIERS = {  meat: 150, grains: 80, dairy: 90, fruits: 60, fats: 45, veg: 25, sweets: 80 };
}

CalorieEstimator.prototype =
{
  estimateCalories: function(servings, foodGroup)
  {
    var multiplier = this.CALORIE_MULTIPLIERS[foodGroup.toLowerCase()];
    // If the multiplier wasn't found, make it 1.
    multiplier = (multiplier) ? multiplier : 1;
    return servings * multiplier;
  }
}

/* Utilities for managing HTML forms */
var FormUtils =
{
  /* Clears the values for an array of text fields */
  clearTextFields: function(textFields)
  {
    for (var i = 0; i < textFields.length; i++)
    {
      var field = YAHOO.util.Dom.get(textFields[i]);
      field.value = '';
    }
  },
  
  /* Sets the default selected values for an array of select fields */
  selectDefaults: function(selectFields, defaults)
  {
    for (var i = 0; i < selectFields.length; i++)
    {
      var field = YAHOO.util.Dom.get(selectFields[i]);
      var theDefault = defaults[i];
      setSelectValue(field, theDefault);
    }
  }
};

/* Abstract base class for a validator object */
FormUtils.Validator = function(fieldId, errorMessage)
{
  this.field = YAHOO.util.Dom.get(fieldId);
  this.errorMessage = errorMessage;
}

FormUtils.Validator.prototype =
{
  /* Gets the value of a field */
  /* Returns a scalar value for all field types except checkbox which returns an array of values */
  getFieldValue: function()
  {
    switch (this.field.tagName.toLowerCase())
    {
      case 'input':
        switch (this.field.getAttribute('type').toLowerCase())
        {
          case 'text':
          case 'password':
          case 'hidden':
          case 'file':
          case 'submit':
          case 'reset':
          case 'button':
          case 'image':
            return this.field.value;
          case 'checkbox':
            return getCheckboxValue(this.field);
          case 'radio':
            return getRadioValue(this.field);
        }
        break;
      case 'select':
        return getSelectValue(this.field);
      case 'textarea':
      default:
        return this.field.value;
    }
  },
  
  /* Checks if the field is valid */
  /* If the field is a checkbox, validates against all checked values. */
  isValid: function()
  {
    var value = this.getFieldValue();
    if (YAHOO.lang.isArray(value))
    {
      for (var i = 0; i < value.length; i++)
      {
        if (!this.isValidValue(value[i]))
        {
          return false;
        }
      }
      return true;
    }
    else
    {
      return this.isValidValue(value);
    }
  },
  
  /* Validates a single value */
  isValidValue: function(value)
  {
    // To be overridden by subclasses.
    return true;
  },
  
  /* Returns the error message if the field is invalid */
  getError: function()
  {
    return (this.isValid()) ? '' : this.errorMessage;
  }
}

/* Validator for required fields */
FormUtils.RequiredValidator = function(fieldId, errorMessage)
{
  FormUtils.RequiredValidator.superclass.constructor.call(this, fieldId, errorMessage);
}

YAHOO.lang.extend(FormUtils.RequiredValidator, FormUtils.Validator,
{
  isValid: function()
  {
    var value = this.getFieldValue();
    if (YAHOO.lang.isArray(value))
    {
      // Just make sure at least one checkbox is checked.
      return (value.length > 0);
    }
    else
    {
      // Zero or more spaces is invalid.
      var matches = value.match(/^\s*$/);
      return (!matches || matches.length == 0);
    }
  }
});

/* Validates the field against a regular expression */
FormUtils.RegExpValidator = function(fieldId, regExp, errorMessage)
{
  FormUtils.RegExpValidator.superclass.constructor.call(this, fieldId, errorMessage);
  this.regExp = regExp;
}

YAHOO.lang.extend(FormUtils.RegExpValidator, FormUtils.Validator,
{
  isValidValue: function(value)
  {
    var matches = value.match(this.regExp);
    return (matches && matches.length > 0);
  }
});

/* Validates that the field has an integer value */
FormUtils.IntValidator = function(fieldId, errorMessage)
{
  FormUtils.IntValidator.superclass.constructor.call(this, fieldId, errorMessage);
}

YAHOO.lang.extend(FormUtils.IntValidator, FormUtils.Validator,
{
  isValidValue: function(value)
  {
    return (value != "" && !isNaN(parseInt(value)));
  }
});

/* Validates that the field has a float value */
FormUtils.FloatValidator = function(fieldId, errorMessage)
{
  FormUtils.FloatValidator.superclass.constructor.call(this, fieldId, errorMessage);
}

YAHOO.lang.extend(FormUtils.FloatValidator, FormUtils.Validator,
{
  isValidValue: function(value)
  {
    return (value != "" && !isNaN(parseFloat(value)));
  }
});

/*
* END Object Classes
*/


function PlayAudio(id,playUrl)
{
	var zl=0;  
	var audioPlayer = document.getElementById("audioPlayer"); 
	var audioPlayerObjContainer = document.getElementById("audioPlayerObjContainer");
	audioPlayerObjContainer.innerHTML =""; 
	//audioPlayerObjContainer.innerHTML = "<embed id='audioPlayerObj' name='audioPlayerObj' src='../AudioFiles/ProcessAudioFile?attachment_id="+id+"&filename="+id+".wav&sav=a&url=http://<%=request.getServerName().toString()%>/ZumeLifePortal/GetVoiceFile?attachment_id="+id+"' width='120' height='40' autostart='true' loop='false'></embed>";
	audioPlayerObjContainer.innerHTML = "<embed id='audioPlayerObj' name='audioPlayerObj' src='"+playUrl+"' width='120' height='40' autostart='true' loop='false'></embed>";
	audioPlayer.style.backgroundColor = "#e4f4fb";
	audioPlayer.style.position   = "absolute";
	audioPlayer.style.visibility = "visible";
	audioPlayer.style.display    = "block";
	audioPlayer.style.left = xMousePos  +'px';
	audioPlayer.style.top  = yMousePos  +'px';
	currAID = id;
}

function LTrim( value ) 

{

	var re = /\s*((\S+\s*)*)/;

	return value.replace(re, "$1");

}



// Removes ending whitespaces

function RTrim( value ) 

{

	var re = /((\s*\S+)*)\s*/;

	return value.replace(re, "$1");

}



// Removes leading and ending whitespaces

function Trim( value ) 

{

	return LTrim(RTrim(value));

}
function roundNumber(num, dec) {
	var result = Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
	return result;
}
function isNumericValue(value,low,high){
	var numericExpression = /^[0-9]+$/;
	if(value.match(numericExpression)){
		if(value<=low || value >= high)
			return false;
		else
			return true;
	}else{
		return false;
	}
}
function isNumeric(elem,low,high){
	var numericExpression = /^[0-9]+$/;
	if(elem.value.match(numericExpression)){
	
		if(elem.value<=low || elem.value >= high)
			return false;
		else
			return true;
	}else{
		
		elem.focus();
		return false;
	}
}
function isDecimal(elem,low,high){
	var regExp = /^([1-9]{1}[0-9]{0,}(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|\.[0-9]{1,2})$/;
	if(elem.value.match(regExp)){
	
		if(elem.value<=low || elem.value >= high)
			return false;
		else
			return true;
	}else{
		
		elem.focus();
		return false;
	}
}
function isEmail(elem){
	var regExp = /([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})/;
	if(elem.value.match(regExp)){
		return true;
	}else{
		elem.focus();
		return false;
	}
}
