function logged_in() {
  return ($('logged_in') ? true : false); // checks the left nav
}
function isIE() {
  return ($$('body.ie').length > 0 ? true : false);
}

function actionBox(t, data) { 
  window.scrollTo(0,0);
  if ( in_array( t, new Array('job','wizard-step-1','wizard-step-2','wizard-step-3')) || t.match('registration-wizard')) {
    $('dialogBox').removeClassName('thin-lightbox-popup');
    $('dialogBox').addClassName('wide-lightbox-popup');
  } else {
    $('dialogBox').removeClassName('wide-lightbox-popup');
    $('dialogBox').addClassName('thin-lightbox-popup');
  }
  actionElement(t, data, 'dialogBox');
}

// actionElement is just like actionBox, except that it inserts the stuff into
// an element, whose id you give
function actionElement(t, data, element_id) {
  var url = 'include/ajaxscripts/popups/'+t ;
  displayLoad(element_id);
  var options = {method: 'post', parameters: { data: data }};         
  new Ajax.Updater(element_id, url, options );  
}


function displayLoad( element_id, message ) {
  var offsets = document.viewport.getScrollOffsets();
  var offsetTop = offsets[1];
  var default_message = "Loading... thanks for waiting";
  $(element_id).innerHTML = '<div class="loader" style="font-size:1.6em;font-weight:bold;text-align:center;margin-top:50px;"><img src="img/indicator_lg.gif" /><br />'+(message ? message : default_message)+'</div>';
  $(element_id).style.top = (offsetTop + 100) + "px";
  if( element_id == 'dialogBox' ) {
    showDialog();
  } else {
    $(element_id).show();
  }
}

//Check Password Strength (for registration page)
function passwordStrength(input, element_id) {
  if (input.length > 4) {
    $('row-insert').show();
    var url = 'include/ajaxscripts/password-strength';
    var options = {method:'post', parameters: "destination="+element_id+"&v="+input}
    new Ajax.Updater(element_id, url, options);
  } else {
    $('row-insert').hide();
  }
}

//Get Help Text
function getHelpText(topic, element_id) {
  var url = 'include/ajaxscripts/help';
  var options = {method:'post', parameters: 'topic='+topic}
  new Ajax.Updater(element_id, url, options);
}


function loadArticles(page_id) {
  var url = 'include/ajaxscripts/get-articles?page_id='+page_id;
  var myAjax = new Ajax.Request(url);
}

function searchAndShowArticles(page_id, element_id, display_type) {
  var url = 'include/ajaxscripts/get-articles?page_id='+page_id+'&show=1&display_type='+display_type;
  var myAjax = new Ajax.Updater(element_id, url);
}

/* inserts what's normally a popup into a div (destination) */
function insertPopupIntoDiv(filename, div_id)
{
  var url = 'include/ajaxscripts/popups/' + filename;
  var options = {method: 'get', parameters: {}}
  $(div_id).show();
  displayLoad(div_id);
  new Ajax.Updater(div_id, url, options); 
}

function showDialog()
{
  $('dialogBox').show();
  $('lb').show();
}

function hideDialog() {
hidePopup('dialogBox');
}

function hideFireflyJar() {
hidePopup('container-profile-edit');
$('container-profile-edit').innerHTML = $('container-profile-edit-loading').innerHTML;
}

function hidePopup( id ) {
  $(id).hide();
  //$('lb').hide();
  //new Effect.Fade( id , { duration: 0.2 });
  //new Effect.Fade('lb', { duration: 0.2 });
  $('lb').hide();
}

// Effect.Highlight won't work properly if you just call it on the biggest element
function highlightCategoryBox(alias, page_id) {
  var duration = 3;
  $(alias+'_jar_ul').show();
  if($('jar_page_'+page_id)) {
    new Effect.Highlight($('jar_page_'+page_id), {duration:10.0});
    duration = 0.5;
  } else {
    var container_id = (alias ? 'left_nav_'+alias : 'left-nav'); 
    var container_id = ($(container_id) ? container_id : 'left-nav'); // ensure the box exists;
    var options = {duration: duration};
    // get the element with id=container_id, and all elements within that have class=highlightable
    var elements = $$('#'+container_id+' *.highlightable');
    // highlight each element individually
    for(var i=0; i < elements.length; i++) {
      new new Effect.Highlight(elements[i], options);
    }
  }
}

function togglePages(element) 
{
  var hiddenPages = $('subnavLeft').getElementsBySelector('ul.pages li.hidden');
  for (i = 0; i < hiddenPages.length; i++) {
    hiddenPages[i].toggle();
  }    
}

function toggleBlind(element_id) {
  var element = $(element_id);
  var options = {duration: 0.2};
  var func = element.visible() ? Effect.BlindUp : Effect.BlindDown;
  func(element_id, options);
}
function addAutocompleter()
{
  new Ajax.Autocompleter('ac', 'acc', 'include/ajaxscripts/get-friends-info.php', { minChars:2, indicator: 'indicator1', paramName: 'input', updateElement: addFriend, login_not_required:"true" });
}

function removeFriend(id) 
{
  $(id).remove();
}


