$z.defModule('access/index', {
  initialize: function() {
    this.addEmailToLink();
    $j("#user_email").change(function() {
      $z('access/index').addEmailToLink();
    });
  }, 

  addEmailToLink: function() {
    if ($j.trim($j("#user_email").val()).length==0) {
      $j('#password_help').attr("href", "/access/help");
    } else {
      $j('#password_help').attr("href", "/access/help?email=" + $j("#user_email").val());
    }
  }
});


$z.defModule('account/monitored_twitter_handles/index', {
  initialize: function() {
    var addMonitorLink = $j('p.add_monitor_handle a#add-twitter');
    if(arguments[0] == true) {
      addMonitorLink.click(function(){
        $j('div.bubble').slideDown("200");
      });
    } else {
      addMonitorLink.click(this.addTwitterMonitorHandle());
    }

    MTH.initialize();
  },
  addTwitterMonitorHandle : function() {
    var self = this;
    return(function(event) {
      Lightview.show({
        href: '/account/monitored_twitter_handles/new',
        rel: 'ajax',
        options: {
          topclose: true,
          autosize: true,
          backgroundColor: '#999',
          ajax: {
            method: 'get'
          }
        } // options
      }); // Lightview.show
    })
  }
});

var MTH = {
  initialize: function() {
    $j('input.handle_master').each(function(index, checkbox) {
      $j(checkbox).click(MTH.setPrimary);
    });
  },

  setPrimary: function(event) {
    var checkbox = $j(event.target);
    var id       = checkbox.attr('id').split('_').last();
    var checked  = checkbox.attr('checked');

    if (checked) {
      MTH.uncheckSiblings(checkbox);
    }

    MTH.togglePrimaryFlag(id, checked);
    MTH.requestUpdate(id, checked);
  },

  showSpinner: function(id) {
    $j('#spinner-' + id).show();
  },

  hideSpinner: function(id) {
    $j('#spinner-' + id).hide();
  },

  uncheckSiblings: function(checkbox) {
    $j('input.handle_master').attr('checked', false);
    checkbox.attr('checked', true);
  },

  togglePrimaryFlag: function(id, checked) {
    $j('.primary-selector').hide();

    if (checked) {
      $j('#primary-selector-' + id).show();
    }
  },

  requestUpdate: function(id, checked) {
    MTH.showSpinner(id);

    $j.ajax({
      type: 'PUT',
      url: '/account/channels/' + id,
      data: { 'handle': { 'master': checked } },
      success: function() {
        MTH.hideSpinner(id);
      }
    });
  }
};

$z.defModule("account/personalize/show", {
  initialize: function(params) {
    
    $j("#account_features_forums2").click(function() {
      $j("#forums_on_home_page_control").toggle();
    });
  }
});

$z.defModule('archived_tickets/index', {
  initialize: function(){
    this.updateUI();
    $j('select#filter_by').change(this.updateUI);
  },

  updateUI: function() {
    ['requester', 'organization'].each(function(item) {
      if (item == $j('select#filter_by').val()) {
        $j('#' + item).show();
      } else {
        $j('#' + item).hide();
      };
    });
  }
});
$z.defModule("entries/_forums1_show", {
  initialize: function() {
    $j("a.start-post-editing").click(function(event) {
      event.preventDefault();
      var formSelector = $j(this).attr("data-form-location");
      var textareaId = $j(this).attr("data-textarea-id");

      $j(formSelector).show();
      tinyMCE.execCommand("mceAddControl", false, textareaId);

      $j(this).closest("div.view-post").hide();
    });

    $j("a.cancel-post-editing").click(function(event) {
      event.preventDefault();
      var formSelector = $j(this).attr("data-form-location");
      var textareaId = $j(this).attr("data-textarea-id");

      $j(this).closest("form").prev("div.view-post").show();
      tinyMCE.execCommand("mceRemoveControl", false, textareaId);
      InputTracking.trackedElements = [];
      $j(formSelector).hide();
    });
  }
});
$z.defModule('entries/_forums2_show', {
  initialize: function (params) {
    $z("entries/_forums1_show").initialize();

    var self = this;
    self.zd_label_answered = $j('div.frame > div.entry span.zd_label.answered');
    $j('div#history.frame > div.item').each(function (index, element) {
      var post_id = $j(element).attr('data-post_id');
      if (params['is_moderator?'] === true) {
        $j(element).find('div.user_formatted span.label_theanswer').click(self.set_the_answer_toggle_option(post_id));
      }
    });

    $j("a[property='is_locked']").click(function(event) {
      $j("div.commenting-controls div.control").toggle();
    });
  },

  // Moderator functions
  
  set_the_answer_toggle_option: function (post_id) { // generates and returns an onClick handler, so that it's easy to refactor this to return a closure with e.g. the post ID for that particular element
    var self = this;
    return(function (event) {
      var answer_span = $j(this);
      answer_span.toggleClass('answered').addClass('ajax');
      var set_answer_label = self.set_answered_label(answer_span.hasClass('answered'));
      $j.post(answer_span.attr('data-update_answer_path'), {is_answer: answer_span.hasClass('answered')}, function(){
        $j.ajax({
          url: answer_span.attr('data-is_answered_path'),
          dataType: 'json',
          type: "GET",
          success: set_answer_label,
          complete: function(){ answer_span.removeClass('ajax');}
        });
      });
    });
  },

  set_answered_label: function (is_answered){
    var self = this;
    if (is_answered === true){
      self.zd_label_answered.addClass('selected');
    } else {
      return function(msg){
        self.zd_label_answered.toggleClass('selected', msg);
      }
    }
    this.zd_label_answered.toggleClass('selected', is_answered);
  },

  set_moderator_toggle_option_for: function (property, on) {
    $(property + '_option').children[0].className = (on ? 'selected' : 'deselected'); 
    $(property + '_option').children[0].className = (on ? 'deselected' : 'selected');
  },

  set_moderator_idea_label: function (flag) {
    $('flag_option').children[0].className = (flag == 1 ? 'selected' : 'deselected'); 
    $('flag_option').children[1].className = (flag == 200 ? 'selected' : 'deselected'); 
    $('flag_option').children[2].className = (flag == 201 ? 'selected' : 'deselected'); 
  }
});
$z.defModule('entries/_sidebar_moderator', {
  initialize: function (params) {
    var self = this;
    self.moderatorBox = $j("#moderator_box");
    self.actionDiv = $j('#contentcolumn > div.content > div.action');
    self.adminLabels = $j('#moderator_box > p.labels');
    self.zdLabels = $j('div.entry');
    self.setModeratorToggleOptionFor();
    self.renderModeratorIdeaLabelFor();
  },
  
  setModeratorToggleOptionFor: function () {
    var self = this;
    self.moderatorBox.find("ul.actions > li > a.mod_option").click(self.selectToggle());
  },

  renderModeratorIdeaLabelFor: function () {
    var self = this;
    self.moderatorBox.find('p.labels > a').click(self.selectToggle());
  },

  selectToggle: function (){
    var self = this;
    return function(event){
      if ($j(this).hasClass('selected')){
        $j(this).removeClass('selected');
        $j.ajax({
          url: $j(this).attr('data-deselected_entry_path'),
          success: self.updatePage("deselected", ($j(this).attr('property'))),
          dataType: 'json',
          type: 'put'
        });
      } else {
        $j(this).addClass('selected');
        $j.ajax({
          url: $j(this).attr('data-selected_entry_path'),
          success: self.updatePage("selected", ($j(this).attr('property'))),
          type: 'put',
          dataType: 'json'
        })
      }
    }
  },

  updatePage: function(state, property){
    var self = this;
    switch (property) {
      case 'planned':
        if(state === 'selected'){
          self.adminLabels.find('a.topic_label_done').removeClass('selected');
          self.adminLabels.find('a.topic_label_not_planned').removeClass('selected');
          self.zdLabels.find('span.done').removeClass('selected');
          self.zdLabels.find('span.not_planned').removeClass('selected');
          self.zdLabels.find('span.planned').addClass('selected');
        } else {
          self.adminLabels.find('a.topic_label_planned').removeClass('selected');
          self.zdLabels.find('span.planned').removeClass('selected');
          self.zdLabels.find('span.planned').removeClass('selected');
        }
        break;
      case 'done':
        if(state === 'selected'){
          self.adminLabels.find('a.topic_label_planned').removeClass('selected');
          self.adminLabels.find('a.topic_label_not_planned').removeClass('selected');
          self.zdLabels.find('span.planned').removeClass('selected');
          self.zdLabels.find('span.not_planned').removeClass('selected');
          self.zdLabels.find('span.done').addClass('selected');
        } else {
          self.adminLabels.find('a.topic_label_done').removeClass('selected');
          self.adminLabels.find('span.done').removeClass('done');
          self.zdLabels.find('span.done').removeClass('selected');
        }
        break;
      case 'not_planned':
        if(state === 'selected'){
          self.adminLabels.find('a.topic_label_planned').removeClass('selected');
          self.adminLabels.find('a.topic_label_done').removeClass('selected');
          self.zdLabels.find('span.planned').removeClass('selected');
          self.zdLabels.find('span.done').removeClass('selected');
          self.zdLabels.find('span.not_planned').addClass('selected');
        } else {
          self.adminLabels.find('a.topic_label_not_planned').removeClass('selected');
          self.adminLabels.find('span.not_planned').removeClass('done');
          self.zdLabels.find('span.not_planned').removeClass('selected');
        }
        break;
      case 'answered':
        if(state === 'selected'){
          self.zdLabels.find('span.answered').addClass('selected');
        } else {
          self.zdLabels.find('span.answered').removeClass('selected');
        }
      break;
    }
  }

})

