// fix for https://prototype.lighthouseapp.com/projects/8886/tickets/365-elementgetstyle-problem-with-ie-6-7
Element.Methods.originalGetStyle = Element.Methods.getStyle;

Element.addMethods({
  getStyle: function(element, style) {
    try {
      return Element.Methods.originalGetStyle(element, style);
    } catch(e) {
      return 'static';
    }
  }
});

// Place your application-specific JavaScript functions and classes here
// This file is automatically included by javascript_include_tag :defaults

var zd = { // used by new modular JS, but needs to be defined before data is pushed into it within the HTML body
  jsInitializers: [],
  jsData: {}
};

var standard_blind_options = {duration: "0.25"};

var items = {}; // For rule data

// Ticket functions - create/edit

//function zd_highlight(p) {
//  if (p) { p.className = (p.value==0 || p.value=='') ? "highlight" : "" }
//}

function render_per_type() {
  if ($("ticket_ticket_type_id")) {
    if ($("ticket_linked_id")) { set_visibility("ticket_link", ($F("ticket_ticket_type_id")=="2")) }
    if ($("ticket_date")) { set_visibility("ticket_date", ($F("ticket_ticket_type_id")=="4")) }
    //if ($("ticket_due_date_1i")) { set_visibility("ticket_date", ($F("ticket_ticket_type_id")=="4")) }
  }
}

// Assignee select - ticket create/edit
function assignee_select(group_id, user_id) {
  group_id = Number(group_id);

  var group;
  var previous;
  var select = $('ticket_assignee_id');
  select.update(new Element('option')); // clear current items in the list, but keep a blank option

  if (group_id >= 0 && typeof(group = groups.find(function(group){ return(group.id === group_id); })) !== 'undefined') {
    // Create an option for every agent of the selected group
    agents.each(function (agent, index) { // just get the agents in this group first.
      if (typeof(group.users.find(function (user) {return(user === agent.id);})) !== 'undefined' ) { // only agents within this group
        var option = new Element('option', {value: agent.id}).update(agent.name);
        if (Number(user_id) === agent.id) {
          option.writeAttribute({selected: 'selected'}); // select the current user if he's one of the potential assignees
        }
        select.insert(option);
      }
    });
    select.enable();
  }
  else {
    select.options.selectedIndex = 0;
    select.disable();
  }

  select.setStyle('width', 'auto'); // hack for IE bug: if #ticket_assignee_id is populated with a name that makes it wider, it stretchs through/behind any selects to its right. see PT#3273178
}

function update_properties(assignee_id) {
  // Highlight missing properties on ticket form
  if ($("ticket_group_id") && $("ticket_group_id").type=="select-one") {
    if ($F("ticket_group_id") == '') {
      }
    else {
      if ($F("ticket_assignee_id")=='') { assignee_select($F("ticket_group_id"), assignee_id) } }
  }
  render_per_type();
  return true;
}

// Highlights agents in ticket cc list
function highlightAgents(){
  // Parse CC-List
  var ccusers = $$('#facebook-list li.choice');
  for(index = 0; index < ccusers.length; index++){
    var choiceId = ccusers[index].readAttribute('choice_id');

    if(typeof(agents.find(function(agent) {return (agent.id === Number(choiceId)); })) !== 'undefined') {
      $$('#facebook-list li.choice')[index].addClassName('agent');
    }
  }

  // Observe changes
  var first_ul = $$('#facebook-list ul.multi_value_field')[0];
  if (first_ul){
    first_ul.observe('DOMNodeInserted', highlightAgents);
  }
};

// Generic functions

function set_visibility(id, want_visible) {
  if (want_visible != $(id).visible()) { (want_visible) ? $(id).show() : $(id).hide() }
}

function toggle_visibility(/* id1, id2, ...*/) {
  for (var i = 0 ; i < arguments.length ; ++i) {
    var id = arguments[i];
    ($(id).visible()) ? $(id).hide() : $(id).show()
  }
}

function toggle_comment(){
  toggle_visibility('comment_full', 'comment_partial');
  toggle_visibility('comment_up', 'comment_down');
  return false;
}

// For user admin page
function toggleFilter(id) {
  $('options').hide();
  toggle_visibility(id);
  return false;
}

function submitUpload() {
  var filename = $('attachment_content').value.strip();
  if(filename != null && filename.length > 0) {
    $('uploadform').submit();
    $('uploadinput').style.display = "none";
    $('uploadbar').style.display = "block";
  }
}

function notifyOnError(name) {
  alert("Failed to upload file '"+name+"', verify the path");
  resetView();
}

function addAttachment(name, size, id) {
  new Insertion.Bottom("attachmentlist", "<div class='attachment' id='attachment_"+id+"'>"+name+" <span class='size'>"+size+"</span> <a href='#' onclick='deleteAttachment("+id+");return false'>x</a>");
  resetView();
}

function deleteAttachment(id) {
  new Ajax.Updater({success:'attachmentDeleted('+id+')'}, '/attachment/delete/'+id, { asynchronous:true, evalScripts:true});
}

function attachmentDeleted(id) {
  Element.remove('attachment_'+id);
}

var attachmentLists = new Array();

function registerAttachmentList(listId, size) {
  attachmentLists[listId] = size;
}

function deleteFromAttachmentList(listId, itemId) {
  Element.remove($(itemId));
  attachmentLists[listId] = attachmentLists[listId]-1;
  if(attachmentLists[listId] <= 0) {
     Element.remove($(listId));
     delete attachmentLists[listId];
  }
}

function resetView() {
  $('attachment_content').value = '';
  $('uploadbar').style.display = "none";
  $('uploadinput').style.display = "block";
}

function showFlash(flash) {
  $('flash_messages').innerHTML = flash;
  new Effect.Highlight('flash_messages', { duration: 2 });
}

// **** Upload photo stuff
function pictureDeleted(key) {
  $('cancel-block-'+key).hide();
  if (key == 'header_logo') { $('website_url').hide(); }
  selectPicture(key);
}

function selectPicture(key) {
  $('image-block-'+key).hide();
  $('upload-block-'+key).show();
  $('ignore-upload-'+key).value = 0;
}

function resetPicture(key) {
  $('upload-block-'+key).hide();
  $('image-block-'+key).show();
  $('ignore-upload-'+key).value = 1;
}


function checkTicketDelete() {
  if ($F('submit_type') == 'delete')
    alert('Warning - selecting this option will delete the ticket when you click submit. Deleted tickets cannot be recovered.');
}

function check_ticket(ticket_id) {

  if (!$('comment_type') && $F('ticket_requester_name') == '') {
    if (!confirm('You haven\'t entered a requester for the ticket. Submitting this form will register you as the requester.'))
      return false;
  }

  // show alert if we're solving with a public comment, a problem that has associated tickets
  //if ($('associated_incidents_warning') && $F('ticket_status_id') == '3' && isAddingPublicComment() && isUpdatingTicket()) {
  //  if (!confirm($('associated_incidents_warning').innerHTML))
  //    return false;
  //}

  $('submit-button').value = 'Submitting...';
  $('submit-button').disabled = true;

  if (typeof(collaboratorList) != 'undefined')
    collaboratorList.update();

  // Remove requester/cc if it is not visible - so we don't need to update it in the ticket model
  if ($F('submit_type') != 'merge' && $('edit_requester').style.display == 'none')
    $('edit_requester').remove()

  return true
}

function isUpdatingTicket() {
  return $F('submit_type') == '' || $F('submit_type') == 'macro' || $F('submit_type') == 'entry'
}

function isAddingPublicComment() {
  return !$F('comment_value').blank() && $('comment_is_public').checked;
}

function copySubmitType() {
  $('ticket-chat').submit_type.value = $('submit_form').submit_type.value;
}

function submitTicketForm(ticket_id) {
  if (check_ticket()) {
    copySubmitType();
    if ($F('submit_type') == 'merge') {
      showMergeWizard(ticket_id);
    } else {
      if(typeof(ticketTagField) != 'undefined') {
        ticketTagField.beforeFormSubmit();
      }
      $('ticket-chat').submit();
    }
  }
}

function submitBulkUpdateForm() {
  if (fetch_tickets_to_bulk_update()) {
    if ($F('submit_type') == 'merge') {
      showMergeWizard($('tickets_to_bulk_update').value);
    } else {
      if ($('ticket_ticket_type_id') && $('ticket_ticket_type_id').value != "4") {
        $('ticket_date').remove(); // Remove due date if the ticket is not a task
      }
      $('ticket-chat').submit();
    }
  }
}