function submitShare(form_id) {
  var data = $(form_id).serialize(true);
  displayLoad('dialogBox', "Next Step...");
  new Ajax.Updater('dialogBox', 'include/ajaxscripts/popups/share_comment', {parameters: data});
}

function submitShareComment(form_id, comment) {
  data = $(form_id).serialize(true);
  if(!comment) {
    data['comment'] = null;
  }
  displayLoad('dialogBox', "Submitting...");
  new Ajax.Updater('dialogBox', 'include/ajaxscripts/share-process', {parameters:data});
}



function addFriend(li)
{
  $('empty-message').hide();
  var exists = $('user-'+li.id);

  if (!exists) {
    var target = $('friends-list');
    $('status-bar').show();
    var url = 'include/ajaxscripts/get-friends-info';
  
    new Ajax.Request(url, {
      parameters: { uid: li.id, login_not_required: "true" },
      onSuccess: function (transport) {
        new Insertion.Top('friends-list', transport.responseText);
      }
    });
  } else {
    new Effect.Highlight('user-'+li.id, { duration: 3 });
  }
 
  $('status-bar').hide();
  $('ac').value = '';
  $('ac').focus();
}


function addEmail()
{
  $('empty-message').hide();

  var email = $('email_input').value;
  $('email_input').value = ""; 
  var url = 'include/ajaxscripts/get-friends-info';
  
  new Ajax.Request(url, {
    parameters: { email: email, login_not_required: "true" },
    onSuccess: function (transport) {
      new Insertion.Top('friends-list', transport.responseText);
    }
  });
}

function addMembership(form_data, callback)
{ 
  var page_id = form_data['page_id'];//$F(input);
  var page_type = form_data['page_type'].split('-')[0];
  var url = 'include/ajaxscripts/add-membership.php';
  var topicBox = new Ajax.Request( url, {method: 'post', 
                  parameters: form_data, 
                  onComplete: createRefreshLeftNav(page_id, page_type, callback)
                  });
}

function createRefreshLeftNav(page_id, page_type_alias, callback) 
{
  return function(t) {
          if(page_id && page_type_alias) {
            next = function(t){ highlightCategoryBox(page_type_alias, page_id);};
          } else {
            next = function(t){};
          }
              var url = 'include/ajaxscripts/refresh-page-list.php';
              showCentralNav('apps/central_nav/fragments/status/' + page_id);
              new Ajax.Updater('left-nav', url, { parameters: { id: page_id }, onComplete:next});
              callback();
  }
}

function refreshApplicationList() {
  var url = 'include/ajaxscripts/refresh-application-list.php';
  new Ajax.Updater('header_application_list', url, {});
}




function showShareComponent( item_type, item_id )
{
  displayLoad( 'invite_members' );
  var options = { item_type: item_type, item_id: item_id };
  var url = 'include/ajaxscripts/share-display.php';
  new Ajax.Updater( 'invite_members', url, { parameters: options } );
}

function in_array( needle, haystack )
{
  for( var i = 0; i < haystack.length; i++ ) {
    if( needle == haystack[i] ) return true;
  }
  return false;
}

function confirmRequest(type, id, status)
{
  var offsets = document.viewport.getScrollOffsets();
  var offsetTop = offsets[1];

  $('dialogBox').innerHTML = '<div class="loader" style="font-size:1.6em;font-weight:bold;text-align:center;margin-top:50px;"><img src="img/indicator_lg.gif" /><br />loading data...</div>';
  $('dialogBox').style.top = (offsetTop + 100) + "px";
  showDialog();

  var url = 'include/ajaxscripts/request-confirm';
	var pars = {type: type, id: id, status:status};
  var myAjax = new Ajax.Updater('dialogBox', url, {method: 'post', parameters: pars});
}

function sendHug(data) 
{
  displayLoad('dialogBox', "Sending Hug...");
  var url = 'include/ajaxscripts/hug';
  var hugBox = new Ajax.Updater('dialogBox', url, {method: 'post', parameters: { data: data }});
}

function sendFriendRequest(form)
{
  var data = $(form).serialize(true);
  displayLoad('dialogBox', 'Sending Friend Request...');
  var url = 'include/ajaxscripts/add-friend';
  var friendBox = new Ajax.Updater('dialogBox', url, {method: 'post', parameters: data });
  $('connectButton').className = "subscribed";
  $('connectButton').innerHTML = "Connected";
}
function followProfile(form) {
  var data = $(form).serialize(true);
  var url = 'include/ajaxscripts/follow-profile';
  new Ajax.Updater('dialogBox', url, {method: 'post', parameters: data, onComplete:function(t){ $('following_action').hide(); } });
}
function ie_log( str )
{
  e = document.getElementById( 'ie_error_message' );
  e.innerHTML = e.innerHTML  + "<br />" + str;
}

function createPublicProfile(data, callback)
{
  var url = 'include/ajaxscripts/create-public-profile.php';
  var options = {
                parameters: { data: data },
                onComplete: function(t)
                { console.log('onComplete');
                  if(callback) {
                    callback();
                  } else {
                    if(t.responseText) {
                      window.location = t.responseText;
                    } else {
                      createRefreshLeftNav()();
                    }
                  }
                }
  };    
  hideDialog();
  new Ajax.Request( url, options );
}

