(function($) {
  var cache = [];
  // Arguments are image paths relative to the current page.
  $.preLoadImages = function() {
    var args_len = arguments.length;
    for (var i = args_len; i--;) {
      var cacheImage = document.createElement('img');
      cacheImage.src = arguments[i];
      cache.push(cacheImage);
    }
  }
})(jQuery)

function replaceButtonImage(elem, search, replace) {
  src = $(elem).attr("src").replace(/_hover/g, "").replace(/_down/g, "");
  src = src.replace(search, replace);
  $(elem).attr("src", src);
}

function preloadButtonImage(elem, search, replace) {
  src = $(elem).attr("src").replace(/_hover/g, "").replace(/_down/g, "");
  src = src.replace(search, replace);
  $.preLoadImages(src);
}

function paginatorPrevNext(items, offset) {
  var current, selected = items.filter('.selected-option');
  var index = items.index(selected) + offset;
  
  if (index < 0) {
    return;
  }
  
  current = items.get(index);
  
  if (typeof current === 'undefined') {
    return;
  }
  
  $(current).click();
}

$(function() {
  // Element like a select box - for links 
  $("div.select-box").removeClass('nojs').bind('mousedownoutside', function(e) {
    $(this).find("div.displayed-option").css("outline", '0');
    $(this).find('div.select-arrow').removeClass('border-bottom');
    $(this).find('ul').hide().find("li.hover").removeClass("hover").click();
  }).each(function(i) {
    fixPseudoSelectZIndex($(this), i);
  }).find('div.select-arrow').mousedown(function() {
    var ul = $(this).siblings("div.select-options").find("ul").toggle();
    
    if (ul.is(":hidden")) {
      $(this).removeClass('border-bottom');
      $(this).siblings(".select-options").find("li.hover").removeClass("hover").click();
    } else {
      $(this).addClass('border-bottom');
      $(this).siblings(".select-options").find("ul").scrollTo($(this).siblings(".select-options").find(".hover, .selected-option"));
    }
  }).end().find('div.displayed-option').mousedown(function() {
    $(this).siblings("ul").toggle();
    $(this).siblings("ul").scrollTo($(this).siblings("ul").find(".hover, .selected-option"));
    $(this).siblings(".select-options").find("li.hover").removeClass("hover").click();
  });
  
  $("div.displayed-option a").click(function() {
    return false;
  });
  
  // Pseudo-select box for forms
  $("select.pseudo-select").each(function(i) {
    if ($.browser.msie && parseInt($.browser.version) < 7) {
      $(this).removeClass('nojs-hidden');
      return; // Don't apply these to IE6
    }
    
    var id = $(this).attr('id');
    var div = $(this).siblings("div.select-box");
    
    div.disableTextSelect();
    ul = fixPseudoSelectZIndex(div, i);
    
    // Add input to store the current value
    var defaultValue = parseOptionValue(div.find("li.selected-option"));
    div.removeClass('hidden').append('<input type="hidden" id="' + id + '" name="' + $(this).attr('name') + '" value="' + defaultValue + '" />');
    
    bindOptionEvents(id, div, ul);
    
    $(this).remove();
  });
  
  // Keybindings for pseudo-select boxes.
  $(document).keydown(function(e) {
    var ul = $("div.select-options ul:visible");
    
    if (ul.length > 0) {
      if (e.which == 27) { // ESC
        ul.parents("div.select-box").find("div.select-arrow").mousedown();
      } else if (e.which == 13) { // Enter
        ul.find(".hover").click();
        return false;
      } else if (e.which == 40 || e.which == 83) { // Down
        pseudoSelectNav(ul, 1);
        return false;
      } else if (e.which == 38 || e.which == 87) { // Up
        pseudoSelectNav(ul, -1);
        return false;
      } else if (e.which == 36) { // Home
        pseudoSelectNav(ul, null, ul.children(":first"));
        return false;
      } else if (e.which == 35) { // End
        pseudoSelectNav(ul, null, ul.children(":last"));
        return false;
      } else if (e.which == 34) { // Page Down
        pseudoSelectNav(ul, 5);
        return false;
      } else if (e.which == 33) { // Page Up
        pseudoSelectNav(ul, -5);
        return false;
      }
    }
  });
  
  var key_stream = "";
  var stream_timeout;
  $(document).keypress(function(e) {
    var ul = $("div.select-options ul:visible");
    
    if (ul.length > 0) {
      key_stream += String.fromCharCode(e.which);
      clearTimeout(stream_timeout);
      switchPseudoSelectOption(ul, key_stream);
      stream_timeout = setTimeout(function() {
        key_stream = "";
      }, 500);
      
      if (e.which == 32) {
        return false; // Don't scroll when spacebar is pressed.
      }
    }
  });
  
  // Enable reset buttons to work with the psuedo select boxes.
  $("input[type='reset']").click(function() {
    var li = $("div.select-box").find("li.default-option");
    
    if (li.length == 0) {
      li = $("div.select-box").find("li:first");
    }
    
    li.click();
  });
  
  // Select Paginators
  $("input[id^='_form-_paginator-']").change(function() {
    window.location.href = $(this).val();
  });
  
  $("div.paginator-arrow").click(function() {
    var ul = $(this).siblings("div.paginator-select").find("div.select-box ul");
    paginatorPrevNext(ul.find('li'), $(this).children("div.paginator-arrow-left").length > 0 ? -1 : 1);
  });
  
  $("#nav, div[id^='banner-icon']").pngFix();
  $("div#halloween_pumpkin_web, div#xmas_present").pngFix({andSelf: true});
  $("div#outer-wrapper, div#search, div#search-anime, div#search-hentai").pngFix({onlySelf: true});
  
  // Button hovers and presses - Preload first  
  $(".button img, img.button, input[type=image].button").each(function(i) {
    $.preLoadImages($(this).attr('src'));
    preloadButtonImage(this, ".png", "_hover.png");
    // preloadButtonImage(this, ".png", "_down.png");
  });
  
  // Then bind
  $(".button img, img.button, input[type=image].button").hover(function() {
    replaceButtonImage(this, ".png", "_hover.png");
  }, function() {
    replaceButtonImage(this, "_hover.png", ".png");
  })/*.mousedown(function() {
    replaceButtonImage(this, ".png", "_down.png");
  }).mouseup(function() {
    replaceButtonImage(this, "_down.png", ".png");
  })*/;
  
  
  if ($.browser.msie) {
    // Don't touch the opacity in MSIE or else it'll trigger the black alpha PNG bug 
    $("#nav > a").hover(function(){
      $(this).find("img").stop().animate({top: -7}, 400);
    }, function(){
      $(this).find("img").stop().animate({top: 0}, 400);
    });
  } else {
    $("#nav > a").hover(function(){
      $(this).find("img").stop().animate({opacity: 0.80, top: -7}, 400);
    }, function(){
      $(this).find("img").stop().animate({opacity: 1.0, top: 0}, 400);
    });
  }
  
  $("ul#banner-rotator").cycle({
    delay: 6000,
    timeout: 6000,
    pause: true,
    pager: "#banner-triggers",
    pagerAnchorBuilder: function(i, slide) {
      var id = "#banner-trigger-" + i;
      $(id).css('cursor', 'pointer');
      return id;
    },
    updateActivePagerLink: function(pager, currSlide, clsName) {
      $(pager).children().each(function() {
        if ($(this).attr('id').split('-')[2] == currSlide) {
          $(this).find("img").attr('src', 'http://static.anifreak.com/plus2010/images/ball_blue.png');
        } else {
          $(this).find("img").attr('src', 'http://static.anifreak.com/plus2010/images/ball_grey.png');
        }
      });
    }
  });
  
  $("#banner-triggers").show();
  
  $("div.cp-menu").removeClass('nojs').hoverIntent(function() {
    $(this).children("ul").show();
  }, function() {
    $(this).children("ul").hide();
  });
  
  $("input#login_username").focusin(function() {
    if ($(this).val() == "Username") $(this).val("");
  }).focusout(function() {
    if ($(this).val() == "") $(this).val("Username");
  });
  
  $("input#login_password").focusin(function() {
    if ($(this).val() == "Password") $(this).val("");
  }).focusout(function() {
    if ($(this).val() == "") $(this).val("Password");
  });
  
  $("input#account_username").focusin(function() {
    if ($(this).val() == "Account Username") $(this).val("");
  }).focusout(function() {
    if ($(this).val() == "") $(this).val("Account Username");
  });
  
  showMoreLess($("div.series-synopsis"), 106);
  $("li.creator, li.status, li.vintage").each(function() { showMoreLess($(this), 33, undefined, " [+]", " [-]"); } );
  $("li.genre").each(function() { showMoreLess($(this), 33, undefined, ' [+]', ' [-]', undefined, ','); });
  $("div.select-box div.select-options div").each(function() { showMoreLess($(this), 30, 232, "", "", "strong") });
  
  // PlusSearch Autocomplete
  $("#series_name").autocomplete({
    source: function(request, response) {
      $.ajax({
        url: getSearchURI(),
        dataType: "json",
        data: {
          series_name: request.term
        },
        success: function( data ) {
          arr = [];
          $.each(data, function(v, k) {
            arr.push({ label: v, value: v });
          });
          response(arr);
        }
      });
    },
    select: function(event, ui) {
      window.location.href = getSearchURI() + "//" + encodeURIComponent(encodeURIComponent(ui.item.value)) + "?exact=1";
      return false;
    },
    minLength: 2
  });
  
  // Rewrite Search Results
  $("#search form, #search-anime form, #search-hentai form").submit(function(e) {
    var genre = $("#series_genre").val();
    var name = $("#series_name").val();
    var keywords = $("#keywords").val();
    var url = getSearchURI() + "/" + encodeURIComponent(encodeURIComponent(genre));
    if (name.length > 0 && name != 'Enter a series title...') {
      url += "/" + encodeURIComponent(encodeURIComponent(name));
    } else if (typeof keywords !== 'undefined' && keywords.length > 0) {
      url += "/";
    }
    if (typeof keywords !== 'undefined' && keywords.length > 0) url += "/" + encodeURIComponent(encodeURIComponent(keywords));
    window.location.href = url;
    return false;
  });
});