$z.defModule('entries', { // can define some stuff here for any home action to use
});

$z.defModule('entries/index', {
  initialize: function(){}
});
$z.defModule("forums/form", {
  initialize: function(params) {
    $j("input#forum_visibility_restriction_id_1, input#forum_visibility_restriction_id_2").click(function() {
      $j("#forum_is_locked_false").removeAttr("disabled");

      $j(".forum-language-selector").show("slow");
    });

    $j("input#forum_visibility_restriction_id_3").click(function() {
      $j("#forum_is_locked_false").attr("disabled", "disabled");
      $j("#forum_is_locked_true").attr("checked", "checked");

      $j(".forum-language-selector").hide();
      $j("#forum_translation_locale_id").val("");
    });
  }
});

var HeaderRenderer = {};

HeaderRenderer.hasRenderedTopRight = false;
HeaderRenderer.renderTopRight = function() {
  var topRight = $j('#top-right');
  if (!topRight || HeaderRenderer.hasRenderedTopRight) {
    return;
  };

  HeaderRenderer.hasRenderedTopRight = true;

  var menuItems = [];

  if (!currentUser.isAnonymous) {
    var name = $j('<span/>', {id: 'top-right-name', html: currentUser.name});
    if (currentAccount.isSandbox) {
      name.append(" (SANDBOX)");
    };
    menuItems.push(name);
  };

  if (currentUser.isAgent && currentAccount.lastTrialDay) {
    menuItems.push(i18n_distance_of_time_in_words(currentAccount.lastTrialDay, new Date()) + ' left in trial');
  };

  if (currentAccount.showUserProfile && !currentUser.isAnonymous) {
    menuItems.push($j('<a/>', {href: '/users/' + currentUser.id, text: I18n.t('txt.layout.profile')}));
  } else if (currentAccount.showChangePassword && !currentUser.isAnonymous) {
    menuItems.push($j('<a/>', {href: '/password', text: I18n.t('txt.layout.change_pwd')}));
  };

  if (currentUser.isAdmin) {
    menuItems.push('<a href="http://support.zendesk.com">help</a>');
  };

  if (currentUser.assumed) {
    menuItems.push('<a href="/users/revert">revert identity</a>');
  };

  if (currentUser.isAnonymous) {
    menuItems.push($j('<a/>', {href: '/login', text: I18n.t('txt.layout.login')}));

    if (currentAccount.isOpen && !currentAccount.hasRemoteAuthentication) {
      menuItems.push($j('<a/>', {href: '/registration', text: I18n.t('txt.layout.signup')}));
    };
  } else {
    var logoutUrl = currentAccount.secureUrlPrefix + '/access/logout';
    if (currentAccount.urlPrefix != currentAccount.secureUrlPrefix) {
      logoutUrl = logoutUrl + '?return_to=' + escape(currentAccount.urlPrefix + '/access/logout');
    };
    menuItems.push($j('<a/>', {href: logoutUrl, text: I18n.t('txt.layout.logout')}));
  };

  if (menuItems.length > 0) {
    topRight.append(menuItems.shift());
    menuItems.each(function(item) {
      topRight.append(' | ');
      topRight.append(item);
    });
  };
};

HeaderRenderer.hasUpdatedTabs = false;
HeaderRenderer.updateTabs = function() {
  var topMenu = $j('#top-menu > ul#green').first();
  if (!topMenu || HeaderRenderer.hasUpdatedTabs) {
    return;
  };

  HeaderRenderer.hasUpdatedTabs = true;

  if (currentUser.isAnonymous) {
    if (!currentAccount.isOpen) { // the account is not open so we remove all tabs
      topMenu.find('> li:not(.right)').remove();
    } else if (!currentAccount.hasRemoteAuthentication && !currentUser.hasEmail) { // open, but has remote auth
      topMenu.find('> li.tab_new a').attr('href', '/anonymous_requests/new');
    };
  };

  if (currentUser.accessibleForums) {
    var forumsTab = $j('<li class="main tab_forums"/>');
    forumsTab.append($j('<a/>', {'class': 'tab', href: '/forums', text: currentAccount.forumsTitle}));

    topMenu.find("> li.tab_home").after(forumsTab);
  };
  
  if (currentUser.isEndUser) {
    if (currentUser.canViewOrganization) { // we add the organization tab
      var previousTab = topMenu.find("> li:not(.right)").last();
      var organizationTab = $j('<li class="main tab_organization"/>');
      organizationTab.append($j('<a/>', {'class': 'tab', href: '/organization_requests', text: currentUser.organization.name.truncate(35)}));
      previousTab.after(organizationTab);
    };
  };

  topMenu.find('> li.first').removeClass('first');
  topMenu.find('> li.active').removeClass('active');
  topMenu.find('> li').first().addClass('first');
  topMenu.find('> li').addClass('main');
  var activeTab = topMenu.find('> li.tab_' + Zendesk.tab);
  activeTab.removeClass('main').addClass('active');
  activeTab.next().addClass('first');
};