function addApplication( app_id, form_id ) {
  var url = 'include/ajaxscripts/add-application.php';
  var options = { parameters: $(form_id).serialize(true), onComplete:hideDialogAndRefresh } ;
  new Ajax.Request( url, options );
}

function hideDialogAndRefresh()
{
  hideDialog();
  location.reload(true);
}

function paginatePrev( prev_start, form_id  )
{
  var child = new Element('input', { type: 'hidden', name: 'prev', value: prev_start });
  $( form_id ).appendChild( child ); 
  $( form_id ).submit();
}

function paginateNext( next_start, form_id )
{
  var child = new Element('input', { type: 'hidden', name: 'next', value: next_start });
  $( form_id ).appendChild( child ); 
  $( form_id ).submit();
}

function updateSubscriptionFrequency( form_id ) {
  var data = $(form_id).serialize(true);
  var url = 'include/ajaxscripts/update-subscription-frequency.php';
  new Ajax.Request( url, {parameters: data,
                        onSuccess: function(t) {
                          $(form_id+"_notice").innerHTML = "<div class='notice success'>Saved</div>";
                          $(form_id+"_notice").show();
                          Effect.Fade( form_id+'_notice', { duration: 2.0 } );
                        }
  } );
}
  
function editPageDetails(page_id, page_type_alias){ 
  var open_and_scroll = function() {
    var e = $('pageli_'+page_id);
    var offset = e.cumulativeOffset();
    e.scrollTo(offset.top, offset.left);
  
    submitFragment('status-'+page_id, 'apps/p_h_r/fragments/edit-page/'+page_id); 
    $('status-'+page_id).show();
  }
  return openEditPHR(page_type_alias, false, false, open_and_scroll);
}
              
function openFireflyJarSection(url, callback) {
  $('lb').show();
  if(!$('container-profile-edit-loading').innerHTML) {
    $('container-profile-edit-loading').innerHTML = $('container-profile-edit').innerHTML;
  }
  $('container-profile-edit').show();
  new Ajax.Request(url, {onComplete: function (t) {
    $('container-profile-edit').innerHTML = t.responseText;
    window.scrollTo(0, 0);
    callback();
  }});
 return false;
}

function openEditProfile(section) {
	return openFireflyJarSection("apps/profile/fragments/edit" + (section ? '/' + section : ''));
}

function sendFamilyInvite() {
  var email = $('invite_email').value; // email address to send to
  var name = $('invite_name').value; // the name of the inviter
  if(!email) {
    $('family_invite_feedback').innerHTML = "<div class='notice error'>Please enter a valid email address</div>";
    new Effect.Pulsate('invite_email');
    return false;
  } else if(!name) {
    $('family_invite_feedback').innerHTML = "<div class='notice error'>Please enter your name.</div>";
    new Effect.Pulsate('invite_name');
    return false;
  }
  var url = 'include/ajaxscripts/send-family-invite.php';
  var options = {
    parameters:{ email:email, name:name }, 
    onFailure:function(t) {
      $('family_invite_feedback').innerHTML = "<div class='notice error'>We were unable to send the email.</div>";
    },
    onSuccess:function(t) {
      if(t.responseText == "bad_email"){
        $('family_invite_feedback').innerHTML = "<div class='notice error'>We were unable to send the email.</div>"; 
        return false;
      }
      $('family_invite_feedback').innerHTML = "<div class='notice success'>Your email has been sent.</div>";
      $('invite_submit').hide();
    } 
  };
  $('family_invite_feedback').innerHTML = "<div class='notice message'><img src='img/indicator.gif' /> Sending email...</div>";
  new Ajax.Request(url, options);
  
}
function openEditPHR(section, sort, filter, callback) {
  var sign = (sort ? '&' : '?');
  return openFireflyJarSection("apps/p_h_r/fragments/edit"+(section ? '/' + section : '')+(sort ? '?sort='+sort : '')+(filter ? sign+'filter='+filter : ''), callback);
}

function submitFragment(target, url, form) {
	if($(target)) {
		var pars = $(form) ? $(form).serialize(true) : null;
		new Ajax.Updater(target, url, { method: 'post', parameters: pars });
	}
	return false;
}  

/* @post registration wizard code (TODO: cleanup and separate out as necessary) */


function showWizard(cat_id) {
  actionBox( 'wizard-step-1', cat_id );
}


function highlightCategory( num ) {
  for( var i = 0; i < 6; i++ ) {
    if( num == i ) {
      $('wiz_cat_'+i).setAttribute('style', 'font-weight:bold' );
    } else {
      $('wiz_cat_'+i).setAttribute('style', '' );
    }
  }
}


function highlightPopular() {
  $('wiz_sort_popular').setAttribute('style', 'font-weight:bold;text-decoration:underline;' );
  var letters = new Array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' );
  for( var i = 0; i < letters.length; i++ ) {
    $('wiz_sort_alpha_'+letters[i]).setAttribute('style', '' );
  }
}