function getSearchURI() {
  var uri, type;
  
  type = $("#search, #search-anime, #search-hentai").find("input[name='t']").val();
  
  if (typeof type == 'undefined') {
    type = '';
  }
  
  if (type == 'hm') {
    uri = '/plus/search/manga';
  } else if (type == 'hv') {
    uri = '/plus/search/videos';
  } else {
    uri = '/plus/search';
  }
  
  return uri;
}

function parseOptionValue(elem) {
  if (elem.is("div#rating-criteria li")) {
    var arr = elem.attr('id').split('-');
    return arr[arr.length - 1];
  } else {
    return elem.attr('val');
  }
}

// Show More/Less for the Series Synopsis and resize accordingly
// If specified, child is a selector that whose contents will be shrunk until the parent (elem) is the correct size,
// leaving anything else in elem intact.
function showMoreLess(elem, maxHeight, maxWidth, linkTextMore, linkTextLess, child, delim) {
  // maxHeight = The height at which text should be cut off
  if (typeof linkTextMore == 'undefined') linkTextMore = " [More]";
  if (typeof linkTextLess == 'undefined') linkTextLess = " [Less]";
  if (typeof delim == 'undefined') delim = ' ';
  var origHeight, height, width, origWidth, text, prevText, lastDelim, controlsAdded = false;
  var hiddenText = "", ellipsis = "<span class=\"ellipsis\"> ...</span>";

  heightElem = elem;
  if (typeof child != 'undefined') {
    elem = $(child, elem);
    if (elem.length > 0) widthElem = elem;
  }
  
  while (true) {
    height = heightElem.height();
    width = (typeof widthElem == 'undefined' || typeof maxWidth == 'undefined') ? 0 : widthElem.width();
    
    if (typeof origHeight == 'undefined') origHeight = height;
    if (typeof origWidth == 'undefined') origWidth = width;
    
    if (controlsAdded) {
      text = prevText; // If the height check below fails, revert to prevText
    } else {
      text = jQuery.trim(elem.html());
    }
    
    if (height > maxHeight || width > maxWidth) {
      // Remove words until elem's height is less than or equal to maxHeight
      lastDelim = text.lastIndexOf(delim);

      if (lastDelim == -1) { // No spaces found; no words to eliminate
        break;
      }
      
      elem.html(text.substring(0, lastDelim));
      hiddenText = text.substring(lastDelim) + hiddenText; // Save the omitted text for later.
      
      controlsAdded = false;
    } else {
      if ((height != origHeight || width != origWidth) && !controlsAdded) {
        // Size has changed; show the More/Less controls
        controlsAdded = true;
        prevText = text; // The element's innerHTML before adding the controls
        
        var str = text + ellipsis;
        
        if (linkTextMore != "") {
          str += "<a href=\"#\" class=\"controls\">" + linkTextMore + "</a>";
        }
        
        elem.html(str);
        
        // Now check if the height of the element exceeds maxHeight now that we've added the controls
        // If necessary, remove some more words until there's enough room. 
      } else {
        break;
      }
    }
  }
  
  if (controlsAdded) {
    // Add an element containing hiddenText and bind an event to a.controls
    elem.find("span.ellipsis").before("<span class=\"hiddenText\" style=\"display: none;\">" + hiddenText + "</span>");
    
    elem.find("a.controls").click(function() {
      if ($(this).text() == linkTextMore) {
        $(this).text(linkTextLess);
        $(this).siblings("span.ellipsis").remove();
        $(this).siblings("span.hiddenText").show();
      } else {
        $(this).text(linkTextMore);
        $(this).before(ellipsis);
        $(this).siblings("span.hiddenText").hide();
      }
      
      return false;
    });
  }
}