function showMergeWizard(ticket_id) {
  var unchecked = '';
  if ($$('input.tickets_to_bulk_update')) {
    unchecked = $$('input.tickets_to_bulk_update').collect(function(s) { if (!s.checked) return s.value;}).compact().join(',');
  }
  Lightview.show({
    href: '/merge/new',
    rel: 'ajax',
    options: {
      topclose: true,
      autosize: true,
      backgroundColor: '#999',
      ajax: {
        parameters: { source_ids: ticket_id, unchecked: unchecked },
        method: 'get'
      }
    }
  });
}

function submitSelectedMerge() {
  var nice_id = $('target_id').value.strip();
  if (!nice_id) {
    alert('Please enter a ticket ID');
    return;
  }

  Lightview.show({
    href: '/merge',
    rel: 'ajax',
    options: {
      topclose: true,
      autosize: true,
      backgroundColor: '#999',
      ajax: {
        parameters: Form.serialize('merge_form'), // the parameters from the form
        method: 'get'
      }
    }
  });

}

function submitNewUserFromTicket(addedAs) {
  new Ajax.Request('/people/users/find_or_create.json', {
    method: 'post',
    parameters: Form.serialize('new_user_form'),
    onSuccess : function(response) {
      addUserToTicket(response.responseJSON, addedAs);
    },
    onFailure : function(response) {
      $('user_email').focus();
      new Effect.Highlight('user_email', { duration: 3 });
    }
  });
}

function addUserToTicket(data, addedAs) {
  value = data.email_address_with_name_without_quotes;
  if (addedAs == 'requester') {
    $('ticket_requester_name').value = value;
  } else {
    collaboratorsInput.addEntry(data.id, value);
  }
  Lightview.hide();
}

function observeMergeWizardEvents() {
  document.observe('lightview:hidden', function(event) {
    $('submit-button').value = 'Submit';
    $('submit-button').disabled = false;
  });

  document.observe('lightview:opened', function(event) {
    // Check if we're in step2 first and if the user wrote something as a comment
    if ($('target_comment') && $('comment_value').value.length > 0) {
      // Add current text in comment area as last comment in target ticket
      $('target_comment').value = $('target_comment').value + '\n\nComment during merge: ' + $('comment_value').value;
      $('source_comment').value = $('source_comment').value + '\n\nComment during merge: ' + $('comment_value').value;
    }
  });
}

function copySolvedState() {
  if ( $('submit_form').solved_true ) {
    $('ticketform').ticket_force_status_change.value = $('submit_form').solved_true.checked;
  }
}

function submitRequestForm() {
  $('ticketform').submit();
}

function toggleAttachForm() {
  $('uploads_link').toggleClassName('unfolded');
  $('uploads_field').toggleClassName('unfolded');
}

function submitAttachForm(uploading_msg) {
  if ($('uploads_attribute')) {
    $('token').value = $('uploads_attribute').value;
  }
  $('submit-button').value = uploading_msg;
  $('submit-button').disabled = true;
  document.attach_form.submit();
  $('uploads_form').hide();
  $('uploading_message').removeClassName('display_none');
  document.attach_form.reset();
}

// TODO use prototype instead
function set_selected_for_select(select, selected_value) {
  if (select) {
    for (var i=0; i<select.options.length; i++) {
      select.options[i].selected = (select.options[i].value == selected_value);
    }
  }
}

// Autotagging for ticket
function autotag_ticket(element) {
  if(!$F(element).blank() && ticketTagField && ticketTagField.selectedEntries().length == 0) {
    new Ajax.Request('/tags/autotag', {
      parameters: { text: $F(element), target: 'ticketTagField' }
    });
  }
}

// ***** Prototip tips

function comment_tip(element, title, body) {
  return new Tip(element, ' ' + body, {
    title: title,
    style: 'zd_comment',
    delay: 0,
    border: 4,
    radius: 4,
    width: 600,
    viewport: true,
    hook: { tip: 'topLeft', mouse: true },
    offset: { x: 12, y: 8 }
  });
}

// *****

function stv(value, title, tagger_id, evt, this_elm) {
  if ($('ticket_fields_' + tagger_id)) {
    $('ticket_fields_' + tagger_id).value = value;
    $('title-tagger-' + tagger_id).innerHTML = title.split("").reverse().join("").truncate(26).split("").reverse().join("");
    var e=(evt)?evt:window.event;
    Event.stop(e);
    var li = e.findElement();
    selection_feedback(li);

    return(false);
  }
}

// ***** Macro stuff

function apply_macro(case_id, evt) {
  if (case_id != '') {
    if (typeof(ticket_id) == 'undefined') { 
      this_id = '0';
    } else {
      this_id = ticket_id;
    }

    new Ajax.Updater('case', '/rules/apply_macro/' + case_id + '?ticket_id=' + this_id, { asynchronous: true, evalScripts: true, insertion: Insertion.After, 
        onComplete: function() { $('comment_value').focus(); }, parameters: Form.serialize('ticket-chat') });
    $('case').hide();
    var e = (evt) ? evt: window.event;
    Event.stop(e);
    var li = e.findElement();
    selection_feedback(li);
    return (false);
  }
}

var hide_macro_li = function(li) {
  // using element storage to retrieve the currently open li and close it
  var current_selection = li.up().retrieve('selection');
  if (current_selection) {
    category_set(current_selection, 'none', 0, 'static');
  }
};

// ***** Topic stuff...

var TopicForm = {
  editNewTitle: function(txtField) {
    $('new_topic').innerHTML = (txtField.value.length > 5) ? txtField.value : 'New Topic';
  }
}