if (currentUser) {
  HeaderRenderer.renderTopRight();
  HeaderRenderer.updateTabs();
};

$z.defModule('home', { // can define some stuff here for any home action to use
});

$z.defModule('home/index', {
  initialize: function() {
    if(currentUser.isAgent) {
      $j('#dashboard').ready(function () {
        $j('#dashboard').show();

        $j.get('/home/dashboard', function(data) {
          $j('#dashboard').html(data).show();
        });
      });
    }
  }
});

$z.defModule("monitor/children/show", {
  initialize: function(params) {
    $j("#subscription_payment_method_type").change(function() {
      if( 0 == $j("#subscription_payment_method_type").val() ) { 
        $j("#manual-discount-options").show();
      } else { 
        $j("#manual-discount-options").hide();
      }
    });
    $j("#subscription_payment_method_type").change();
  }
});

$z.defModule('people/users/edit', {
  initialize: function(user_id){
    $j('a#twitter.add_identity').click(this.add_identity("twitter", user_id));
    $j('a#email.add_identity').click(this.add_identity("email", user_id));
    $j('a#twitter_manually').click(this.add_identity("manual_twitter", user_id));

    document.observe('lightview:opened', function(event) {
      $j('input#email').focus();
    });
  },
  
  add_identity : function(identity_type, user_id){
    var self = this;
    return(function(event){
      Lightview.show({
        href: '/users/' + user_id + '/user_identities/new?type=' + identity_type,
        rel: 'ajax',
        options: {
          topclose: true,
          autosize: true,
          backgroundColor: '#999',
          ajax: {
            method: 'get', 
            onComplete: function() { 
              if ( identity_type == "email" ) {
                self.hijackAddEmailForm();
              } else if ( identity_type == "manual_twitter" ) {
                self.hijackAddTwitterForm();
              }
            }
          }
        } // options
      }); // Lightview.show
    })
  }, 

  hijackAddEmailForm : function() {
    $j('#add_email_form').submit(function() {
      $j.ajax({
        data: $j(this).serialize(), 
        type: $j(this).attr('method'), 
        url: $j(this).attr('action') + '?format=js', 
        beforeSend: function(request) {
          $j('#adding_email').show();
          Lightview.hide();
        }, 
        success: function(response) { 
          $j('#email_identities').append(response);
          new Effect.Highlight('email_identities', { duration: 2 });
          showFlash("");
        }, 
        error: function(request) {
          showFlash(request.responseText);
        }, 
        complete: function() { $j('#adding_email').hide(); }
      });
      return false;
    });
  }, 
  
  hijackAddTwitterForm : function() {
    $j('#add_manual_twitter_form').submit(function() {
      $j.ajax({
        data: $j(this).serialize(), 
        type: $j(this).attr('method'), 
        url: $j(this).attr('action') + '?format=js', 
        beforeSend: function(request) {
          $j('#adding_twitter').show();
          Lightview.hide();
        }, 
        success: function(response) { 
          $j('#twitter_identities').append(response);
          new Effect.Highlight('twitter_identities', { duration: 2 });
          showFlash("");
          $j('#add_twitter_identity').hide();
        }, 
        error: function(request) {
          showFlash(request.responseText);
        }, 
        complete: function() { 
          $j('#adding_twitter').hide();
        }
      });
      return false;
    });
  }

});

$z.defModule('people/users/merge', { 
  initialize: function(){
    /* This part is sadly never reached for lightboxes... */
  },  
  
  switch_to_password_form : function(){ 
    $("user_merge_email_form").hide(); 
    $("user_merge_password_form").show();
    $("user_merge_email_for_password_form").value = $F("user_merge_email");
    $("user_merge_password_email_display").innerHTML = $F("user_merge_email");
  },

  on_email_submit : function(){
    if (this.email_validate($F("user_merge_email"))) { 
      this.toggle_form('email');
      return false;
    } else {
      alert("Please enter a valid email address");
      return true;
    }    
  },
  
  on_password_submit : function(){
    if (!$F("user_merge_password").blank()) { 
      this.toggle_form('password');
      return false;
    } else {
      alert("Please enter a password");
      return true;
    }    
  },
  
  email_validate : function (address) {
    var reg = /^([A-Za-z0-9_\+\-\.])+(\+[0-9]+)?\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
    return reg.test(address);
  },
  
  password_does_not_match : function (text) {
    this.toggle_form('password');
    alert(text);
  },
  
  toggle_form : function (type) {
    $("user_merge_waiting_for_" + type).toggle();
    $("user_merge_submit_" + type).toggle();
  }
  
});
$z.defModule('people/users/show', {
  initialize: function() {
    $j('a.toggle-twitter-data').click(function() {
      $j(this).closest("p.user-twitter").next('.twitter-properties').slideToggle(50);
    });

    $j(".visibility-controls").click(function() {
      $j("a.toggle-twitter-data", this).toggle();
    });
  }
});
$z.defModule('rules/_personal_rules', {
  initialize: function(params) {
    var sortByHtml = function(a, b) {
      return ($j(a).html() < $j(b).html()) ? -1 : ($j(a).html() > $j(b).html()) ? 1 : 0;
    }

    $j("div#active-personal-rules_sort input.sort_asc").click(function(event) {
      var sortedRules = $j("ul#active-personal-rules-sort-list li.item.sortable").sort(function(a, b) {
        return sortByHtml(a, b);
      });
      $j("ul#active-personal-rules-sort-list li.item.sortable").remove();
      $j("ul#active-personal-rules-sort-list").prepend(sortedRules);
    });

    $j("div#active-personal-rules_sort input.sort_desc").click(function(event) {
      var sortedRules = $j("ul#active-personal-rules-sort-list li.item.sortable").sort(function(a, b) {
        return sortByHtml(b, a);
      });
      $j("ul#active-personal-rules-sort-list li.item.sortable").remove();
      $j("ul#active-personal-rules-sort-list").prepend(sortedRules);
    });

    $j("a.cancel-sorting").click(function(event) {
      Ordering.cancelOrdering("div#active-personal-rules");
    });
  }
});