function fixPseudoSelectZIndex(div, i) {
  // Fix the z-index values
  var ul = div.find("div.select-options ul");
  ul.css("z-index", ul.css("z-index") - i);
  
  var arrow = div.find("div.select-arrow");
  arrow.css("z-index", arrow.css("z-index") - i);
  
  // Fix IE7 z-index problems
  if ($.browser.msie && parseInt($.browser.version) <= 7) {
    div.css("z-index", div.css("z-index") - i);
  }
  
  return ul;
}

function bindOptionEvent(e) {
  $(this).addClass('selected-option').siblings().removeClass('selected-option hover');
  $("#" + e.data.id).attr('prevVal', $("#" + e.data.id).val()).val(parseOptionValue($(this))).change();
  e.data.div.find('div.displayed-option').html($(this).html()).css("outline", "1px dotted black");
  e.data.div.find('div.select-arrow').removeClass('border-bottom');
  e.data.ul.hide();
}

function bindOptionEvents(id, div, ul) {
  ul.children("li:not(.optgroup-title)").bind('click', {id: id, div: div, ul: ul}, bindOptionEvent);
}

function bindOptionEventsForPseudoSelect(div) {
  var id = $(div).children("input").attr('id');
  var ul = $(div).find("div.select-options ul");
  bindOptionEvents(id, div, ul);
}