function highlightLetter( letter ) {
  $('wiz_sort_popular').setAttribute('style', '' );
  var letters = new Array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' );
  for( var i = 0; i < letters.length; i++ ) {
    if( letters[i] == letter ) {
      $('wiz_sort_alpha_'+letters[i]).setAttribute('style', 'font-weight:bold;text-decoration:underline;' );
    } else {
      $('wiz_sort_alpha_'+letters[i]).setAttribute('style', '' );
    }
  }
}
  
  
function wizardStep2( transport )
{ 
  $('dialogBox').addClassName('wide-lightbox-popup');
  var page_id = 0;
  if( transport ) {
    page_id = transport.request.parameters.id;
  }
  var url = 'include/ajaxscripts/popups/wizard-step-2.php';
  displayLoad( 'dialogBox' );
  new Ajax.Updater( 'dialogBox', url, {method:'post', parameters: {page: page_id}} );
}


function wizardBackTo2( page_id )
{
  wizardStep2( { request : {parameters : { id : page_id } } } );
}


function wizardStep3()
{
  $('dialogBox').addClassName('wide-lightbox-popup');
  var url = 'include/ajaxscripts/popups/wizard-step-3.php';
  displayLoad('dialogBox');
  new Ajax.Updater('dialogBox', url, {method:'post'});
}
  

function getPopularPages(first_page, page_count, category, div_id, director)
{
  highlightPopular();
  url = 'include/ajaxscripts/get-popular-pages.php';
  type = 'Popular';
  displayLoad( div_id );
  new Ajax.Updater( div_id, url, { method: 'post', 
                                parameters: {first_page: first_page, page_count: page_count, category: category, director: director, type:type }
                              });
}


function getAlphabeticalPages( first_page, page_count, category, div_id, alphabet_string, director )
{
  highlightLetter( alphabet_string );
  url = 'include/ajaxscripts/get-alphabetical-pages.php';
  type = 'Alphabetical';
  displayLoad( div_id );
  new Ajax.Updater( div_id, url, { method: 'post', 
                                parameters: 
                                  {   first_page: first_page, page_count: page_count, 
                                      category: category, director: director, str: alphabet_string, type:type }
                                } );
}


function getRelatedPages( first_page, page_count, category, div_id, page_ids, director )
{
  url = 'include/ajaxscripts/get-related-pages.php';
  type = 'Related';
  var params =  {  first_page: first_page, 
                  page_count: page_count, 
                  category: category, 
                  director: director, 
                  page_ids: 3, 
                  type:type
               };
  var options = { method: 'post', parameters: params, onSuccess: updateMoreResults }; 
  displayLoad( div_id );                                
  new Ajax.Updater( div_id, url, options );
}

function goHome() {
  window.location = 'home.php';
}
function requestFamilyLink(user_id) {
  var relative_id = $('edit-family-relative_id').value;
  actionBox('request-family-link?relative_id='+relative_id+'&user_id='+user_id, {}); 
}
function createFamilyLink(user_id, relative_id) {
  var url = 'include/ajaxscripts/create-family-link.php';
  var options = { parameters: {user_id:user_id, relative_id:relative_id},
    onSuccess: function(t) {
      if(t.responseText == "goody") {
        new Ajax.Updater('dialogBox', 'include/ajaxscripts/popups/message-box?message=The request has been sent.', {});
      } else {
        new Ajax.Updater('dialogBox', 'include/ajaxscripts/popups/message-box?message=Sorry, we were not able to send the request.&notice=error', {});
      }
    },
    onFailure: function(t) {
      new Ajax.Updater('dialogBox', 'include/ajaxscripts/popups/message-box?message=Sorry, we were not able to send the request.&notice=error', {});
    }
  };
  new Ajax.Request(url, options);
}

/*
function submitPageRegistrationPitch(form_id) {
  var url = 'include/ajaxscripts/main-registration-pitch.php';
  var options = { parameters: $(form_id).serialize(true),
                 onComplete: wizardStep2
              }
  new Ajax.Request( url, options );
}*/

function addManyPages(form_id, callback) {
  var url = 'include/ajaxscripts/add-many-pages-to-cookie.php';
  var options = { parameters: $(form_id).serialize(true),
                 onComplete: callback
              }
  new Ajax.Request( url, options );
}
// visibility_action should be either show or hide
// option_to_select should be 'All', 'None', or whatever
function updateNotifications( visibility_action, option_to_select) {
  var element = $('add_membership_notifications');
  // show/hide the element with all the subscription selections
  if(visibility_action == 'show') {
    element.show();
    //new Effect.BlindDown('add_membership_notifications',{duration:0.6});
  } else if(visibility_action == 'hide') {
    element.hide();
    //new Effect.BlindUp('add_membership_notifications',{duration:0.6});
  }
  
  // for firefox, you have to unselect all the options first, before you begin selecting, so don't merge these two for loops together
  option_elements = element.getElementsBySelector('option');
  for( var i=0; i < option_elements.length; i++ ) {
    var option = option_elements[i];
    option.removeAttribute('selected');
  }
  /// for each subscription, set selected on the correct option
  for( var i=0; i < option_elements.length; i++ ) {
    var option = option_elements[i];
    if( option.innerHTML == option_to_select) {
      option.setAttribute('selected','true');
    }
  }
  
  
  return false;
}
function forgetWizard() {
  setUserAttribute('wizard_completed', 1);
}
function setUserAttribute(attribute_name, attribute_value) {
  if(logged_in()) {
    url = 'include/ajaxscripts/set_user_attribute';
    new Ajax.Request(url, { parameters: {name: attribute_name, value: attribute_value}});
  }
}