$z.defModule('rules/_shared_rules', {
  initialize: function(params) {
    var sortByHtml = function(a, b) {
      return ($j(a).html() < $j(b).html()) ? -1 : ($j(a).html() > $j(b).html()) ? 1 : 0;
    }

    $j("div#active-shared-rules_sort input.sort_asc").click(function(event) {
      var sortedRules = $j("ul#active-shared-rules-sort-list li.item.sortable").sort(function(a, b) {
        return sortByHtml(a, b);
      });
      $j("ul#active-shared-rules-sort-list li.item.sortable").remove();
      $j("ul#active-shared-rules-sort-list").prepend(sortedRules);
    });

    $j("div#active-shared-rules_sort input.sort_desc").click(function(event) {
      var sortedRules = $j("ul#active-shared-rules-sort-list li.item.sortable").sort(function(a, b) {
        return sortByHtml(b, a);
      });
      $j("ul#active-shared-rules-sort-list li.item.sortable").remove();
      $j("ul#active-shared-rules-sort-list").prepend(sortedRules);
    });

    $j("a.cancel-sorting").click(function(event) {
      Ordering.cancelOrdering("div#active-shared-rules");
    });
  }
});

$z.defModule('rules/show', {
  initialize: function(){
    var selector = "textarea[id*='ticket_fields'], input[id*='ticket_fields']";
    var defaultColor = $j(selector).css("color");
    $j(selector).css("color", "gray");
    $j(selector).click(function() {
      $j(this).css("color", defaultColor);
    });
    $j(selector).blur(function() {
      if ($j(this).val() == "- No change -") {
        $j(this).css("color", "gray");
      }
    });
  }
});


$z.defModule('scheduled_csv_exports/_edit_form', {

  buttonLabels: [
    'Save schedule', 'Save and export', 'Test callback', 'Delete schedule'
  ],

  formIds: ['edit_form', 'edit_form', 'test_form', 'delete_form'],

  initialize: function() {
    var self = this;

    $j('#submit_type').change(function() {
      self.submitTypeChanged();
    });

    $j('#submit_button').click(function() {
      self.submit();
    });

    $j('#test_form').submit(function() {
      self.preserveUserInput();
    });

    $j('#edit_form').submit(function() {
      self.handleFireNow();
    });

    self.callbackClick();
    this.submitTypeChanged();
  },

  submitTypeChanged: function() {
    var index = $j('#submit_type').val();

    this.updateButtonText(index);
    this.updateButtonColor(index);
  },

  updateButtonText: function(index) {
    var label = this.buttonLabels[index];
    $j('#submit_button').text(label);
  },

  updateButtonColor: function(index) {
    var method = (index == 3) ? 'addClass' : 'removeClass';
    $j('#submit_button')[method]('negative');
  },

  submit: function() {
    var index = $j('#submit_type').val();
    var form  = $j('#' + this.formIds[index]);

    form.submit();
  },

  preserveUserInput: function() {
    $j('#test_scheduled_at').val($j('#scheduled_csv_export_hour').val());
    $j('#test_callback_url').val($j('#scheduled_csv_export_callback_url').val());
    $j('#test_auth_type').val($j('#edit_form').find('input:checked').val());
  },

  handleFireNow: function() {
    var index = $j('#submit_type').val();

    if (index == 1) {
      this.addFireNow();
    }
  },

  addFireNow: function() {
    var fireNow = $j('<input>', {
      "type":  "hidden",
      "value": "1",
      "name": "scheduled_csv_export[fire_after_save]"
    });

    $j('#edit_form').append(fireNow);
  },

  callbackClick: function() {
    $j('#callback_code').click(function(){
      $j('#callback_pre').slideDown(200);
      $j('#callback_code').toggle();
      $j('#callback_show_text').toggle();
    });

    $j('#callback_pre').click(function(){
      $j('#callback_pre').slideUp(200);
      $j('#callback_code').toggle();
      $j('#callback_show_text').toggle();
    });
  }

});

$z.defModule("shared/_help_container", {
  initialize: function() {

    $j("span.question-link").click(function() {
      $j(this).nextAll('.help-bubble').slideToggle(50);
    });
    
    $j("span.question-link img").hover(function(){
        $j(this).attr('src', '/images/question-hover.png');
      },
      function(){
      $j(this).attr('src', '/images/question.png');
    });
  }
 
});
zd.jsInitializers.push(["shared/_help_container",[]]);