var LoginForm = {
  checkLogin: function(txt) {
    if(txt.value.match(/^https?:\/\//)) {
      $('password_fields').hide();
    } else {
      $('password_fields').show();
    }
  }
}

function showOrHideBulkForm() {
  fetch_tickets_to_bulk_update();
  if ($F('tickets_to_bulk_update').blank()) {
    $('bulk-update').hide();
  }
  else {
    $('bulk-update').show();
  }
}

function fetch_tickets_to_bulk_update() {
  $('tickets_to_bulk_update').value = $$('input.tickets_to_bulk_update').collect(function(s) { if (s.checked) return s.value;}).compact().join(',')
  return true;
}

function select_all_tickets_for_bulk_update(elm) {
  state = elm.checked
  if ($('bulk-update')) {
    state ? $('bulk-update').show() : $('bulk-update').hide()
    $$('input.tickets_to_bulk_update').each(function(s) {s.checked = state})
  }
}

// Color picking and calculations for account
var rgb_css_to_hex = function(str) { // e.g. rgb(0, 122, 255)
  var color_components = str.match(/\d+/g);
  var hex_color = '#';
  str.match(/\d+/g).each(function(val){
    hex_color += Number(val).toColorPart();
  });
  return(hex_color);
}

function hsv2hex(hsv_new) {
  rgb = YAHOO.util.Color.hsv2rgb(hsv_new[0], hsv_new[1], hsv_new[2])
  return YAHOO.util.Color.rgb2hex(rgb[0], rgb[1], rgb[2])
}

function calculateColors(){
  var color;
  if (fncIsValidColor(color = $F('branding_header_color')) &&
  fncIsValidColor($F('branding_page_background_color')) &&
  fncIsValidColor($F('branding_sidebox_color'))){
    rgb = YAHOO.util.Color.hex2rgb(color)
    if (!YAHOO.util.Color.isValidRGB(rgb)) return;
    hsv = YAHOO.util.Color.rgb2hsv(rgb[0], rgb[1], rgb[2])
    hsv_new = hsv[0] * 1.03
    if (hsv_new > 1.0) hsv_new = 1.0
    $('branding_tab_background_color').value = hsv2hex([hsv_new, hsv[1] * 0.87, hsv[2] * 0.83])
    hsv_new = hsv[2] * 1.02
    if (hsv_new > 1.0) hsv_new = 1.0
    $('branding_tab_hover_color').value = hsv2hex([hsv[0], hsv[1] * 0.62, hsv_new])
    if ($('branding_tab_hover_color').value == 'FFFFFF')
      $('branding_tab_hover_color').value = 'E8E8E8'
    $('branding_text_color').value = (hsv[2] > 0.85) ? "2A2A2A" : "FFFFFF";
    return true;}
  else {
    alert('You have not entered a valid hex color');
    return false;
  }
}

function fncIsValidColor(hexcolor) {
  var strPattern = /^#?[0-9a-f]{3,6}$/i;
  return strPattern.test(hexcolor);
}

// ********* Sorting
Ordering = {
  SetOrder: function(table){
    Element.hide(table);
    Element.show(table + '_sort');
  },

  cancelOrdering: function(listOfItems) {
    var sortableList = $j(listOfItems + "_sort");
    $j(listOfItems).show();

    sortableList.hide();
    var sortByOriginalPosition = function(a, b) {
      var attrName = "data-zendesk-original-position";
      return ($j(a).attr(attrName) < $j(b).attr(attrName)) ? -1 : ($j(a).attr(attrName) > $j(b).attr(attrName)) ? 1 : 0;
    }

    var sortedRules = $j("ul li.item.sortable", sortableList).sort(function(a, b) {
      return sortByOriginalPosition(a, b);
    });
    $j("ul li.item.sortable", sortableList).remove();
    $j("ul", sortableList).prepend(sortedRules);
  }
};


// Cookie stuff

var Cookie = {
  set: function(name, value, daysToExpire) {
    var expire = '';
    if (daysToExpire != undefined) {
      var d = new Date();
      d.setTime(d.getTime() + (86400000 * parseFloat(daysToExpire)));
      expire = '; expires=' + d.toGMTString();
    }
    return (document.cookie = escape(name) + '=' + escape(value || '') + expire + '; path=/');
  },
  get: function(name) {
    var cookie = document.cookie.match(new RegExp('(^|;)\\s*' + escape(name) + '=([^;\\s]*)'));
    return (cookie ? unescape(cookie[2]) : null);
  },
  erase: function(name) {
    var cookie = Cookie.get(name) || true;
    Cookie.set(name, '', -1);
    return cookie;
  },
  accept: function() {
    if (typeof navigator.cookieEnabled == 'boolean') {
      return navigator.cookieEnabled;
    }
    Cookie.set('_test', '1');
    return (Cookie.erase('_test') === '1');
  }
};

/* Textarea auto-resize. http://www.felgall.com/jstip45.htm */
function textarea_resize() {
  t = this;
  a = t.value.split('\n');
  b=1;
  for (x=0;x < a.length; x++) {
    if (a[x].length >= t.cols) b+= Math.floor(a[x].length/t.cols);
  }
  b += a.length;
  if (b > t.rows) t.rows = b;
}

//Javacript difference in time in words - http://nullstyle.com/2007/06/02/caching-time_ago_in_words/
function time_ago_in_words(from) {
  return distance_of_time_in_words(new Date(), new Date(from))
}

function i18n_time_ago_in_words(from) {
  return i18n_distance_of_time_in_words(new Date(), new Date(from))
}

function distance_of_time_in_words(to, from) {
  seconds_ago = ((to  - from) / 1000);
  minutes_ago = Math.floor(seconds_ago / 60)

  if(minutes_ago <= 0) { return "less than a minute";}
  if(minutes_ago == 1) { return "a minute";}
  if(minutes_ago < 45) { return minutes_ago + " minutes";}
  if(minutes_ago < 90) { return "1 hour";}
  hours_ago  = Math.round(minutes_ago / 60);
  if(minutes_ago < 1439) { return hours_ago + " hours";}
  if(minutes_ago < 2879) { return "1 day";}
  days_ago  = Math.round(minutes_ago / 1440);
  if(minutes_ago < 43199) { return days_ago + " days";}
  if(minutes_ago < 86399) { return "1 month";}
  months_ago  = Math.round(minutes_ago / 43200);
  if(minutes_ago < 525960) { return months_ago + " months";}
  if(minutes_ago < 1051920) { return "1 year";}
  years_ago  = Math.round(minutes_ago / 525960);
  return "over " + years_ago + " years"
}

/*
  Object factory. Used to allow multiple occurences of the same object type on the same page
  Use like so:

  ObjectFactory.create(TextWidget, {
    id: <%= @widget.id %>, params: <%= @widget.params.to_json %>
  });

  This instantiates and returns a new instance of the class specified. The instance gets initialized
  with an args parameter, containing the property list (eg. { id: 4, params: 'horse' }). The id must be
  set as it is used to lookup the instance later. So, to get the instance reference:

  ObjectFactory.get(<%= @widget.id%>).dance_the_funky_chicken_dance();
*/
var ObjectFactory       = Class.create({});
ObjectFactory.instances = new Hash();

ObjectFactory.create    = function(type, args) {
  instance = new type(args);
  ObjectFactory.instances.set(args.id, instance);
  return instance;
};

ObjectFactory.get = function(id) {
  return ObjectFactory.instances.get(id);
};

ObjectFactory.remove = function(id) {
  return ObjectFactory.instances.unset(id);
};

var usableChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiklmnopqrstuvwxyz";

function randomString() {
  var result = '';

  for (var i=0; i< 48; i++) {
    var index = Math.floor(Math.random() * usableChars.length);
    result += usableChars.substring(index, index+1);
  }

  return result;
}

document.getUrlParameter = function(name) {
  name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
  var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
  var results = regex.exec(window.location.href);
  return results ? unescape(results[1]) : null;
}


// Will format strings in human readable format... addCommas(1234567890) -> 1,234,567,890
function addCommas(nStr)
{
  nStr += '';
  var rgx = /(\d+)(\d{3})/;
  while (rgx.test(nStr)) {
    nStr = nStr.replace(rgx, '$1' + ',' + '$2');
  }
  return nStr;
}

function showSortingForForumType(type_id) {
  set_visibility("div_ordering", (type_id == 1 ? true : false))
}

var AccountAlert = {
  hide: function(id, key) {
    var notice = $j('#account_alert_' + id);
    $j.cookie(key, '1', 14);
    notice.hide();
  },

  show: function(id, key) {
    if (!$j.cookie(key)) {
      var notice = $j('#account_alert_' + id);
      notice.show();
    }
  }
}

$(document).observe('dom:loaded',  function(){
  //if ($('views-drop') && ($$('ul#views-drop>li').length == 0))
  //  $('views-drop').innerHTML = '<li class="drop-error">There are no tickets in your views currently</li>';

  // Mouse over for nested category menues
  var ul = $$('div.content ul.drop-list').each(function(ul){
    document.observe('click', function(event){ // close the menu if the user clicks outside of it
      if (!event.findElement().descendantOf(ul)){
        ul.select('li').each(function(li){
          category_set(li, 'none', 0, 'static');
        });
      }
    });
    var applicator = ul.firstDescendant('li');

    applicator.observe('click', function(event){
      category_set(applicator, 'block', 5, 'relative');
    });

    ul.select('ul.first-drop li').each(function(li){
      li.observe('mouseover', function(event){ // adding mouseover handler
        hide_macro_li(li);
        li.up().store('selection', li); // store the currently selected li
        category_set(li, 'block', 5, 'relative'); // open this sub-menu
      });
    });
  });

  if (!window.XMLHttpRequest) startList(); // Only for IE6
});

function createRef(instance,method) {
  return function(){  method.apply(instance,arguments); };
}

var upsell = function(calling_page) {
  $$(".upsell-observe").each(function(n){
    n.observe('click', function(element){
      switch(calling_page){
        case "rules":
          $('rule_owner_type_account').focus();
          $('rule_owner_type_account').click();
          $('upsell-message').removeClassName('hide');
          return false;
        break;
        case "reports":
          $('exports').remove();
          $('upsell-message').removeClassName('hide');
          return false;
        break;
      }
    });
  });
}

var additional_language_check = function(upselling){
  $$('a.additional_languages')[0].observe("click", function(element){
    if(!upselling){
      $$(".translation_boxes")[0].removeClassName('hide');}
    else{
      $('upsell-message').removeClassName('hide');
    }
  });
}

function category_set(element, visibility, z_index, position) {
  if (elm = element.down('ul')) {
//    var elm_a = elm
    elm.style.display = visibility;
/*    if (elm = element.up('div.select')) {
      // Agent form
      if (elm_z = elm.down('label')) {
        elm_z.style.zIndex = z_index;
        elm_z.style.position = position;
      }
    if (elm_z = elm.down('span.drop')) elm_z.style.zIndex = z_index;
    }*/
  }
}

var selection_feedback = function(li){
  new Effect.Highlight(li, {
    queue: 'end',
    beforeStart: function(){
        li.store('selection_feedback.style', li.readAttribute('style')); // make sure to set it to an empty string if it's null, otherwise you get problems in e.g. Safari
        li.setStyle({color: li.getStyle('background-color')}); // to temporarily invert the colors
    },
    startcolor: rgb_css_to_hex(li.getStyle('color')),
    duration: 0.2,
    afterFinish: function(){
      li.writeAttribute('style', li.retrieve('selection_feedback.style') || '');
    }
  });
  new Effect.Fade(li.up('ul.first-drop'), { queue: 'end', duration: 0.3, afterFinish: hide_macro_li(li) });
}

var what_is_category = function(){
  var category_description = $$('div.category-description')[0];

  $$('a.category-description-link')[0].observe('click', function(){
    $$('div.category-description')[0].toggle();
  });
}

var category_top_right_edit = function(id){
  var category_top_right = $(id).down('div.category-top-right');
  var edit_options_list = $(id).down('ul.edit_options');
  var show = function(){
    category_top_right.removeClassName('inactive');
    edit_options_list.removeClassName('inactive');
  };
  var hide = function(){
    edit_options_list.addClassName('inactive');
    category_top_right.addClassName('inactive');
  };

  $(id).down('span.edit_this').observe('mouseover', show);
  $(id).down('div.category-top-right').observe('mouseleave', hide);

  var category_selection_feedback = function(li){
    new Effect.Highlight(li, {
      queue: 'end',
      beforeStart: function(){
          li.store('selection_feedback.style', li.readAttribute('style')); // make sure to set it to an empty string if it's null, otherwise you get problems in e.g. Safari
          li.setStyle({color: li.getStyle('background-color')}); // to temporarily invert the colors
      },
      startcolor: rgb_css_to_hex(li.getStyle('color')),
      duration: 0.2,
      afterFinish: function(){
        li.writeAttribute('style', li.retrieve('selection_feedback.style') || '');
        hide();
      }
    });
  }

  edit_options_list.childElements('li').each(function(li){
    li.childElements('a').each(function(anchor){
      anchor.observe('click', function(e){
        category_selection_feedback(li);
      });
    });
  });
}

var make_categorized_forums_draggable = function(category_id){
  $$('#category_' + category_id + ' > div.column').each(function(forum_element, index) {forum_element.store('position', index)});
  $$('#category_header_' + category_id + '> div.category-top-right > ul.edit_options > li.reorder_forums > a')[0].observe('click', function(e){
    e.preventDefault();

    $('category_' + category_id).addClassName('reordering');
    $$('#category_' + category_id + ' > div.reorder > a')[0].show();
    Sortable.create('category_' + category_id, { // undo with Sortable.destroy(category_id);
      tag: 'div',
      only: 'column',
      constraint: undefined,
      overlap: 'horizontal',
      onUpdate: function(){
        $('category_' + category_id).store('changed', true);
      },
      onChange: function(element){
        $$('#category_' + category_id + ' > div.column').each(function(list_element, index){
          if (index % 2 === 0) {
            list_element.removeClassName('right').addClassName('left');
          } else {
            list_element.removeClassName('left').addClassName('right');
          }
        });
      }
    });
  });

  $$('#category_' + category_id + ' > div.column a').each(function(anchor){
    anchor.observe('click', function(event){
      if ($('category_' + category_id).hasClassName('reordering')){
        event.preventDefault();
      }
    });
  });

  $$('#category_' + category_id + ' > div.reorder > a')[0].observe('click',  function(e){
    e.preventDefault();

    $('category_' + category_id).removeClassName('reordering');
    Sortable.destroy('category_' + category_id);

    if ($('category_' + category_id).retrieve('changed') === true){
      $$('#category_' + category_id + ' > div.column').each(function(forum_element, index){
        forum_element.writeAttribute('style', undefined);
        if(index !== forum_element.retrieve('position')) {
          var ajax_update = new Ajax.Request(forum_element.readAttribute('data-forum_path'), { method: 'put', parameters: {'forum[position]': index}});
          forum_element.store('position', index);
        }
      });
      $('category_' + category_id).store('changed', false);
    }
  });
}



var add_category_reordering = function(){

  var reorder_anchor = $$('div.buttons-right > div.reorder > a')[0];
  var container = $('sortedlist').up('div.frame.columns');

  $('sortedlist').childElements().each(function(list_item, index){ list_item.store('position', index);});
  reorder_anchor.observe('click', function(event){
    var original_text = reorder_anchor.retrieve('reorder_text');
    if (typeof(original_text) === 'string'){
      reorder_anchor.update(original_text).store('reorder_text', undefined);
      container.removeClassName('reordering');
      Sortable.destroy('sortedlist');
      if ($('sortedlist').retrieve('changed') === true){
        $('sortedlist').childElements().each(function(list_item, index){
          var category_header_element = $('category_header_' + list_item.readAttribute('data-item_id'));
          var category_element = $('category_' + list_item.readAttribute('data-item_id'));
          container.insert(category_header_element).insert(category_element); // reorder the current categories
          if (index !== list_item.retrieve('position')){
            var ajax_update = new Ajax.Request(category_element.readAttribute('data-category_path'), { method: 'put', parameters: {'category[position]': index}});
            list_item.store('position', index);
          }
        });
        $('sortedlist').store('changed', false);
      }
    } else {
      reorder_anchor.store('reorder_text', this.innerHTML).update(this.readAttribute('data-done_text'));
      container.addClassName('reordering');
      Sortable.create('sortedlist', {only: 'sortable', onUpdate: function(){$('sortedlist').store('changed', true);}});
    }
  });
}

var submit_sortable_list = function(display_container, sort_container, sort_list, url){
  $$('#' + sort_list + ' > li.sortable.item').each(function(list_item, index){
    list_item.store('real_element', $$('#' + display_container + ' div.item')[index]);
  });
  $(display_container + '_reorder_done_link').observe('click', function(event){
    var list = $$('#' + sort_list + ' > li.sortable').reverse();
    list.each(function(list_item,index){
      list_item.retrieve('real_element').up().insert({top: list_item.retrieve('real_element')});
      if (index === 0){
        list_item.retrieve('real_element').addClassName('nobottom');
      } else {
        list_item.retrieve('real_element').removeClassName('nobottom');
      }
      $j(list_item).attr("data-zendesk-original-position", (list.length - index - 1));
    });
    $(sort_container).hide();
    $(display_container).show();
    var ajax_update = new Ajax.Request(url, { parameters: Sortable.serialize(sort_list) });
  });
}

/* Make IE 6 do (h)over */
function startList() {
  iterate_startList($("green"));
  if (document.getElementById("gray")) {
    iterate_startList($("gray"));}
}

function iterate_startList(navRoot) {
  if (!navRoot) {return;}
  for (i=0; i<navRoot.childNodes.length; i++) {
    node = navRoot.childNodes[i];
    if (node.nodeName=="LI") {
      node.onmouseover=function() {
        this.className+=" over";
        if (this.childNodes[2] && this.childNodes[2].nodeName=='UL')
          ie6_show_iframe_mask(this.childNodes[2]);
      }
      node.onmouseout=function() {
        this.className=this.className.replace(" over", "");
        ie6_hide_iframe_mask(this.childNodes[2]);
      }
    }
  }
}

function ie6_show_iframe_mask(el) {
  if (el)
    el.style.display = 'block';
  //if (!window.XMLHttpRequest) {
  var ieMat = document.createElement('iframe');
  if(document.location.protocol == "https:")
    ieMat.src="//0";
  else if(window.opera != "undefined")
    ieMat.src="";
  else
    ieMat.src="javascript:false";

  ieMat.id = 'mIframe';
  ieMat.scrolling="no";
  ieMat.frameBorder="0";
  ieMat.style.top = -1;
  ieMat.style.left= -1;
  ieMat.style.width= el.offsetWidth+"px";
  ieMat.style.height= el.offsetHeight+"px";
  ieMat.style.zIndex= -1;
  ieMat.style.filter='alpha(opacity=0)';
  el.insertBefore(ieMat, el.childNodes[0]);
  ieMat.style.position = 'absolute';
  //}
}

function ie6_hide_iframe_mask(el) {
  if (el)
    el.style.display = 'none';
  if (iframe = document.getElementById('mIframe'))
    iframe.style.display = 'none';
}

var ticket_id;

if(!Zendesk) var Zendesk = {};
Zendesk.resources = [];
Zendesk.Resource = Class.create();
  
Zendesk.Resource.prototype = {
  initialize : function(options) {          
    this.options      = options || {};   
    this.options.user = options.user || Cookie.get(this.options.anchor + '_user')
    this.options.pass = options.pass || Cookie.get(this.options.anchor + '_pass') 
    this.content_anchor = $$('#' + this.options.anchor + ' #content')[0]
    this.title_anchor   = $$('#' + this.options.anchor + ' #title')[0]  
     
     Ajax.Responders.register({ onException: function(r, e) { alert("Exception:\n\n" + e) }});          

    if (this.options.title) {
      this.title_anchor.innerHTML = this.options.title;
    }
    
    this.render();                                         
  },
  submit_credentials : function(form) {  
    this.options.user = form['username'].value;
    this.options.pass = form['password'].value;    
    if (this.options.user.blank() && this.options.pass.blank())
      alert('Please provide both a username and a password');
    else {
      Cookie.set(this.options.anchor + '_user', this.options.user);
      Cookie.set(this.options.anchor + '_pass', this.options.pass); 
      this.render();       
    }    
  },  
  logout : function() { 
    options = this.options;
    Cookie.erase(options.anchor + '_user');
    Cookie.erase(options.anchor + '_pass');
    this.options.user = this.options.pass = null;
    this.render();
  },
  submit_data : function(form) {
    control = this;
    var parameters = Form.serialize(form);
    parameters += "&user=" + control.options.user + "&pass=" + control.options.pass + "&domain=" + control.options.domain + "&use_ssl=" + control.options.use_ssl;
    if (ticket_id) {
      parameters += "&ticket_id=" + ticket_id;
    }
    if ( parameters.indexOf("media_type=") == 0 ) {
      var media_type = control.options.media_type || 'application/xml';
      parameters += "&media_type=" + media_type;
    }
    new Ajax.Request('/proxy.js', {asynchronous:true, evalScripts:true, parameters:parameters,
      onSuccess: function(transport) { control.resource_write_success(transport, control); enable_submit(form); },
      onFailure: function(transport) { control.resource_failure(transport, control); enable_submit(form); }
    }); 
    disable_submit(form)
  },
  render : function() { 
    control = this;  
    options = control.options;   
    if (options.login_content != null && !(options.user && options.pass)) 
      control.content_anchor.innerHTML = options.login_content();
    else {                    
      control.content_anchor.innerHTML =  options.application_content();        
      options.application_resources.each(function(resource){control.request(resource)});
    }    
  },
  request : function(options) {
    control = this;     
    if (options.resource == null) {
      if (options.on_success != null) {
        options.on_success();
      }
    }
    else {        
      media_type = options.media_type || 'application/json';
      new Ajax.Request('/proxy.js', {
        method: 'get',
        parameters: {user: control.options.user, pass: control.options.pass, 
                     domain: control.options.domain, use_ssl: control.options.use_ssl, 
                     resource: options.resource, media_type: media_type, cache_gets: control.options.cache_gets},
        onSuccess: function(transport) { control.resource_read_success(transport, control, options); },
        onFailure: function(transport){ control.resource_failure(transport, control); }
      });  
    }  
  },
  resource_failure : function(transport, control) {
    if (transport.status == 401) {  
      control.options.user = null; control.options.pass = null;               
      Cookie.erase(control.options.anchor + '_user'); Cookie.erase(control.options.anchor + '_pass');     
      if (control.content_anchor.innerHTML != control.options.login_content())      
        alert("Username and password are not correct. Please re-enter.");
      control.render();  }
    else {
      alert(transport.responseJSON.error)
    }
  },
  //Called when data has been read
  resource_read_success : function(transport, control, options) {
    if(options != null && options.on_success != null) {
      options.on_success(transport.responseJSON);      
    }
  },
  //Called when data has been written
  resource_write_success : function(transport, control) {
    if(transport.responseJSON.audit != null) {
      new Ajax.Request('/events/create.js', {
        method: 'post', asynchronous:true,
        parameters: { ticket_id: transport.responseJSON.audit.ticket_id,
                      value:     transport.responseJSON.audit.value,
                      reference: transport.responseJSON.audit.reference,
                      via_id:    transport.responseJSON.audit.via_id },
        onSuccess: function(transport) { },
        onFailure: function(transport){ alert('Failed to register event: '+transport.responseJSON.error); }
      });  
    }
  }  
}  


function enable_submit(form) {
  form['submit'].value = form['submit'].getAttribute('originalValue'); 
  form.enable();    
  form.reset();
}

function disable_submit(form) {
  form['submit'].setAttribute('originalValue', form['submit'].value);  
  form.disable();    
  form['submit'].value = 'Submitting...';    
}



var InputTracking = {
  trackedElements: [],
  enabled: true,

  trackElement: function(e) {
    if(!InputTracking.trackedElements.include(this)) {
      if (typeof(this.value) === 'undefined') {
        this.originalValue = this.innerHTML;
      } else {
        this.originalValue = this.value;
      }
      InputTracking.trackedElements.push(this);
      Event.stopObserving(this, 'keydown', InputTracking.trackElement);
    }
  },

  disable: function(e) {
    InputTracking.enabled = false;
    return true;
  },

  fixSubmit: function(element, eventName) {
    //I would do it like "Event.observe(form, 'submit', InputTracking.disable)",
    //but that does not work in IE
    var eventHandler = element[eventName];
    if (Object.isString(eventHandler)) {
      element[eventName] = "InputTracking.disable() && " + eventHandler;
    } else if (Object.isFunction(eventHandler)) {
      element.onsubmitWithoutInputTracking = eventHandler;
      element[eventName] = function(e) {
        return InputTracking.disable() && element.onsubmitWithoutInputTracking();
      };
    } else {
      element[eventName] = InputTracking.disable;
    }
  }
};

var InitialHelpValue = Class.create({
  initialize: function(formElement) {
    this.element = formElement;
    this.helpValue = formElement.getValue();

    Event.observe(this.element, 'focus', this.onFocus.bindAsEventListener(this));
    Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
  },

  onFocus: function(e) {
    if (this.element.getValue() == this.helpValue) {
      this.element.value = '';
    };
    this.element.removeClassName('initial_help_value');
  },

  onBlur: function(e) {
    if (this.element.getValue().blank()) {
      this.element.value = this.helpValue;
      this.element.addClassName('initial_help_value');
    };
  }
});

var CountrySelectField = Class.create({
  initialize: function(selectElement) {
    this.element = selectElement;
    this.container = new Element('div', {className: 'country_select_field'});
    this.closedView = new Element('div', {className: 'closed'});
    this.container.insert(this.closedView);
    this.openedView = new Element('div', {className: 'opened', style: 'display: none;'}).update('<ul/>');
    this.container.insert(this.openedView);
    this.renderOpenedView();
    this.updateOpenedView();
    this.updateClosedView();
    this.element.hide();
    this.element.insert({after: this.container});

    this.closedView.observe('click', this.toggle.bind(this))
  },

  renderOpenedView: function() {
    var list = this.openedView.down('ul');
    list.update();
    var item;
    this.element.select('option').each(function(option) {
      item = new Element('li', {country: option.value});
      this.renderOption(item, option);
      list.insert(item);
      item.observe('click', this.clickOption.bindAsEventListener(this));
    }, this);
  },

  updateOpenedView: function() {
    this.openedView.select('li.selected').each(function(item) {
      item.removeClassName('selected');
    });

    var selectedOption = this.element.down("option[value=" + this.element.getValue() + "]");

    this.openedView.down('li[country=' + selectedOption.value + ']').addClassName('selected');
  },

  updateClosedView: function() {
    var selectedOption = this.element.down("option[value=" + this.element.getValue() + "]");
    this.renderOption(this.closedView, selectedOption);
  },

  renderOption: function(element, option) {
    element.update();
    element.insert(new Element('img', {src: '/images/flags/' + option.value + '.gif'}));
    element.insert(' ' + option.innerHTML);
  },

  open: function() {
    //this.closedView.hide();
    this.openedView.show();
    this.element.focus();
  },

  close: function() {
    this.openedView.hide();
    //this.closedView.show();
  },

  toggle: function() {
    this.openedView.toggle();
    this.element.focus();
  },

  clickOption: function(e) {
    this.element.down("option[value=" + e.findElement('li').getAttribute('country').toLowerCase() + "]").selected = true;
    this.updateOpenedView();
    this.updateClosedView();
    this.close();
  }
});

var CheckboxMultiSelect = Class.create({
  initialize: function(selectElement) {
    this.element = selectElement;
    this.container = new Element('div', {className: 'checkbox_multi_select'});
    this.render();
    Element.replace(this.element, this.container);
  },

  render: function() {
    var item;
    var input;
    this.element.select('option').each(function(option) {
      input = new Element('input', {type: 'checkbox',
                                    value: option.value,
                                    name: this.element.name,
                                    id: this.element.identify() + '_' + option.value});
      input.checked = option.selected;

      item = new Element('div');
      item.insert(input);
      item.insert(new Element('label', {'for': input.id}).update(option.innerHTML));
      if (input.id != "account_allowed_translation_locale_ids_1") { //special case for english by zendesk
        var results = input.id.split("_");
        item.insert(new Element('a', { 'class': 'lightview',
                                       href: '#more_translation_info_' + results[5],
                                       title: ' :: :: topclose: true, autosize: true' }).update('(more info)'));
      }
      this.container.insert(item);
    }, this);
  }
});

var DelayedRuleCounts = Class.create(Hash, {
  initialize: function($super, options) {
    $super();
    this.ticket_show_empty_views = options.ticket_show_empty_views || false;
  },

  requestUpdate: function(ruleIds) {
    new Ajax.Request('/rules/count', {
      parameters: {'rule_ids[]': ruleIds},
      onSuccess: this.updateUiFromResponse.bind(this)
    });
  },

  updateUiFromResponse: function(response) {
    response.responseJSON.each(function(data) {
      this.set(data.ruleId, {value: data.value, fresh: data.fresh});
      this.updateUiForRule(data.ruleId);
    }, this);
    this.update(5);
  },

  updateNow: function() {
    this.update();
  },

  update: function(delay) {
    var ruleIdsThatNeedRefreshing = $$('span.r_count[data-fresh=false]').map(function(elm) {return elm.readAttribute('data-rule-id')});
    ruleIdsThatNeedRefreshing = ruleIdsThatNeedRefreshing.uniq();
    if (ruleIdsThatNeedRefreshing.length > 0) {
      if (delay) {
        this.requestUpdate.bind(this).delay(5, ruleIdsThatNeedRefreshing);
      } else {
        this.requestUpdate(ruleIdsThatNeedRefreshing);
      };
    };
  },

  updateUiForRule: function(ruleId) {
    var data = this.get(ruleId);
    var elements = $$('span.r_count[data-rule-id=' + ruleId + ']');

    for (var i=0; i < elements.length; i++) {
      var elm = elements[i];
      elm.update('(' + data.value + ')');
      elm.writeAttribute('data-fresh', data.fresh ? 'true' : 'false');

      if (data.fresh) {
        if (data.value == 0) {
          elm.up('a').addClassName('empty');
          if (!this.ticket_show_empty_views) {
            elm.up('li').slideUp();
          }
        } else {
          elm.up('a').removeClassName('empty');
        };
      };
    };
  },

  updateUi: function() {
    this.keys().each(this.updateUiForRule, this);
  }
});

Event.observe(document, 'dom:loaded', function() {
  $$('textarea').each(function(textarea) {
    Event.observe(textarea, 'keydown', InputTracking.trackElement);
  });

  $$('form').each(function(form) {
    InputTracking.fixSubmit(form, 'onsubmit');
  });

  $$('form input[type=button]').each(function(button) {
    InputTracking.fixSubmit(button, 'onclick');
  });

  $$('input.initial_help_value').each(function(formElement) {
    new InitialHelpValue(formElement);
  });

  $$('select.country_select_field').each(function(selectElement) {
    new CountrySelectField(selectElement);
  });

  $$('select.checkbox_multi_select').each(function(selectElement) {
    new CheckboxMultiSelect(selectElement);
  });
});

//Somehow this does not work when done with Event.observe
window.onbeforeunload = function() {
  if (InputTracking.enabled) {
    for (var i = 0; i < InputTracking.trackedElements.length; i++) {
      var new_value;
      if (typeof(InputTracking.trackedElements[i].value) === 'undefined'){
        new_value = InputTracking.trackedElements[i].innerHTML;
      } else {
        new_value = InputTracking.trackedElements[i].value;
      }
      if (new_value !== InputTracking.trackedElements[i].originalValue) {
        return "You have entered some text on this page. If you choose to proceed you will lose your changes.";
      };
    };
  };
};
document.observe('dom:loaded', function() {
  if(window.fluid) {
    document.body.insert("<div id='notifications' style='display:none'></div>");

    //Synchronous poller
    new Ajax.PeriodicalUpdater('notifications', '/notifications/status', {
      asynchronous: false, method: 'get', frequency: 120, decay: 10,
      requestHeaders: {Accept: 'application/json'},
      onSuccess: function(transport) {
        var json = transport.responseText.evalJSON();

        if(json.count != null && json.count > 0) {
          window.fluid.dockBadge = json.count;
        }

        if(json.message != null) {
          window.fluid.showGrowlNotification({
            title: "Zendesk update",
            description: json.message.toString(),
            priority: 1,
            sticky: false,
            identifier: "Zendesk " + Math.random() * 10000
          });
        }
      }
    });
  }
});

/* User */
Autocompleter.lookupUser = function(multi_user, searchTerm, callback) {
  var url = multi_user ? '/people/users/multivalue_autocomplete' : '/people/users/autocomplete';
  new Ajax.Request(url, { parameters: {name: searchTerm, rand: (new Date()).getTime()},
                          onSuccess: function(response) {
                            callback(response.responseJSON);
                          }
                        });
};

Autocompleter.UserCache = new Autocompleter.Cache(Autocompleter.lookupUser.curry(false));
Autocompleter.cachedLookupUser = Autocompleter.UserCache.lookup.bind(Autocompleter.UserCache);

Autocompleter.MultiUserCache = new Autocompleter.Cache(Autocompleter.lookupUser.curry(true));
Autocompleter.cachedLookupMultiUser = Autocompleter.MultiUserCache.lookup.bind(Autocompleter.MultiUserCache);

/* Tag */
Autocompleter.lookupTag = function(searchTerm, callback) {
  new Ajax.Request('/tags/autocomplete', { parameters: {name: searchTerm, rand: (new Date()).getTime()},
                                           onSuccess: function(response) {
                                             callback(response.responseJSON);
                                           }
                                         });
};

Autocompleter.TagCache = new Autocompleter.Cache(Autocompleter.lookupTag);
Autocompleter.cachedLookupTag = Autocompleter.TagCache.lookup.bind(Autocompleter.TagCache);

/* Account */
Autocompleter.lookupAccount = function(searchTerm, callback) {
  new Ajax.Request('/monitor/children/lookup', { parameters: {query: searchTerm, rand: (new Date()).getTime()},
                                           onSuccess: function(response) {
                                             callback(response.responseJSON);
                                           }
                                         });
};
Autocompleter.AccountCache = new Autocompleter.Cache(Autocompleter.lookupAccount, {choices: 50});
Autocompleter.cachedLookupAccount = Autocompleter.AccountCache.lookup.bind(Autocompleter.AccountCache);

/* Organization */
Autocompleter.lookupOrganization = function(searchTerm, callback) {
  new Ajax.Request('/organizations/autocomplete', { parameters: {name: searchTerm, rand: (new Date()).getTime()},
                                           onSuccess: function(response) {
                                             callback(response.responseJSON);
                                           }
                                         });
};
Autocompleter.OrganizationCache = new Autocompleter.Cache(Autocompleter.lookupOrganization);
Autocompleter.cachedLookupOrganization = Autocompleter.OrganizationCache.lookup.bind(Autocompleter.OrganizationCache);


var ZdSubscription = {
  initialize : function(currentPlanId, sourcePage) {
    Page.originalPlanId = currentPlanId;
    Page.setCurrentPlan(currentPlanId);
    Page.selectPlan(Page.currentPlan());
    $('plan-' + Page.currentPlan() + '-vars-inner').innerHTML = $('plan-vars-org').innerHTML;
    $('plan-vars-org').remove();
  }, 

  initializeUpgradeScreen : function(originalPlanId) {
    Page.originalPlanId = originalPlanId;
    Page.currentPlanId  = originalPlanId;
    Page.updatePrice();
  },
  
  updatePrice: function() {
    var success = new Ajax.Request('/account/subscription/calculate', { 
      method: 'post',
      parameters: { 
        current_plan       : ZdSubscription.currentPlan(),
        max_agents         : ZdSubscription.maxAgents(), 
        plan_type          : ZdSubscription.planType(),
        billing_cycle_type : ZdSubscription.billingCycleType() 
      },
 
      // TODO: do we really need a spinner/waiting indication? 
      // onLoading : ZdSubscription.beforeCalculateBilling,

      onSuccess : function(response) { 
        ZdSubscription.calculateBillingCallback(response.responseJSON); 
      }
    }); 
  }, // updatePrice

  maxAgents        : function() { return ZdSubscription.adjustAgents($F('subscription_max_agents')); },  // maxAgents
  planType         : function() { return $F('subscription_plan_type'); }, // planType
  billingCycleType : function() { return $F('subscription_billing_cycle_type'); }, // billingCycleType
  currentPlan      : function() { return Page.currentPlanId; } , // currentPlan
  
  setCurrentPlan   : function(planId) { 
    $('subscription_plan_type').value = planId;
    Page.currentPlanId = planId; 
  }, // setCurrentPlan

  beforeCalculateBilling : function() {
    $('billing-cycle-price').innerHTML = '-';
    $('billing-cycle-discounted-amount').innerHTML  = '-';
    $('billing-cycle-undiscounted-price').innerHTML = '-';
  }, // beforeCalculateBilling

  calculateBillingCallback : function(data) { 
    $('billing-cycle-price').update('$' + addCommas(data.discounted_price.toFixed(2)));
    $('billing-cycle-discounted-amount').update('-&nbsp;$' + addCommas(data.discounted_amount.toFixed(2)));
    $('billing-cycle-undiscounted-price').update('$' + addCommas(data.undiscounted_price.toFixed(2)));
    if($('billing-cycle-desc')){ 
      $('billing-cycle-desc').update("Billed " + ZdSubscription.billingCycleName());
    }
  }, // cb_calculateBilling

  billingCycleName : function() {
    switch(ZdSubscription.billingCycleType()) { 
      case('1') : { return "monthly";   };
      case('2') : { return "quarterly"; };
      case('3') : { return "biannually"; };
      case('4') : { return "annually";  };
    }; 
  }, // billingCycleName 

  adjustAgents : function(agents) {
    var agents = parseInt(agents);
    if (isNaN(agents)) { agents = 1; }
    var currentPlan = Page.currentPlan();
    var max_agent_floor    = Page.plans[currentPlan]["max_agent_floor"];
    var max_agent_ceiling  = Page.plans[currentPlan]["max_agent_ceiling"];
    if (agents < max_agent_floor)   { agents = max_agent_floor; }
    if (agents > max_agent_ceiling) { 
      agents = max_agent_ceiling; }
    $('subscription_max_agents').value = agents;

    return agents;
  }, // adjustAgents

  selectPlan : function(selectedPlan) {
    if($$('.maximum-agent-notification')[0]) {
      $$('.maximum-agent-notification')[0].remove();
    }

    var thisPlan = ZdSubscription.currentPlan();
    ZdSubscription.setCurrentPlan(selectedPlan);

    //Update billing cycle labels
    var cycleOptions = $('subscription_billing_cycle_type').options;
    for(var i=0; i< cycleOptions.length; i++) {
      //update() does not work for IE in this case. cycleOptions[i].update(Page.labels[""+selectedPlan][""+cycleOptions[i].value]);
      $j(cycleOptions[i]).html(Page.labels[""+selectedPlan][""+cycleOptions[i].value]);
    }

    [1, 2, 3].each(function(s) {
      var selectButton = $('plan-' + s + '-select');
      var divPlanVars  = $('plan-' + s + '-vars');
      var planNode = $('plan-' + s);
      
      if(selectedPlan === s){
        planNode.setStyle({border: '3px solid #A4D1DB'}); 
        selectButton.writeAttribute({disabled : true});
        selectButton.value = "Selected plan!";
        
        if (s !== thisPlan) {
          plan_vars = $('plan-' + thisPlan + '-vars-inner'); //.innerHTML;
          plan_vars.id = 'plan-' + s + '-vars-inner';
          divPlanVars.insert({ top: plan_vars }); 
        } // !thisPlan
        
        divPlanVars.style.padding = '5px 10px';
        divPlanVars.style.borderTop = '1px dashed #CCC';
        ZdSubscription.updatePrice();
      
      } else { // selectedPlan != s
      
        planNode.style.border = '3px solid #DDD';
        selectButton.disabled = false;
        selectButton.value = "Select this plan";
        divPlanVars.style.padding = '';
        divPlanVars.style.borderTop = 'none';
      } // if / else
    }); // [1,2,3].each
  }, // selectPlan

  confirmSubscription : function() {    
    if(Page.isDowngrading()){
      window.location = '/account/subscription/downgrade' + '?' + Page.buildSubscriptionQueryString();
      return false;
    } else {
      Lightview.show({
        href: '/account/subscription/confirm',
        rel: 'ajax',
        options: {
          topclose: true,
          autosize: true,
          backgroundColor: '#999',
          ajax: {
            parameters: { 
              'subscription[plan_type]': $F('subscription_plan_type'), 
              'subscription[max_agents]': $F('subscription_max_agents'), 
              'subscription[billing_cycle_type]': $F('subscription_billing_cycle_type') 
            },  
            method: 'get'
          }
        } // options
      }); // Lightview.show
    }
  },
  
  isPlusPlan : function(){
    return(Page.originalPlanId === 3)
  },

  isDowngrading : function(){
    return(Page.currentPlanId < Page.originalPlanId);
  },
    
  buildSubscriptionQueryString : function() {
    return $('subscription_form').serialize();
  },
  
  submitSubscription : function() {
    $('subscription_form').submit();
  },
  
  AgentNotification : function() {
    var notificationNode = $$('#plan-' +Page.currentPlanId+ '-vars-inner > p')[0];
    var planName = Page.plans[Page.currentPlanId]["name"];
    var maxAgents = Page.plans[Page.currentPlanId]["max_agent_ceiling"];
    var minAgents = Page.plans[Page.currentPlanId]["max_agent_floor"];
    var enteredAgent = $('subscription_max_agents').value;
    var upgradePath;
    
    if(planName === "Solo"){
      upgradePath = "<a onclick='Page.selectPlan(2);; return false;' id='plan-2-select' href='#' class='plan-select'>Regular</a> or " +
      "<a onclick='Page.selectPlan(3);; return false;' id='plan-3-select' href='#' class='plan-select'>Plus+</a>";
    } else {
        upgradePath = "<a onclick='Page.selectPlan(3);; return false;' id='plan-3-select' href='#' class='plan-select'>Plus+</a>";
    }
    
    function nodeCheck(){
      if($$('.maximum-agent-notification')[0]) {
        $$('.maximum-agent-notification')[0].remove();
      }
    }
    
    if(enteredAgent > maxAgents) {
      nodeCheck();
      notificationNode.insert("<p class='maximum-agent-notification'>" +maxAgents+ " agent" + ((maxAgents !== 1) ? 's' : '') + " maximum for the " +planName+ " plan. " +
      "You must upgrade to the " +upgradePath+ " plan to add more agents</p>");
    } else if (enteredAgent < minAgents) {
        nodeCheck();
        notificationNode.insert("<p class='maximum-agent-notification'>There is a minimum of "+minAgents+" agents for the " +planName+ " plan.</p>");
    } else {
        nodeCheck(); 
    }
  }

}; // "class" ZdSubscription

var ZdCreditCard = { 
  submitCreditCardForm : function() {
    $('credit-card-error').hide(); 
    if(ZdCreditCard.validate()) { 
      ZdCreditCard.serializeExpiry();
      $('transparent-redirect').submit();
      $('submit-credit-card').disabled = true; 
      $('submit-credit-card').value = 'Please wait...';
    } else {
      $('credit-card-error').show(); 
    }
    return false;
  },

  validate : function() {
    var country = $F('country');
    var state   = $F('state');
    var zip     = $F('zip');

    if( zip.blank() || country.blank() || zip.blank() ) { return false; } 
    if( country == "prompt") { return false; }
    if( country == "US") { if( state == "prompt") { return false; } }
    return true;
  },

  resetCreditCardForm : function() { 
    var submitCreditCard = $('submit-credit-card');
    var submitCreditCardInTrial = $$('input#submit-credit-card.trial')[0];
    var termsAgree = $('terms_agree');
    submitCreditCard.disabled = false;

    // for trial form
    if (submitCreditCardInTrial){
      submitCreditCardInTrial.value = 'Begin my subscription';
      submitCreditCard.disabled = true;
      termsAgree.observe('click', function(event){
        if(termsAgree.checked === true) {
          submitCreditCard.disabled = false;
        }
        else if (termsAgree.checked === false){
          submitCreditCard.disabled = true;
        }
      });
    }
    else {
      submitCreditCard.value = 'Submit Credit Card';
    }
  },

  showCvvHelper : function() { 
    Lightview.show({
      href: '/account/subscription/cvv',
      rel: 'ajax',
      options: {
        ajax: { method: 'get' },
        topclose: true,
        autosize: true,
        backgroundColor: '#FFF'
      }});
  },

  serializeExpiry : function() {
    var month = $F('expiry_month');
    var year  = $F('expiry_year');
    $('ccexp').value = month + "" + year;
  },

  preloadImages : function() {
   image = new Image();
   image.src = "/images/find-the-cvv.png";
  }, 

  toggleStateSelect : function() { 
    if($('country').value == 'US') { 
      $('state-select-row').show(); 
      $('state').disabled = false; 
    } else { 
      $('state-select-row').hide();
      $('state').disabled = true; 
    };
  }
};

var ZendeskSearchCursor = Class.create({
  initialize: function(options) {
    this.pages            = new Object();
    this.pages.length     = options.pageCount + 1;
    this.currentPageIndex = options.pageIndex;
  }
});

var ZendeskSearcher = Class.create({
  initialize: function(options) {
    self.latestQuery = null;
    this.options     = options;
		if (typeof(this.options.per_page) == "undefined")
			{ this.options.per_page = 3; }
  },
  executeSearch: function(query, page) {
    this.latestQuery = query;
    
    new Ajax.Request('/suggestions/search.json', {
      requestHeaders: { Accept: 'application/json' },
      method:'get',
      parameters: {
        query: query,
        per_page: this.options.per_page,
        page: page
      },
      onSuccess: function(transport) {
        var searchResult = transport.responseText.evalJSON();
        this.results     = searchResult.results;

        // Rewrite the results to the expected format for rendering
        this.results.each(function(result) {
          result.titleNoFormatting = result.title;
          result.content           = result.body;
          result.url               = '/entries/'+result.id;
        });

        this.cursor = new ZendeskSearchCursor({ pageCount: searchResult.pages, pageIndex: searchResult.page });
        this.callbackMethod();
      }.bind(this),
      onFailure: function() {
        $('topic_suggestions').update(new Element('h2').update(this.options.noResults));
        $('topic_suggestions').removeClassName('loading');
      }.bind(this)
    });
  },
  execute: function(query) {
    return this.executeSearch(query, 1);
  },
  gotoPage: function(page) {
    if(this.latestQuery) {
      return this.executeSearch(this.latestQuery, page);
    }
    else {
      return false;
    }
  },
  setSearchCompleteCallback: function(callbackScope, callbackMethod, args) {
    this.callbackScope  = callbackScope;
    this.callbackMethod = callbackMethod.bind(callbackScope);
  }
});

var SuggestionsSearch = Class.create({
  initialize: function(options) {
    this.options = options;
    
    var moreLink  = new Element('a').update(this.options.more);
    this.more     = new Element('li', {id: 'more_suggestions'}).update(moreLink);
    this.showMore = options.showMore;
  },

  searchComplete: function() {
    $('topic_suggestions').removeClassName('loading');

    Try.these(this.more.remove);

    //clear if this is a new search
    if (!this.searcher.cursor || this.searcher.cursor.currentPageIndex == 0) {
      $('topic_suggestions').update('');
    }

    if (this.searcher.results && this.searcher.results.length > 0) {
      var list = $('suggestions');
      if (!list) {
        //$('topic_suggestions').insert(new Element('h2').update(this.options.header));
        list = new Element('ul', {id: 'suggestions'});
        $('topic_suggestions').insert(list);
      };

      this.searcher.results.each(function(result) {
        //removes the account name prefix in titles
        var title = result.titleNoFormatting.gsub(/.* :: /, '');
        var link = new Element('a', {href: result.url}).update(title);

        var item = new Element('li', {className: 'suggestion'});
        item.insert(new Element('h3').update(link));
        item.insert(new Element('div').update(result.content.stripTags().truncate(160)));
        
        this.insert(item);
      }, list);

      if(this.searcher.cursor && this.searcher.cursor.currentPageIndex < this.searcher.cursor.pages.length - 1) {
        list.insert(this.more);
      }
      
    } 
    else {
      if(this.options.emptyResultRedirect) {
        window.location = this.options.emptyResultRedirect + escape($F('suggestions_query'));
        return false;
      }
      else {
        $('topic_suggestions').insert(new Element('h2').update(this.options.noResults));
      }
    };
  },

  onSubmit: function() {
    $('topic_suggestions').update();
    $('topic_suggestions').addClassName('loading');

    this.searcher.execute($F('suggestions_query'));

    return false;
  },

  onShowMore: function() {
    this.more.remove();
    $('topic_suggestions').addClassName('loading');
    this.searcher.gotoPage(this.searcher.cursor.currentPageIndex + 1);
    return false;
  },

  setup: function() {
    if(this.options.mechanism === 'google') {
      this.searcher = new google.search.WebSearch();
      this.searcher.setSiteRestriction(this.options.site);
      this.searcher.setResultSetSize(google.search.Search.SMALL_RESULTSET);
      this.searcher.setRestriction(google.search.Search.RESTRICT_SAFESEARCH, google.search.Search.SAFESEARCH_OFF);
      this.searcher.setSearchCompleteCallback(this, this.searchComplete, null);
    }
    else {
      this.searcher = new ZendeskSearcher(this.options);
      this.searcher.setSearchCompleteCallback(this, this.searchComplete, null);
    }

    $('suggest_form').onsubmit = this.onSubmit.bind(this);
    
    if(this.options.moreLink) {
      this.more.observe('click', function() {
        window.location = this.options.moreLink + escape($F('suggestions_query'));
      }.bind(this));
    }
    else {
      this.more.observe('click', this.onShowMore.bind(this));
    }
  }
});


var Account = Class.create({
  initialize: function(attributes) {
    this.id                      = attributes['id'];
    this.name                    = attributes['name'];
    this.showChangePassword      = attributes['showChangePassword'];
    this.showUserProfile         = attributes['showUserProfile'];
    this.showChangePassword      = attributes['showChangePassword'];
    this.hasRemoteAuthentication = attributes['hasRemoteAuthentication'];
    this.isSandbox               = attributes['isSandbox'];
    this.isOpen                  = attributes['isOpen'];
    this.urlPrefix               = attributes['urlPrefix'];
    this.secureUrlPrefix         = attributes['secureUrlPrefix'];
    this.forumsTitle             = attributes['forumsTitle'];
    if (attributes['lastTrialDay']) {
      this.lastTrialDay          = new Date(attributes['lastTrialDay']);
    } else {
      this.lastTrialDay          = null;
    };
  }
});

var User = Class.create({
  initialize: function(attributes) {
    this.id               = attributes['id'];
    this.account          = attributes['account'];
    this.name             = attributes['name'];
    this.email            = attributes['email'];
    this.assumed          = attributes['assumed'];
    this.organization     = attributes['organization'];
    this.accessibleForums = attributes['accessibleForums'];

    switch(attributes['role'])
    {
    case User.roles.endUser:
      this.isAnonymous = attributes['id'] == null;
      this.isEndUser = true;
      this.isAgent = false;
      this.isAdmin = false;
      break;
    case User.roles.admin:
      this.isAnonymous = false;
      this.isEndUser = false;
      this.isAgent = true;
      this.isAdmin = true;
      break;
    case User.roles.agent:
      this.isAnonymous = false;
      this.isEndUser = false;
      this.isAgent = true;
      this.isAdmin = false;
      break;
    }

    this.canViewOrganization = this.organization != null && (!this.isEndUser || attributes['restriction'] == User.restrictions.organization || this.organization.isShared);
  }
});
User.roles = {endUser: 0, admin: 2, agent: 4};
User.restrictions = {none: 0, groups: 1, organization: 2, assigned: 3, requested: 4}

var Organization = Class.create({
  initialize: function(attributes) {
    this.id       = attributes['id'];
    this.name     = attributes['name'];
    this.isShared = attributes['isShared'];
  }
});

var currentUserVersion = Cookie.get('zendesk_user_version');
var currentUser = null;
var currentAccount = null;