function changeToTab(link_element, tab_name) {
  changeCurrentTabLink(link_element);
  changeCurrentTabContent(tab_name);
}

function changeCurrentTabContent(tab_name) {
  var tab_elements = document.getElementById('tabs').getElementsByTagName('div')[1].getElementsByTagName('div');
  for (var i = 0; i < tab_elements.length; i++) {
    if (tab_elements[i].className == 'content_tab') {
      tab_elements[i].style.display = 'none';
    }
  }
  document.getElementById(tab_name).style.display = 'block';
}

function changeCurrentTabLink(link_element) {
  var tab_elements = document.getElementById('tabs').getElementsByTagName('ul')[0].getElementsByTagName('li');
  for (var i = 0; i < tab_elements.length; i++) {
    tab_elements[i].getElementsByTagName('a')[0].className = '';
  }
  link_element.className = 'current';
}

function clickRegiWizAdd(){
  var elements = document.getElementsByClassName('page_list_row');
  for(var i=0; i<elements.length; i++) {
    var element = elements[i];
    // make sure the element has the 'hide' method (to keep IE from breaking)
    if( element.hide ) {
      element.hide();
      element.innerHTML = ''; // need to remove it, because it has non-unique ids in it
    }
  }
}

function saveListOrder(type)
{ 
  if(in_array( type, new Array('conditions','groups','symptoms','treatments', 'profiles'))) {
    var file_prefix = 'page';
  } else {
    var file_prefix = type;
  }
  new Ajax.Request("include/ajaxscripts/"+file_prefix+"-reorder.php", {
                        method: "post",
                        parameters: {list: Sortable.serialize(type+'_list_sortable')},
                        onSuccess: function (transport) { 
                          $(type+'_message_box').style.background = '#ddffdd';
                          $(type+'_message_box').style.border = '1px solid #6b6';
                          $(type+'_message_box').style.padding = '5px';
                          $(type+'_message_box').style.margin = '5px 0';
                          $(type+'_message_box').innerHTML = 'Your '+type+' have been reordered.';
                          $(type+'_message_box').show();
                          new Effect.Fade(type+'_message_box', {duration:4});
                          if(type == 'application') {
                            refreshApplicationList();
                          }
                        }
                      }); 
  resetArrows(type+'_list_sortable');
}
function saveApplicationListOrder() {
  saveListOrder('application');
}

// returns a function that takes no arguments, but knows the correct page type
// can't have arguments because it is used as 'onUpdate' in a sortable
function savePageTypeListOrder(page_type) {
  var page_type_function = function() { 
    saveListOrder(page_type); 
  };
  return page_type_function; 
}

function moveListItemUp(type, li_id )
{
  var li = $(li_id);
  var ul = $(li_id).parentNode;
  var prev_li = $(li_id).previousSibling;
  // only move the item up if it is not the first
  if( prev_li ){
    ul.insertBefore( li, prev_li ); 
    saveListOrder(type);
  }
}

function moveListItemDown(type, li_id )
{
  var li = $(li_id);
  var ul = $(li_id).parentNode;
  var next_li = $(li_id).nextSibling;
  // only move the item down if it is not last
  if( next_li ) {
    ul.insertBefore( next_li, li );
    saveListOrder(type);
  }
}



  // reset the up/down arrows, and the displayed order, when a row has been moved
function resetArrows(ul_id) { 
  var li_elements = $(ul_id).getElementsByClassName('sortable_list_li');
  for( var i = 0; i < li_elements.length; i++ ) {
    var spans = li_elements[i].getElementsByClassName('order_span');
    var number = spans[0];
    number.innerHTML = i+1;
    
    var arrow_up = li_elements[i].getElementsByClassName('arrow_up');
    arrow_up = arrow_up[0];
    if(i == 0) {
      arrow_up.hide();
    } else {
      arrow_up.show();
    }
   
    var arrow_down = li_elements[i].getElementsByClassName('arrow_down');
    arrow_down = arrow_down[0];
    if(i == li_elements.length-1) {
      arrow_down.hide();
    } else {
      arrow_down.show();
    }
  }
}


String.prototype.quote = function () {
  var c, i, l = this.length, o = '"';
  for (i = 0; i < l; i += 1) {
      c = this.charAt(i);
      if (c >= ' ') {
          if (c === '\\' || c === '"') {
              o += '\\';
          }
          o += c;
      } else {
          switch (c) {
          case '\b':
              o += '\\b';
              break;
          case '\f':
              o += '\\f';
              break;
          case '\n':
              o += '\\n';
              break;
          case '\r':
              o += '\\r';
              break;
          case '\t':
              o += '\\t';
              break;
          default:
              c = c.charCodeAt();
              o += '\\u00' + Math.floor(c / 16).toString(16) +
                  (c % 16).toString(16);
          }
      }
  }
  return o + '"';
};