$z.defModule('shared/_macro_list', {
  MAX_RESULTS: 20,
  initialize: function (macros, macro_search_enabled, id) {
    var self = this;
    self.root = $j(id);
    self.macro_search_enabled = macro_search_enabled;

    $j(document).bind('keydown', 'ctrl+m', self.toggle_macro_menu_with_key_combo()); // ctrl-m key combo opens macro menu; keypress has some bugs with current version of Hotkeys
    $j('form#ticket-chat').find('input,textarea,select').bind('keydown', 'ctrl+m', self.toggle_macro_menu_with_key_combo());

    $j(document).keydown(self.escape_close()); // escape closes macro menu even there's no macro search input

    if (macro_search_enabled) {
      self.search_results = self.root.find('ul.search_results');
      self.nested_macros =  self.root.find('ul.first-drop > li');
      self.root.data('cache', {'': {results: [], max_index: 0}});
      self.root.data('full_results', $j.map(macros, function(macro, index){return(index);}));
      self.macros = macros;
      self.root.data('macro_list', self.root.find('ul.search_results li.search_result'));
      self.add_apply_macro();
      self.root.data('input', $j(id + '_search'));
      self.root.find('ul.drop-list li ul.first-drop div.search img.clear').click(function (event) {self.clear();});
      self.root.find('ul.drop-list li ul.first-drop ul.search_results li.no_results div.explain p.try_again a.clear_search').click(function (event) {self.clear();});
      self.root.data('input').bind('keydown', self.escape_clear()).bind('keyup change', self.on_text_changed(id, self.root.data('cache'), self.root.data('full_results'), macros, self.root.data('macro_list'))); // keypress doesn't catch escape
      self.root.find('ul.drop-list > li').click(function(event){self.root.data('input').focus(); // focus to the search input when the user clicks on "Apple macro"
      });
      self.root.data('input').keydown(self.advance_on_key(38, -1)).keydown(self.advance_on_key(40, 1)).keydown(self.select_with_enter());
    }
  },
  select_with_enter: function () {
    var self = this;
    return(function (event) {
      var selection;
      if (event.keyCode === 13 && typeof(selection = self.search_results.data('selection')) !== 'undefined') {
        event.preventDefault();
        event.stopPropagation();
        self.root.data('macro_list').eq(selection).click();
      }
    });
  },
  advance_on_key: function (key_code, steps) {
    var self = this;
    return(function (event) {
      if (event.keyCode === key_code) {
        event.stopPropagation();
        event.preventDefault();
        self.advance_selection(steps);
      }
    });
  },
  advance_selection: function (steps) {
    var self = this;
    var search_term = (typeof(self.root.data('search_term')) !== 'undefined') ? self.root.data('search_term') : '';
    var cache = self.root.data('cache')[search_term];

    if (cache.results.length > 0) {
      steps %= cache.max_index;
      var selection_index = ((typeof (self.search_results.data('selection_index')) === 'undefined') ? 0 : self.search_results.data('selection_index') + steps + cache.max_index) % cache.max_index;
      self.select(selection_index);
    }
  },
  select: function (selection_index) {
    var self = this;
    var previous_selection = self.search_results.data('selection');
    var search_term = (typeof(self.root.data('search_term')) !== 'undefined') ? self.root.data('search_term') : '';
    var cached_results = self.root.data('cache')[search_term].results;

    if (typeof(previous_selection) !== 'undefined') {
      self.root.data('macro_list').eq(previous_selection).removeClass('selected');
    }
    if (typeof (selection_index) === 'number' && selection_index >= 0) {
      self.search_results.data('selection_index', selection_index);
      self.search_results.data('selection', cached_results[selection_index]);
      self.root.data('macro_list').eq(cached_results[selection_index]).addClass('selected');
    } else {
      self.search_results.data('selection', null);
    }
  },
  toggle_macro_menu_with_key_combo: function () {
    var self = this;
    var menu = self.root.find('ul.first-drop');

    return(function (event) {
      event.stopPropagation();
      event.preventDefault(); // if the browser uses ctrl-m, tell it not to - we're overriding it
      if (menu.css('display') === 'none') {
        self.open_macro_menu();
      } else {
        self.close_macro_menu();
      }
    });
  },
  close_macro_menu: function () {
    var self = this;
    self.root.find('ul.first-drop').hide();
    if (self.macro_search_enabled) { self.clear(); }
  },
  open_macro_menu: function () {
    var self = this;
    self.root.find('ul.first-drop').show();
    if (self.macro_search_enabled) { self.root.data('input').focus(); }
  },
  clear: function () {
    var self = this;

    self.root.data('input').val('');
    self.root.data('input').change();
  },
  escape_close: function(){
    var self = this;
    return(function(event){
      if(event.keyCode === 27) /* escape key pressed */ { self.close_macro_menu(); }
    });
  },
  escape_clear: function(){
    var self = this;
    return(function(event){
      if(event.keyCode === 27){ // escape key pressed
        event.preventDefault();
        if($j.trim($j(this).val()) !== ''){ // close the menu
          event.stopPropagation(); // don't let the event bubble up to trigger the close
          self.clear(); // clear the text
        }
      }
    });
  },
  on_text_changed: function(id, cache, full_results, macros, macro_list) {
    // This code is EXTREMELY optimized. Please be careful if you change it!
    var self = this;

    var no_results = self.root.find('ul.search_results li.no_results');
    var display_term = no_results.find('span.search_term');
    var search_img = self.root.find('ul.drop-list li ul.first-drop div.search img.search');
    var clear_img = self.root.find('ul.drop-list li ul.first-drop div.search img.clear');

    var highlight = function (index, regex) {
      return(macros[index].label.replace(regex, '<span class="highlight">$1</span>'));
    };
    var update_macro = function (index, new_html) { macro_list.eq(index).find(' > a').html(new_html); };
    return (function (event) {
      var previous_search_term = (typeof(self.root.data('search_term')) !== 'undefined') ? self.root.data('search_term') : '';
      var previous_cache = cache[previous_search_term];
      var search_term = $j.trim($j(this).val());
      self.root.data('search_term', search_term);

      var cachify = function(superset, hide_previous_results) {
        if (typeof(hide_previous_results) === 'undefined') { hide_previous_results = false; }
        var regex_escaped_search_term = $j.ui.autocomplete.escapeRegex(search_term);

        var regex = RegExp(regex_escaped_search_term, 'i');
        var highlight_regex = RegExp('(' + regex_escaped_search_term + ')', 'gi');
        var highlighted;
        var superset_index = 0;
        var subset = [];
        var highlights = [];
        if (hide_previous_results) {
          for (var i = 0; i < previous_cache.max_index; i++) { macro_list.eq(previous_cache.results[i]).hide(); }
          for (; subset.length < self.MAX_RESULTS && superset_index < superset.length; superset_index++) {
            if (macros[superset[superset_index]].label !== (highlighted = highlight(superset[superset_index], highlight_regex))) { // string was changed, because there were a substitution because it contained the query
              subset.push(superset[superset_index]);
              highlights.push(highlighted);
              update_macro(superset[superset_index], highlighted);
              macro_list.eq(superset[superset_index]).show();
            }
          }
        } else {
          for (; subset.length < self.MAX_RESULTS && superset_index < superset.length; superset_index++) {
            if (macros[superset[superset_index]].label === (highlighted = highlight(superset[superset_index], highlight_regex))) { // string was unchanged, because there were no substitutions because it didn't contain the query
              macro_list.eq(superset[superset_index]).hide();
            } else {
              subset.push(superset[superset_index]);
              highlights.push(highlighted);
              update_macro(superset[superset_index], highlighted);
              macro_list.eq(superset[superset_index]).show();
            }
          }
          for (; superset[superset_index] < previous_cache.results[previous_cache.max_index] ; superset_index++) {
            macro_list.eq(superset[superset_index]).hide(); // hiding everything that could possibly be visible
            if (regex.test(macros[superset[superset_index]].label)) {
              subset.push(superset[superset_index]);
            }
          }
        }
        for (; superset_index < superset.length; superset_index++) { // todo: take out this entire for loop, and change the code above to start looking at the full result set once it's out of superset results = big efficiency boost
          if (regex.test(macros[superset[superset_index]].label)) {
            subset.push(superset[superset_index]);
          }
        }
        cache[search_term] = {max_index: Math.min.apply(Math, [subset.length, self.MAX_RESULTS]), regex: regex, results: subset, highlights: highlights};
      };

      if (search_term !== previous_search_term) {
        if (search_term.length === 0) {
          clear_img.hide();
          search_img.show();
          self.search_results.hide();
          self.nested_macros.show();
          for (var i = 0; i < previous_cache.max_index; i++) { macro_list.eq(previous_cache.results[i]).hide(); }
        } else {
          if (previous_search_term.length === 0) {
            search_img.hide();
            clear_img.show();
            self.nested_macros.hide();
            self.search_results.show();
          }
          var previous_index = 0, current_index = 0;
          if (previous_search_term.length > 0 && search_term.length > previous_search_term.length && previous_cache.regex.test(search_term)) { // drill down into a subset of what's already selected
            if (typeof(cache[search_term]) === 'object' && cache[search_term].max_index > 0) {
              if (previous_cache.results[previous_cache.max_index - 1] < cache[search_term].results[cache[search_term].max_index - 1]) {
                for (; previous_index < previous_cache.max_index ; previous_index++) {
                  if (previous_cache.results[previous_index] < cache[search_term].results[current_index]) {
                    macro_list.eq(previous_cache.results[previous_index]).hide();
                  } else {
                    update_macro(cache[search_term].results[current_index], cache[search_term].highlights[current_index]);
                    current_index++;
                  }
                }
                for (; current_index < cache[search_term].max_index ; current_index++) {
                  update_macro(cache[search_term].results[current_index], cache[search_term].highlights[current_index]);
                  macro_list.eq(cache[search_term].results[current_index]).show();
                }
              } else {
                for (; cache[search_term].results[current_index] <= previous_cache.results[previous_cache.max_index - 1]; current_index++) {
                  update_macro(cache[search_term].results[current_index], cache[search_term].highlights[current_index]);
                  for (; previous_cache.results[previous_index] < cache[search_term].results[current_index]; previous_index++) {
                    macro_list.eq(previous_cache.results[previous_index]).hide();
                  }
                  if (previous_cache.results[previous_index] === cache[search_term].results[current_index]) {
                    previous_index++;
                  }
                }
                for (; previous_index < previous_cache.max_index ; previous_index++) {
                  macro_list.eq(previous_cache.results[previous_index]).hide();
                }
              }
            } else {
              cachify(previous_cache.results, false);
            }
          } else {
            if (typeof(cache[search_term]) === 'object') {
              for (previous_index = 0, current_index = 0; previous_index < previous_cache.max_index && current_index < cache[search_term].max_index;) {
                if (previous_cache.results[previous_index] < cache[search_term].results[current_index]) {
                  macro_list.eq(previous_cache.results[previous_index]).hide();
                  previous_index++;
                } else if (previous_cache.results[previous_index] > cache[search_term].results[current_index]) {
                  update_macro(cache[search_term].results[current_index], cache[search_term].highlights[current_index]);
                  macro_list.eq(cache[search_term].results[current_index]).show();
                  current_index++;
                }
                else {
                  update_macro(cache[search_term].results[current_index], cache[search_term].highlights[current_index]);
                  current_index++;
                  previous_index++;
                }
              }
              if (previous_index === previous_cache.max_index) {
                for (; current_index < cache[search_term].max_index; current_index++) {
                  update_macro(cache[search_term].results[current_index], cache[search_term].highlights[current_index]);
                  macro_list.eq(cache[search_term].results[current_index]).show();
                }
              }
              if (current_index === cache[search_term].max_index) {
                for (; previous_index < previous_cache.max_index; previous_index++) {
                  macro_list.eq(previous_cache.results[previous_index]).hide();
                }
              }
            } else {
              cachify(full_results, true);
            }
          }
          if (cache[search_term].results.length > 0) {// indicate that there were no matches
            self.select(0);
            if (previous_cache.results.length === 0) {
              no_results.hide();
            }
          } else {
            self.select();
            display_term.html(search_term);
            if (previous_cache.results.length > 0 || previous_search_term.length === 0) {
              no_results.show();
            }
          }
        }
      }
    });
  },
  add_apply_macro: function(index) {
    var self = this;

    self.root.find('ul.search_results li.search_result').each(function (index, element) {
      var case_id = self.macros[index].value;
      if (Number(case_id) >= 0) {
        $j(element).click(function (event) {
          $j.get('/rules/apply_macro/' + case_id,
            {ticket_id: typeof(ticket_id) === 'undefined' ? '0' : ticket_id},
            function (html) {
              $j('body').append(html);
              $j('textarea#comment_value').focus();
          });

          $j(this).fadeOut('fast').fadeIn('fast', function () {
            self.clear();
            self.root.find('ul.drop-list li ul.first-drop').hide();
          });
        });
      }
    });
  }
});
$z.defModule("shared/_tickets_table", {
  initialize: function() {
    $j("input.tickets_to_bulk_update").enableCheckboxRangeSelection();    
  }
 
});