function bindOptionEventsForPseudoSelectParent(descendant) {
  bindOptionEventsForPseudoSelect($(descendant).parents("div.select-box"));
}

String.prototype.ltrim = function() {
  return this.replace(/^\s+/,"");
}

function switchPseudoSelectOption(ul, str) {
  str = str.ltrim().toLowerCase();
  var mode = ul.parents("div.select-box").find("input").is("[id*='paginator']") ? 'digits' : 'full';
  var elems = ul.children();
  var hi = elems.index(elems.filter("li.hover, li.selected-option"));
  
  if (hi == -1) {
    hi = 0;
  }
  
  for (var i = hi, j = 0; j < elems.length; i++, j++) {
    if (i == elems.length) {
      i = 0;
    }
    elem = $(elems.get(i));
    var text = elem.contents().filter(function() {
      return this.nodeType == 3
    }).text();
    
    if (mode == 'digits') {
      str = parseInt(str, 10);
      var substr = parseInt(text.replace(/[^\d]+/, ''), 10);
    } else {
      var substr = text.ltrim().substr(0, str.length).toLowerCase();
    }
    
    if (str == substr) {
      elems.filter(".hover, .selected-option").removeClass("hover selected-option");
      elem.addClass("hover");
      elem.parents("div.select-box").find('div.displayed-option').html(elem.html());
      ul.scrollTo(elem);
      break;
    }
  }
}

function pseudoSelectNav(ul, offset, elem) {
  var elems = ul.children();
  var filtered = elems.filter("li.hover");
  
  if (offset !== null) {
    if (filtered.length == 0) {
      filtered = elems.filter("li.selected-option");
    }
    
    var hi = elems.index(filtered);
    if (hi + offset < 0 || hi + offset > elems.length - 1) {
      return false;
    }
    var elem = $(elems.get(hi + offset));
  }
  
  if (elem !== null) {
    elems.filter(".hover, .selected-option").removeClass("hover selected-option");
    elem.addClass("hover");
    elem.parents("div.select-box").find('div.displayed-option').html(elem.html());
    scrollIntoView(elem, ul);
  }
}

function scrollIntoView(elem, parent) {
  if (typeof parent === 'undefined') {
    parent = window;
  }
  
  var parentTop = $(parent).scrollTop();
  var parentBottom = parentTop + $(parent).height();
  
  var elemTop = parentTop + $(elem).offset().top - $(parent).offset().top;
  var elemBottom = elemTop + $(elem).innerHeight();
  
  if (elemTop >= parentBottom) {
    var pos = elemBottom - $(parent).height();
    
    if (pos < parentTop) {
      return false;
    }
    
    parent.scrollTo(pos);
  } else if (elemBottom <= parentTop) {
    parent.scrollTo(elemTop);
  }
}