function deletePost(post_id, forum_id) {
  var returnToForum = function(t) {
    window.location = 'home/#app=discussions/forum/'+forum_id;
  }
  deleteItem('Post', post_id, returnToForum);
}
function deleteThread(thread_id, forum_id) {
  var returnToForum = function(t) {
    window.location = 'home/#app=discussions/forum/'+forum_id;
  }
  deleteItem('Thread', thread_id, returnToForum);
}
function deleteItem(item_type, item_id, callback) {
  var url = 'include/ajaxscripts/delete-item';
  var options = {parameters: {item_type: item_type, item_id:item_id}, onComplete:callback};
  new Ajax.Request(url, options);
}

function submitComment(hash, item_type, item_id, hook) {
  var message_txt = $('new_comment_message-'+hash).value;
  var comments_div = $('comments-'+hash);
  var new_comment_id = 'new_comment-'+(new Date()).getTime();
  var new_comment = new Element('div', { id:new_comment_id } );
  comments_div.appendChild(new_comment);
  var options = { 
    parameters:{ item_type:item_type, item_id:item_id, message:message_txt }, 
    onSuccess: function(t){ 
      if (t.responseText == 'error') {
        $('comment-error-'+hash).show();
      } else {
        $('comment-error-'+hash).hide();
        $('comments-count-'+hash).innerHTML = $('comments-count-'+hash).innerHTML * 1 +  1;
        displayLoad(new_comment_id);
        new_comment.innerHTML = t.responseText;
        $('new_comment_message-'+hash).value = '';
        hook(item_type, item_id, message_txt);
      }},
    onFailure: function(t){ new_comment.innerHTML = '<div class="notice error">Failed to save comment</div>'; $('new_comment_message-'+hash).value = ''; hook()}
  };
  var url = 'include/ajaxscripts/new-comment';
  new Ajax.Request(url, options);
}

function submitTags(msg,form) {
  var form_data = $(form).serialize(true);
  var url = 'include/ajaxscripts/add-tags.php';
  var options = {parameters:form_data, onComplete: function(transport) {
    $(msg).show();
  }};
  new Ajax.Updater(msg, url, options);
}

function bookmarkCommentNotification(item_type, item_id, message_txt) {
  if(item_type == 'Article') {
    // TODO: do an app notification every time a comment is made on a bookmarked article
    //var url = 'include/ajaxscripts/bookmark-notifications';
    //var options = {}
    //new Ajax.Request(url, options);
  }
}

function deleteComment(comment_id, div_id) {
  var options = { 
    parameters: {comment_id:comment_id},
    onSuccess: function(t) { Effect.Fade(div_id); }
  }
  var url = 'include/ajaxscripts/delete-comment';
  new Ajax.Request(url, options);
}
/*********************************************/
/* @Directors */
/*********************************************/
// this director is used on any Add Page that is not in the registration wizard
var GlobalAddPageDirector =
{
  onConfirm : function( form, callback )
    {
      var form_data = $(form).serialize(true);
      $('dialogBox').removeClassName('thin-lightbox-popup');
      $('dialogBox').addClassName('wide-lightbox-popup');
      displayLoad('dialogBox');
      var show_page_confirmed = function() {
        actionBox('registration-wizard/similar', serialize({item_type:'Page',item_id:form_data['page_id']}));
      }
      if(callback) {
        addMembership( form_data, callback );
      } else {
        if(logged_in()) 
          addMembership(form_data, show_page_confirmed );
        else
          addMembership(form_data, function(t){ hideDialog();});
      }
    },
  onCancel : function() { hideDialog(); }
};



function SuggestionAddPageDirector(hash, id)
{
  return {
          onConfirm : function(form)
          {  
            var form_data = $(form).serialize(true);
            displayLoad('dialogBox', 'Adding to your Firefly Jar...');
            var remove_li= function() {
              hideDialog();
              new Effect.Highlight('listy_brief_'+hash+'_'+id, {startcolor:'#DBF0E6'});
              new Effect.Fade('listy_brief_'+hash+'_'+id);
            }
            addMembership(form_data, remove_li );
          },
          onCancel : function(){ 
            hideDialog();
          }
  }
}


/* This director is called in Wizard Step 2 */
function ItemDirector( page_id, content_div )
{
  return {
          onConfirm : function( form )
          {  
              addMembership( $(form).serialize(true), function(){} );
              // note, we say the page is added before it's actually been added (but assuming it will be)
              //$(content_div).innerHTML = '';
              $(content_div).innerHTML = "<span class='page_added'>Page Added</span>";
              new Effect.Highlight(content_div, { duration:3.0 });
          },
          onCancel : function(){ 
              if($(content_div)) {
                $(content_div).innerHTML = '';
              }
            }
  }
}


function RegWizStep1Director( page_id ) {
  return {
          onConfirm : function( form )
          { 
            addMembership( $(form).serialize(true), wizardStep2 ); 
            displayLoad('dialogBox'); 
          },
          onCancel : function()
          {
            $( 'page_list_row_' + page_id ).innerHTML = "";
          }
        }
}



function search_page_redirect(misspelling, chosen) {
  return function(t) { window.location = 'search.php?q='+chosen; };
}  