(function($) {
  $.fn.enableCheckboxRangeSelection = function() {
    var lastCheckbox = null;
    var $spec = this;
    $spec.unbind("click.checkboxrange");
    $spec.bind("click.checkboxrange", function(e) {
      if (lastCheckbox != null && (e.shiftKey || e.metaKey)) {
        $spec.slice(
          Math.min($spec.index(lastCheckbox), $spec.index(e.target)),
          Math.max($spec.index(lastCheckbox), $spec.index(e.target)) + 1
        ).attr({checked: e.target.checked ? "checked" : ""});
      }
      lastCheckbox = e.target;
    });
  };
})(jQuery);


zd.jsInitializers.push(["shared/_tickets_table",[]]);
$z.defModule('tabindex', {
  addtabindexes: function(){ // easily set the order of tab navigation in a single call
    var args = Array.prototype.slice.call(arguments); // get an array from the arguments object
    var tabindex = args.slice(-1)[0];
    if(typeof(tabindex) === 'number'){
      args.pop();
    } else {
      tabindex = 1;
    }
    $j(args).each(function(index, selector){
      $j(selector).each(function(index, element){
        $j(element).attr({tabindex: tabindex++});
      });
    });
  }
});
$z.defModule("ticket_fields/_list_for_index", {
  initialize: function(params) {
    $j("a.cancel-sorting").click(function(event) {
      Ordering.cancelOrdering("div#fields");
    });
  }
});
$z.defModule('tickets/new', {
  initialize: function(){
    $j('input#ticket_requester_name').focus(); // focus on the requester field on page load

    // navigate in the right order
    $z('tabindex').addtabindexes(
      'input#ticket_requester_name',
      '#edit_cc input',
      'form#ticket-chat div.selects div.select > input[readonly != readonly][attribute_name != additional_tags],form#ticket-chat div.selects div.select > select[readonly != readonly]',
      'textarea#comment_value',
      '#ticket_tags', // tags input, before autocomplete changes it
      '.selects .multi_value_field .search_field_item input', // tags input, after autocomplete changes it
      'select#submit_type',
      'input#submit_type',
      'input#submit-button'
    );

    $z('tickets').addSubmitBindings(); // adds ctrl+s ticket submission, but won't work with current version of jQuery Hotkeys
  }
});
$z.defModule('tickets/show', {
  initialize: function(){
    $j('textarea#comment_value').focus(); // focus on the requester field on page load

    // navigate in the right order
    $z('tabindex').addtabindexes(
      '#edit_cc input',
      'form#ticket-chat div.selects div.select > input[readonly != readonly][attribute_name != additional_tags],form#ticket-chat div.selects div.select > select[readonly != readonly]',
      '#ticket_tags', // tags input, before autocomplete changes it
      '.selects .multi_value_field .search_field_item input', // tags input, after autocomplete changes it
      'textarea#comment_value',
      'input#comment_is_public',
      'select#submit_type',
      'input#submit_type',
      'input#submit-button'
    );

    $z('tickets').addSubmitBindings(); // adds ctrl+s ticket submission, but won't work with current version of jQuery Hotkeys

    $j(".visibility-controls").click(function() {
      $j("a.toggle-twitter-data", this).toggle();
    });

    $j('a.toggle-twitter-data').click(function() {
      $j('.twitter-properties').toggle();
    });
  },
  
  setupCommentCharacterCounter : function(offset) {
    $j('div#comment_type').prepend('<div id="charcounter"><div title="Remaining Character Count: Characters past this limit will be truncated on Twitter but appear in their entirety in Zendesk. A shortened link to this ticket will be appended to the tweet, depending on the setup of your zendesk."></div></div>');
    $z('tickets/show').commentCharacterCounter(offset);
    $z('tickets/show').toggle_comment_character_counter()
    $j('div#charcounter > div').html(140-offset);
  },
  
  commentCharacterCounter : function(offset) {
    $j('textarea#comment_value').keyup(function() {
      count = 140-offset-$j('textarea#comment_value').val().length;
      $j('div#charcounter > div').html(count);
    });
  },  
  
  toggle_comment_type_for_ticket : function() {
    if ($('comment_type')) {
      $('comment_type').className = ($('comment_type').className == 'say public') ? 'say private' : 'say public';
      if ($('channel_comment')) {
        $('channel_comment').style.display = ($('comment_type').className == 'say public') ? 'inline' : 'none';
        $z('tickets/show').toggle_comment_character_counter();
      }
    }
  },

  toggle_comment_character_counter : function() {
    if ($j('div#charcounter')) {
      if ($j('comment_type') && $('comment_channel_back').checked && $('comment_is_public').checked) {
        $j('div#charcounter').show();
      } else {
        $j('div#charcounter').hide();
      }
    }
  },
  
  toggle_comment_channel_back : function(requester_has_email) {
    if ($('comment_type') && !requester_has_email) {
      if (!$('comment_channel_back').checked && $('comment_is_public').checked && !$F("comment_value").blank()) {
        alert('Warning: The requester does not have an email associated. If you disable tweet back, the requester will not be notified of your update.')
      }
    }
  }
  
});