// this function returns a function that returns another function
function build_misspelling_callback(input_id) {
  return function(misspelling, chosen) {
    return function(t) { 
      $(input_id).value = chosen;
      new Effect.Highlight(input_id);
      fakeKeyPress(input_id);
    }
  }
}


function rate_misspelling(misspelling, chosen, callback) {
  var url = 'include/ajaxscripts/rate-misspelling';
  var go_to = function(t) { window.location = 'search.php?q='+chosen; };
  var options = { parameters: { misspelling:misspelling, chosen:chosen }};
  if(callback) { 
    options['onComplete'] = callback(misspelling, chosen);
  }
  new Ajax.Request(url, options);
}


function removePageCookie() {
  var url = 'include/ajaxscripts/remove-page-cookie';
  var refresh = createRefreshLeftNav();
  var options = { parameters: {}, onComplete:refresh };
  new Ajax.Request(url, options);
}
var omNomNom = removePageCookie; 

function removePageFromJar(id, page_name, callback) {
  if(confirm('Are you sure you want to remove '+page_name+'?')) {
    $('remove_page_link_'+id).innerHTML = "<img src='img/indicator.gif' /> Removing...";
    new Ajax.Request('include/ajaxscripts/remove-page', {
         method: 'post',
         parameters: {page_id:id},
         onComplete: createRefreshLeftNav(null, null, callback)                        
         
    });
  }
  
  return false;
}
function removePage(id, page_name, connection_hash, is_group) {
  if(confirm('Are you sure you want to remove '+page_name+'?')) {
    new Ajax.Request('include/ajaxscripts/remove-page', {
         method: 'post',
         parameters: {page_id:id},
         onComplete: function(transport) {
                        var action_link = "";
                        if (is_group) {
                          action_link = "+Join Group";
                        } else {
                          action_link = "+Add to Jar";
                        }
                        $('rm_'+id).innerHTML = 
"<li><a class=\"extremely-clickable\" href=\"#\" onClick=\"actionBox(\'add-membership\',serialize({page:"+id+"}));return false;\">"+action_link+"</a></li>";
                        createRefreshLeftNav()(transport);                        
         }
    });
  }
  
  return false;
}

/*** thinking about moving the ConnectWithPeopleLikeMe js to another file? Think again. Because this
     code is used in the registration wizard, and also in an application, and ALSO on the category page,
     there's no telling when you'll need these functions. Better just keep them in common. K?   ***/
/*     
function getPageIdsAsString(hash) {
  var inputs = $$('li.dtag_span input');
  var ids = '';
  for(var i = 0; i < inputs.length; i++) {
    ids = ids+ inputs[i].value + ',';
  }
  ids = ids + '0'; // append zero so you don't have the trailing comma
  return ids;
}


function checkBackspace(e, value, alias, hash)
{
  var keynum;
  var keychar;
  var numcheck;
  
  if(window.event) // IE
    {
    keynum = e.keyCode;
    }
  else if(e.which) // Netscape/Firefox/Opera
    {
    keynum = e.which;
    }
  if(keynum == 8 && value == '') {
    deleteLatestDtag(alias, hash);
  }
  //return !numcheck.test(keychar);
}
function deleteLatestDtag(alias, hash) {
  var dtags = $$('#'+alias+'_dtags_'+hash+' li.dtag_span');
  var last_dtag = dtags[dtags.length-1];
  
  last_dtag.remove();
}


function insert_dtag_into(insert_into_id, dtag_display, dtag_input_value, dtag_input_name, input_li_id) {
  var element_id = insert_into_id+'_'+randomString(20);
  
  //var children = element_id.childElements();
  var inner =   '  <span class="dtag_display" >'+dtag_display+'</span>'+
                '  <input type="hidden" value="'+dtag_input_value+'" name="'+dtag_input_name+'[]" />'+
                '  <a class="dtag_close" onClick="$(\''+element_id+'\').remove();return false;">X</a>';
  var dtag= new Element('li', {'class':'dtag_span', 'id':element_id}).update(inner);
  Element.insert($(input_li_id), {'before':dtag});
  return false;
}

*/
function randomString(len) {
  var str = "";
  for(var i = 0; i < len; i++ ) {
    str = str + String.fromCharCode(65 + Math.round(Math.random() * 25));
  }
  return str;
}