$z.defModule('tickets', {
  addSubmitBindings: function(){
    function submit(event){
      event.preventDefault();
      $j('input#submit-button').click();
    }

    $j('form#ticket-chat').find('input,textarea,select').bind('keydown', 'ctrl+s', submit);
    $j(document).bind('keydown', 'ctrl+s', submit);
  }
});
if (Twitter == undefined) {
  var Twitter = {};
  Twitter.tweetsPerPage = 30;
  Twitter.pollingFrequency = 10000;
}

if (typeof(TwitterMultiRequest) === 'undefined') {
  function TwitterMultiRequest() {};

  TwitterMultiRequest.prototype = {
    tweetsPerPage: 30,

    fireRequests: function(query, mthId) {
      this.reset();

      this.search(query);
      this.retweetedBy(mthId);
    },

    // Reset the twitter object
    reset: function() {
      this.metaData    = null;
      this.searchData  = null;
      this.retweetData = null;
    },



    // AJAX

    // Search Twitter
    search: function(query) {
      var self = this;

      jQuery.ajax({
        url:      'https://search.twitter.com/search.json',
        data:     { 'rpp': this.tweetsPerPage, 'q': query },
        type:     'GET',
        dataType: 'jsonp',
        success:  function(data) { self.getMetaData(data); }
      });
    },

    // Get metaData from Zendesk
    getMetaData: function(data) {
      var self = this;
      this.searchData = data;

      var ids = [];
      jQuery.each(data.results, function(index, item) {
        ids.push(item.id);
      });

      jQuery.ajax({
        url:  '/twitter/tickets/exist.json',
        data: { 'q': ids.join(',') },
        type: 'GET',
        success:  function(data) { self.metaDataCallback(data); }
      });
    },

    // Get retweets for a specific user
    retweetedBy: function(mthId) {
      var self = this;

      jQuery.ajax({
        url:  '/twitter/api/retweeted_by_me.json',
        data: { 'mth_id': mthId },
        type: 'GET',
        success: function(data) { self.retweetedByCallback(data); }
      });
    },



    // Callbacks
    metaDataCallback: function(data) {
      this.metaData = data;
      this.render();
    },

    retweetedByCallback: function(data) {
      this.retweetData = data;
      this.render();
    },



    // Synchronization Gate.
    // Gets called at the end of all the AJAX calls, but does not do anything
    // until all of them are complete.
    render: function() {
      if (this.searchData && this.metaData && this.retweetData) {
        var renderer = new TwitterSearchRenderer(this.searchData, this.metaData, this.retweetData);
        renderer.render();

        this.reset();
      }
    }
  };
}

if (typeof(TwitterSearchRenderer) === 'undefined') {
  function TwitterSearchRenderer(searchData, metaData, retweetData) {
    this.searchData  = searchData;
    this.metaData    = metaData;
    this.retweetData = retweetData;
  };

  TwitterSearchRenderer.prototype = {
    render: function() {
      console.log('I didnt die!');
    }
  };
}