function serialize( mixed_value ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Arpad Ray (mailto:arpad@php.net)
    // +   improved by: Dino
    // %          note: We feel the main purpose of this function should be to ease the transport of data between php & js
    // %          note: Aiming for PHP-compatibility, we have to translate objects to arrays
    // *     example 1: serialize(['Kevin', 'van', 'Zonneveld']);
    // *     returns 1: 'a:3:{i:0;s:5:"Kevin";i:1;s:3:"van";i:2;s:9:"Zonneveld";}'
    // *     example 2: serialize({firstName: 'Kevin', midName: 'van', surName: 'Zonneveld'});
    // *     returns 2: 'a:3:{s:9:"firstName";s:5:"Kevin";s:7:"midName";s:3:"van";s:7:"surName";s:9:"Zonneveld";}'
 
    var _getType = function( inp ) {
        var type = typeof inp, match;
        if (type == 'object' && !inp) {
            return 'null';
        }
        if (type == "object") {
            if (!inp.constructor) {
                return 'object';
            }
            var cons = inp.constructor.toString();
            if (match = cons.match(/(\w+)\(/)) {
                cons = match[1].toLowerCase();
            }
            var types = ["boolean", "number", "string", "array"];
            for (key in types) {
                if (cons == types[key]) {
                    type = types[key];
                    break;
                }
            }
        }
        return type;
    };
    var type = _getType(mixed_value);
    var val, ktype = '';
    
    switch (type) {
        case "function": 
            val = ""; 
            break;
        case "undefined":
            val = "N";
            break;
        case "boolean":
            val = "b:" + (mixed_value ? "1" : "0");
            break;
        case "number":
            val = (Math.round(mixed_value) == mixed_value ? "i" : "d") + ":" + mixed_value;
            break;
        case "string":
            val = "s:" + mixed_value.length + ":\"" + mixed_value + "\"";
            break;
        case "array":
        case "object":
            val = "a";
            /*
            if (type == "object") {
                var objname = mixed_value.constructor.toString().match(/(\w+)\(\)/);
                if (objname == undefined) {
                    return;
                }
                objname[1] = serialize(objname[1]);
                val = "O" + objname[1].substring(1, objname[1].length - 1);
            }
            */
            var count = 0;
            var vals = "";
            var okey;
            for (key in mixed_value) {
                ktype = _getType(mixed_value[key]);
                if (ktype == "function" && ktype == "object") { 
                    continue; 
                }
                
                okey = (key.match(/^[0-9]+$/) ? parseInt(key) : key);
                vals += serialize(okey) +
                        serialize(mixed_value[key]);
                count++;
            }
            val += ":" + count + ":{" + vals + "}";
            break;
    }
    if (type != "object" && type != "array") val += ";";
    return val;
}

function showCentralNav(url) {
	url = url ? url : 'apps/central_nav/fragments/display';
  var myAjax = new Ajax.Updater('head-ad-wrap', url, {
		onComplete: function (transport) {
			$('header-ad').show();
		}
	});
}

function skipCentralNav(url) {
	url = url ? url : 'apps/central_nav/fragments/skip';
	if ($('central_notification_id')) {
		url = url + '/' + $('central_notification_id').innerHTML;
	}
  var myAjax = new Ajax.Request(url, {
		onComplete: function (transport) {
			showCentralNav();
		}
	});
}

function submitPaginator(form_id) {
	var form = $(form_id).serialize(true);
	if(form['app_name']) {
		var app_name = form['app_name'];
		var page     = form['page'];
		delete form['app_name'];
		delete form['page'];
		submitForm(app_name, page, form, 1, 1);
	} else if(form['search_query']) {
		getSearchResults(form['tab'], form['start'], form['subtab']);
	} else if(form['regwiz_page_name']) {
    var options = { page_id:   form['page_id'],
							      type:      form['type'],
							      start:     form['start'],
							      transform: form['transform'],
							      is_quick:  form['is_quick'] };
    actionBox('registration-wizard/' + form['regwiz_page_name'], serialize(options));
  }
	return false;
}

function loadSuggestions(hash, page_ids, var_name) {
  new Ajax.Updater('suggestions_'+hash, 'include/ajaxscripts/load-suggestions?page_ids='+page_ids+'&hash='+hash+'&var_name='+var_name);
}

function genericRegister() {
  actionBox('register', serialize({source:"generic"}));
  return false;
}

function submitLinkAndDisplay(hash) {
  $('loading_'+hash).show();
  $('add_link_form_'+hash).hide();
  var data = $('add_link_form_'+hash).serialize(true);
  var insertIntoList = function(t) {
    var html = t.responseText;
    var new_link = new Element('span', {'class':"new_link"}).update(html);
    Element.insert($('add_link_form_'+hash), {'after':new_link});
    $('loading_'+hash).hide();
    
    var inputs = $$('#add_link_form_'+hash+' .resetable'); console.log(hash);
    for(var i = 0; i < inputs.length; i++) { inputs[i].value=""; }
  }
  new Ajax.Request('include/ajaxscripts/link_to_html', {parameters:data, onComplete:insertIntoList});
}

function submit_rating(hash) {
  data = $('rating_form_'+hash).serialize(true);
  $('options_'+hash).innerHTML = "<img src='img/indicator.gif' /> Saving...";
  new Ajax.Updater('options_'+hash, 'include/ajaxscripts/submit_rating', {parameters: data});

}
function submitJournalPrivacy(hash) {
  var data = $('journal-privacy_'+hash).serialize(true);
  $('indicator_'+hash).show();
  var callback = function(t) {
    $('indicator_'+hash).hide();
    $('privacy_display_'+hash).innerHTML = '<span style="font-weight:bold;">'+t.responseText+'</span>';
  }
  new Ajax.Request('include/ajaxscripts/set-journal-privacy', {parameters:data, onComplete:callback });

}

// assumes height is in pixels
function changeHeight(element, delta_height) {
    element.style.height = (element.getHeight()  + delta_height) + "px";
}