$z.defModule('twitter/search/index', {

  initialize: function(loading_image, initial_query, mth) {
    // var multi = new TwitterMultiRequest();
    // display loading image
    // multi.fireRequests(initial_query, mth);

    var self = this;
    self.loading_image = loading_image;
    self.shouldCheckForUpdates = false;

    Twitter.search = function(query, page, mth_id) {
      self.resetUnreadTweetCounter();
      self.mth_id = mth_id;
      self.currentQuery = query;
      self.removeTemporaryElements(page)
      self.showLoading();
      self.downloadTweets(query, page);
    };

    // Ajax History
    jQuery.address.change(function(event) {
      if(event.value == "/") { 
        Twitter.search(initial_query, 1, mth);
      } else { 
        var queryArray = event.value.split("&"); 
        var queryString = queryArray[0].substr(1);
        var mthId = queryArray[1];

        Twitter.search(queryString, 1, mthId);
      } 
    });

    // Begin polling.
    window.setInterval(function() { self.checkForUpdates(); }, Twitter.pollingFrequency);
  },

  showLoading: function() {
    var html = '<p class="temp">Downloading tweets... ' + this.loading_image + '</p>';
    jQuery('#twitter_search_results').append(html);
  },

  checkForUpdates: function() {
    var self = this;
    if(self.currentQuery == null || (self.shouldCheckForUpdates == false)) { return; }
      
    var url    = 'https://search.twitter.com/search.json';
    var params = '?rpp=' + Twitter.tweetsPerPage + '&page=&q=' + self.currentQuery;

    jQuery.ajax({
      url: url + params,
      type: 'GET',
      dataType: 'jsonp',
      success: function(data) { self.checkForUpdatesCallback(data); }
    }); 
  },

  checkForUpdatesCallback: function(data) { 
    var self = this;
    var newTweetCount = 0;
    jQuery.each(data.results, function(index, value) { 
      if(value.id > self.mostRecentTweet) { 
        newTweetCount += 1;
      }
    });

    if(newTweetCount > self.unreadTweetCount) { 
      self.unreadTweetCount = newTweetCount;
      self.displayNewTweetsMessage();
    }
  },

  displayNewTweetsMessage: function() {
    var self = this;
    // Disable polling when we've exceeded the number of results returned on a single page.
    if(self.unreadTweetCount >= Twitter.tweetsPerPage) { self.shouldCheckForUpdates = false; }
    
    var noticeContainer = jQuery(document.createElement('div'));
    if(self.unreadTweetCount > 0 && self.unreadTweetCount < Twitter.tweetsPerPage) {
      noticeContainer.append(self.unreadTweetCount + " new tweets.");
      noticeContainer.append(self.linkToCurrentSearch());
      jQuery('#twitter_new_result_count').html(noticeContainer);
    }
    else if(self.unreadTweetCount >= Twitter.tweetsPerPage) {
      noticeContainer.append("More than " + Twitter.tweetsPerPage + " new tweets.");
      noticeContainer.append(self.linkToCurrentSearch());
      jQuery('#twitter_new_result_count').html(noticeContainer);
    }

  },

  cacheBuster: function() { 
    return Math.floor(
      Math.random() * Math.pow(2, 32)
    );
  },

  linkToCurrentSearch: function() { 
    var self = this;
    return "&nbsp;<a rel='address:" + 
      self.currentQuery + 
      "&mth_id" + 
      "&" + self.mostRecentTweet + 
      "&" + self.cacheBuster() + "'>(Refresh)</a>"
  },

  resetUnreadTweetCounter: function() { 
    var self = this;
    self.currentQuery = null;
    self.unreadTweetCount = 0;
    jQuery('#twitter_new_result_count').html('');
  },

  markAsMostRecentTweet: function(tweet) { 
    var self = this;
    self.mostRecentTweet = tweet.id;
  },

  downloadTweets: function(query, page) {
    var self   = this;
    var url    = 'https://search.twitter.com/search.json';
    var params = '?rpp=30&page=' + page + '&q=' + query;

    jQuery.ajax({
      url: url + params,
      type: 'GET',
      dataType: 'jsonp',
      success: function(data) { self.checkTwicketized(data, page); }
    });
  },

  checkTwicketized: function(data, page) {
    var self = this;

    if (data && data.results) {
      var ids = [];

      jQuery.each(data.results, function(i, result) {
        ids.push(result.id);
      });

      var query = '?q=' + ids.join(',');
      var url   = '/twitter/tickets/exist.json';

      jQuery.ajax({
        url: url + query,
        type: 'GET',
        success: function(zdData) { self.checkTwicketizedCallback(data, zdData, page) }
      });
    }
  },

  checkTwicketizedCallback: function(data, zdData, page) {
    var self = this;
    if (zdData && zdData.tickets) {

      var masterObjects = [];
      jQuery.each(data.results, function(i, result) {

        jQuery.each(zdData.tickets, function(j, zd_data_object) {
          if (zd_data_object.status_id == result.id) {
            result.twicketized = true;
            result.ticket_id = zd_data_object.ticket_id;
          }
        });

        masterObjects.push(result);
      });

      self.shouldCheckForUpdates = true;
      self.renderTweets(masterObjects, page, data.query);
    }
  },

  renderTweets: function(masterObjects, page, query) {
    var self = this;

    page++;

    self.removeTemporaryElements(page);
    self.markAsMostRecentTweet(masterObjects[0]);

    jQuery.each(masterObjects, function(i, obj) {
      tweet = jQuery(self.buildTweet(obj));

      if (!obj.twicketized) {
        self.attachEventsTo(tweet, obj.id);
      }

      jQuery('#twitter_search_results').append(tweet);
    });

    more_link = jQuery('<a class="view_more temp" href="#">Show more results</a>').click(function(event) {
		event.preventDefault();
      Twitter.search(query, page);
    });
    jQuery('#twitter_search_results').append(more_link);
  },

  buildTweet: function(obj) {
    var string = '<div id="tweet_' + obj.id + '" class="tweet clearfix">' +
    '  <img src="' + obj.profile_image_url + '" class="profile_image" />' +
    '  <div class="tweet_container">'+
    '    <div class="tweet_content">' +
    '      <a href="#" class="faux_checkbox">Select tweet</a>' +
    '      <h4>' + obj.from_user +
    '        <span class="meta">' + this.tweetedAt(obj.created_at) + '</span>' +
    '      </h4>' +
    '      <p>' + obj.text + '</p>' +
    '    </div>';

    if (obj.twicketized === true) {
      string = string + this.buildTwicketizedDiv(obj.ticket_id);
    } else {
      string = string + '<div class="tweet_actions">' +
      '  <a class="convert_to_ticket">Convert to ticket</a>' +
      '  <a class="retweet">Re-tweet</a>' +
      '  <a class="follow">Follow @' + obj.from_user + '</a>' +
      '  <a class="quick_reply">Quick reply</a>' +
      '</div>';
    }

    string = string + '</div></div>';

    return string;
  },

  tweetedAt: function(dateString) {
    var date = new Date(dateString);

    return [date.getFullYear(), date.getMonth(), date.getDate()].join('.');
  },

  buildTwicketizedDiv: function(ticketId) {
    return '<div class="tweet_converted">' +
    '  <span>Converted to Ticket</span>' +
    '  <a href="/tickets/' + ticketId + '" target="_blank">' +
    '    Ticket #' + ticketId +
    '  </a>' +
    '</div>';
  },

  attachEventsTo : function(element, tweetId){
    var self = this;

    element.find('a.convert_to_ticket').first().click(function() {
      self.createTicket(self.mth_id, tweetId);
    });

    element.find('a.retweet').first().click(function() {
      self.retweet(tweetId);
    });
  },

  createTicket: function(mth_id, status_id) {
    var self = this;

    var tweet = jQuery('#tweet_' + status_id);
    tweet.find('a.convert_to_ticket').after(self.loading_image);

    jQuery.ajax({
      url: '/twitter/tickets.json',
      type: 'POST',
      data: { 'mth_id': mth_id, 'status_id': status_id },
      success: function(data) {
        if (data.location) {
          var ticketId = data.location.replace('/tickets/', '');
          self.createTicketCallback(status_id, ticketId);
        }
      },
      error: function() {
        var controls = jQuery('#controls_' + status_id);
        controls.html('<span>error creating ticket</span>')
      }
    });
  },

  createTicketCallback: function(status_id, ticketId) {
    var tweet = jQuery('#tweet_' + status_id);
    tweet.find('.tweet_actions').remove();

    twicketizedDiv = this.buildTwicketizedDiv(ticketId);
    tweet.find('.tweet_content').after(twicketizedDiv);
  },

  retweet: function(tweetId) {
    var self = this;

    jQuery.ajax({
      url: '/twitter/api/retweet',
      type: 'POST',
      data: { 'mth_id':self.mth_id, 'status_id':tweetId },
      success: function(data) {
        self.retweetCallback(data, tweetId);
      }
    });
  },

  retweetCallback: function(data, tweetId) {
    var tweet = jQuery('#tweet_' + tweetId);
    tweet.find('.retweet').replaceWith('<span>Retweeted by @mth</span>');
  },

  removeTemporaryElements: function(page) {
    if (page == 1) {
      jQuery('#twitter_search_results').empty();
    } else {
      jQuery('#twitter_search_results .temp').remove();
    }
  }

});
