/**
* hoverIntent r5 // 2007.03.27 // jQuery 1.1.2+
* <http://cherne.net/brian/resources/jquery.hoverIntent.html>
* 
* @param  f  onMouseOver function || An object with configuration options
* @param  g  onMouseOut function  || Nothing (use configuration options object)
* @author    Brian Cherne <brian@cherne.net>
*/
(function($){$.fn.hoverIntent=function(f,g){var cfg={sensitivity:7,interval:100,timeout:0};cfg=$.extend(cfg,g?{over:f,out:g}:f);var cX,cY,pX,pY;var track=function(ev){cX=ev.pageX;cY=ev.pageY;};var compare=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);if((Math.abs(pX-cX)+Math.abs(pY-cY))<cfg.sensitivity){$(ob).unbind("mousemove",track);ob.hoverIntent_s=1;return cfg.over.apply(ob,[ev]);}else{pX=cX;pY=cY;ob.hoverIntent_t=setTimeout(function(){compare(ev,ob);},cfg.interval);}};var delay=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);ob.hoverIntent_s=0;return cfg.out.apply(ob,[ev]);};var handleHover=function(e){var p=(e.type=="mouseover"?e.fromElement:e.toElement)||e.relatedTarget;while(p&&p!=this){try{p=p.parentNode;}catch(e){p=this;}}if(p==this){return false;}var ev=jQuery.extend({},e);var ob=this;if(ob.hoverIntent_t){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);}if(e.type=="mouseover"){pX=ev.pageX;pY=ev.pageY;$(ob).bind("mousemove",track);if(ob.hoverIntent_s!=1){ob.hoverIntent_t=setTimeout(function(){compare(ev,ob);},cfg.interval);}}else{$(ob).unbind("mousemove",track);if(ob.hoverIntent_s==1){ob.hoverIntent_t=setTimeout(function(){delay(ev,ob);},cfg.timeout);}}};return this.mouseover(handleHover).mouseout(handleHover);};})(jQuery);

/*
 * jQuery clueTip plugin
 * Version 0.9.9  (04/24/2009)
 * @requires jQuery v1.1.4+
 * @requires Dimensions plugin IF USED WITH jQuery VERSIONS PRIOR TO 1.2.5)
 *
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */
 
/*
 *
 * Full list of options/settings can be found at the bottom of this file and at http://plugins.learningjquery.com/cluetip/
 *
 * Examples can be found at http://plugins.learningjquery.com/cluetip/demo/
 *
*/

;(function($) { 

  var $cluetip, $cluetipInner, $cluetipOuter, $cluetipTitle, $cluetipArrows, $dropShadow, imgCount;
  $.fn.cluetip = function(js, options) {
    if (typeof js == 'object') {
      options = js;
      js = null;
    }
    return this.each(function(index) {
      var $this = $(this);      
      
      // support metadata plugin (v1.0 and 2.0)
      var opts = $.extend(true, {}, $.fn.cluetip.defaults, options || {}, $.metadata ? $this.metadata() : $.meta ? $this.data() : {});

      // start out with no contents (for ajax activation)
      var cluetipContents = false;
      var cluezIndex = parseInt(opts.cluezIndex, 10)-1;
      var isActive = false, closeOnDelay = 0;

      // create the cluetip divs
      if (!$('#cluetip').length) {
        $cluetipInner = $('<div id="cluetip-inner"></div>');
        $cluetipTitle = $('<h3 id="cluetip-title"></h3>');        
        $cluetipOuter = $('<div id="cluetip-outer"></div>').append($cluetipInner).prepend($cluetipTitle);
        $cluetip = $('<div id="cluetip"></div>').css({zIndex: opts.cluezIndex})
        .append($cluetipOuter).append('<div id="cluetip-extra"></div>')[insertionType](insertionElement).hide();
        $('<div id="cluetip-waitimage"></div>').css({position: 'absolute', zIndex: cluezIndex-1})
        .insertBefore('#cluetip').hide();
        $cluetip.css({position: 'absolute', zIndex: cluezIndex});
        $cluetipOuter.css({position: 'relative', zIndex: cluezIndex+1});
        $cluetipArrows = $('<div id="cluetip-arrows" class="cluetip-arrows"></div>').css({zIndex: cluezIndex+1}).appendTo('#cluetip');
      }
      var dropShadowSteps = (opts.dropShadow) ? +opts.dropShadowSteps : 0;
      if (!$dropShadow) {
        $dropShadow = $([]);
        for (var i=0; i < dropShadowSteps; i++) {
          $dropShadow = $dropShadow.add($('<div></div>').css({zIndex: cluezIndex-i-1, opacity:.1, top: 1+i, left: 1+i}));
        };
        $dropShadow.css({position: 'absolute', backgroundColor: '#000'})
        .prependTo($cluetip);
      }
      var tipAttribute = $this.attr(opts.attribute), ctClass = opts.cluetipClass;
      if (!tipAttribute && !opts.splitTitle && !js) return true;
      // if hideLocal is set to true, on DOM ready hide the local content that will be displayed in the clueTip
      if (opts.local && opts.localPrefix) {tipAttribute = opts.localPrefix + tipAttribute;}
      if (opts.local && opts.hideLocal) { $(tipAttribute + ':first').hide(); }
      var tOffset = parseInt(opts.topOffset, 10), lOffset = parseInt(opts.leftOffset, 10);
      // vertical measurement variables
      var tipHeight, wHeight;
      var defHeight = isNaN(parseInt(opts.height, 10)) ? 'auto' : (/\D/g).test(opts.height) ? opts.height : opts.height + 'px';
      var sTop, linkTop, posY, tipY, mouseY, baseline;
      // horizontal measurement variables
      var tipInnerWidth = isNaN(parseInt(opts.width, 10)) ? 275 : parseInt(opts.width, 10);
      var tipWidth = tipInnerWidth + (parseInt($cluetip.css('paddingLeft'),10)||0) + (parseInt($cluetip.css('paddingRight'),10)||0) + dropShadowSteps;
      var linkWidth = this.offsetWidth;
      var linkLeft, posX, tipX, mouseX, winWidth;
            
      // parse the title
      var tipParts;
      var tipTitle = (opts.attribute != 'title') ? $this.attr(opts.titleAttribute) : '';
      if (opts.splitTitle) {
        if(tipTitle == undefined) {tipTitle = '';}
        tipParts = tipTitle.split(opts.splitTitle);
        tipTitle = tipParts.shift();
      }
      if (opts.escapeTitle) {
        tipTitle = tipTitle.replace(/&/g,'&amp;').replace(/>/g,'&gt;').replace(/</g,'&lt;');
      }
      
      var localContent;

/***************************************      
* ACTIVATION
****************************************/
    
//activate clueTip
    var activate = function(event) {
      if (!opts.onActivate($this)) {
        return false;
      }
      isActive = true;
      $cluetip.removeClass().css({width: tipInnerWidth});
      if (tipAttribute == $this.attr('href')) {
        $this.css('cursor', opts.cursor);
      }
      $this.attr('title','');
      if (opts.hoverClass) {
        $this.addClass(opts.hoverClass);
      }
      linkTop = posY = $this.offset().top;
      linkLeft = $this.offset().left;
      mouseX = event.pageX;
      mouseY = event.pageY;
      if ($this[0].tagName.toLowerCase() != 'area') {
        sTop = $(document).scrollTop();
        winWidth = $(window).width();
      }
// position clueTip horizontally
      if (opts.positionBy == 'fixed') {
        posX = linkWidth + linkLeft + lOffset;
        $cluetip.css({left: posX});
      } else {
        posX = (linkWidth > linkLeft && linkLeft > tipWidth)
          || linkLeft + linkWidth + tipWidth + lOffset > winWidth 
          ? linkLeft - tipWidth - lOffset 
          : linkWidth + linkLeft + lOffset;
        if ($this[0].tagName.toLowerCase() == 'area' || opts.positionBy == 'mouse' || linkWidth + tipWidth > winWidth) { // position by mouse
          if (mouseX + 20 + tipWidth > winWidth) {  
            $cluetip.addClass(' cluetip-' + ctClass);
            posX = (mouseX - tipWidth - lOffset) >= 0 ? mouseX - tipWidth - lOffset - parseInt($cluetip.css('marginLeft'),10) + parseInt($cluetipInner.css('marginRight'),10) :  mouseX - (tipWidth/2);
          } else {
            posX = mouseX + lOffset;
          }
        }
        var pY = posX < 0 ? event.pageY + tOffset : event.pageY;
        $cluetip.css({left: (posX > 0 && opts.positionBy != 'bottomTop') ? posX : (mouseX + (tipWidth/2) > winWidth) ? winWidth/2 - tipWidth/2 : Math.max(mouseX - (tipWidth/2),0)});
      }
        wHeight = $(window).height();

/***************************************
* load a string from cluetip method's first argument
***************************************/
      if (js) {
        if (typeof js == 'function') {
          js = js($this[0]);
        }
        $cluetipInner.html(js);
        cluetipShow(pY);
      }
/***************************************
* load the title attribute only (or user-selected attribute). 
* clueTip title is the string before the first delimiter
* subsequent delimiters place clueTip body text on separate lines
***************************************/

      else if (tipParts) {
        var tpl = tipParts.length;
        $cluetipInner.empty();
        for (var i=0; i < tpl; i++){
          if (i == 0) {
            $cluetipInner.html(tipParts[i]);
          } else { 
            $cluetipInner.append('<div class="split-body">' + tipParts[i] + '</div>');
          }            
        };
        cluetipShow(pY);
      }
/***************************************
* load external file via ajax          
***************************************/

      else if (!opts.local && tipAttribute.indexOf('#') != 0) {
        if (/\.(jpe?g|tiff?|gif|png)$/i.test(tipAttribute)) {
          $cluetipInner.html('<img src="' + tipAttribute + '" alt="' + tipTitle + '" />');
          cluetipShow(pY);
        } else if (cluetipContents && opts.ajaxCache) {
          $cluetipInner.html(cluetipContents);
          cluetipShow(pY);
        } else {
          var ajaxSettings = opts.ajaxSettings;
          ajaxSettings.cache = false; // force requested page not to be cached by browser
          ajaxSettings.url = tipAttribute;
          ajaxSettings.beforeSend = function() {
            $cluetipOuter.children().empty();
            if (opts.waitImage) {
              $('#cluetip-waitimage')
              .css({top: mouseY+20, left: mouseX+20})
              .show();
            }
          };
         ajaxSettings.error = function() {
            if (isActive) {
              $cluetipInner.html('<i>sorry, the contents could not be loaded</i>');
            }
          };
          ajaxSettings.success = function(data) {
            cluetipContents = opts.ajaxProcess(data);
            if (isActive) {
              $cluetipInner.html(cluetipContents);
            }
          };
          ajaxSettings.complete = function() {
            imgCount = $('#cluetip-inner img').length;
            if (imgCount && !$.browser.opera) {
              $('#cluetip-inner img').load(function() {
                imgCount--;
                if (imgCount<1) {
                  $('#cluetip-waitimage').hide();
                  if (isActive) cluetipShow(pY);
                }
              }); 
            } else {
              $('#cluetip-waitimage').hide();
              if (isActive) cluetipShow(pY);    
            } 
          };
          $.ajax(ajaxSettings);
        }

/***************************************
* load an element from the same page
***************************************/
      } else if (opts.local) {
        
        var $localContent = $(tipAttribute + (/#\w+$/.test(tipAttribute) ? '' : ':eq(' + index + ')')).clone(true).show();
        $cluetipInner.html($localContent);
        cluetipShow(pY);
      }
    };

// get dimensions and options for cluetip and prepare it to be shown
    var cluetipShow = function(bpY) {
      $cluetip.addClass('cluetip-' + ctClass);
      
      if (opts.truncate) { 
        var $truncloaded = $cluetipInner.text().slice(0,opts.truncate) + '...';
        $cluetipInner.html($truncloaded);
      }
      function doNothing() {}; //empty function
      tipTitle ? $cluetipTitle.show().html(tipTitle) : (opts.showTitle) ? $cluetipTitle.show().html('&nbsp;') : $cluetipTitle.hide();
      if (opts.sticky) {
        var $closeLink = $('<div id="cluetip-close"><a href="#">' + opts.closeText + '</a></div>');
        (opts.closePosition == 'bottom') ? $closeLink.appendTo($cluetipInner) : (opts.closePosition == 'title') ? $closeLink.prependTo($cluetipTitle) : $closeLink.prependTo($cluetipInner);
        $closeLink.click(function() {
          cluetipClose();
          return false;
        });
        if (opts.mouseOutClose) {
          if ($.fn.hoverIntent && opts.hoverIntent) { 
            $cluetip.hoverIntent({
              over: doNothing, 
              timeout: opts.hoverIntent.timeout,  
              out: function() { $closeLink.trigger('click'); }
            });
          } else {
            $cluetip.hover(doNothing, 
            function() {$closeLink.trigger('click'); });
          }
        } else {
          $cluetip.unbind('mouseout');
        }
      }
// now that content is loaded, finish the positioning 
      var direction = '';
      $cluetipOuter.css({overflow: defHeight == 'auto' ? 'visible' : 'auto', height: defHeight});
      tipHeight = defHeight == 'auto' ? Math.max($cluetip.outerHeight(),$cluetip.height()) : parseInt(defHeight,10);   
      tipY = posY;
      baseline = sTop + wHeight;
      if (opts.positionBy == 'fixed') {
        tipY = posY - opts.dropShadowSteps + tOffset;
      } else if ( (posX < mouseX && Math.max(posX, 0) + tipWidth > mouseX) || opts.positionBy == 'bottomTop') {
        if (posY + tipHeight + tOffset > baseline && mouseY - sTop > tipHeight + tOffset) { 
          tipY = mouseY - tipHeight - tOffset;
          direction = 'top';
        } else { 
          tipY = mouseY + tOffset;
          direction = 'bottom';
        }
      } else if ( posY + tipHeight + tOffset > baseline ) {
        tipY = (tipHeight >= wHeight) ? sTop : baseline - tipHeight - tOffset;
      } else if ($this.css('display') == 'block' || $this[0].tagName.toLowerCase() == 'area' || opts.positionBy == "mouse") {
        tipY = bpY - tOffset;
      } else {
        tipY = posY - opts.dropShadowSteps;
      }
      if (direction == '') {
        posX < linkLeft ? direction = 'left' : direction = 'right';
      }
      $cluetip.css({top: tipY + 'px'}).removeClass().addClass('clue-' + direction + '-' + ctClass).addClass(' cluetip-' + ctClass);
      if (opts.arrows) { // set up arrow positioning to align with element
        var bgY = (posY - tipY - opts.dropShadowSteps);
        $cluetipArrows.css({top: (/(left|right)/.test(direction) && posX >=0 && bgY > 0) ? bgY + 'px' : /(left|right)/.test(direction) ? 0 : ''}).show();
      } else {
        $cluetipArrows.hide();
      }
			
// (first hide, then) ***SHOW THE CLUETIP***
      $dropShadow.hide();
      $cluetip.hide()[opts.fx.open](opts.fx.open != 'show' && opts.fx.openSpeed);
      if (opts.dropShadow) $dropShadow.css({height: tipHeight, width: tipInnerWidth}).show();
      if ($.fn.bgiframe) { $cluetip.bgiframe(); }
      // delayed close (not fully tested)
      if (opts.delayedClose > 0) {
        closeOnDelay = setTimeout(cluetipClose, opts.delayedClose);
      }
      // trigger the optional onShow function
      opts.onShow($cluetip, $cluetipInner);
      
    };

/***************************************
   =INACTIVATION
-------------------------------------- */
    var inactivate = function(event) {
      isActive = false;
      $('#cluetip-waitimage').hide();
      if (!opts.sticky || (/click|toggle/).test(opts.activation) ) {
        cluetipClose();
clearTimeout(closeOnDelay);        
      };
      if (opts.hoverClass) {
        $this.removeClass(opts.hoverClass);
      }
    };
// close cluetip and reset some things
    var cluetipClose = function() {
      $cluetipOuter 
      .parent().hide().removeClass();
      opts.onHide($cluetip, $cluetipInner);
      $this.removeClass('cluetip-clicked');
      if (tipTitle) {
        $this.attr(opts.titleAttribute, tipTitle);
      }
      $this.css('cursor','');
      if (opts.arrows) $cluetipArrows.css({top: ''});
    };

/***************************************
   =BIND EVENTS
-------------------------------------- */
  // activate by click
      if ( (/click|toggle/).test(opts.activation) ) {
        $this.click(function(event) {
          if ($cluetip.is(':hidden') || !$this.is('.cluetip-clicked')) {
            activate(event);
            $('.cluetip-clicked').removeClass('cluetip-clicked');
            $this.addClass('cluetip-clicked');
          } else {
            inactivate(event);
          }
          this.blur();
          return false;
        });
  // activate by focus; inactivate by blur    
      } else if (opts.activation == 'focus') {
        $this.focus(function(event) {
          activate(event);
        });
        $this.blur(function(event) {
          inactivate(event);
        });
  // activate by hover
    // clicking is returned false if cluetip url is same as href url
      } else {
        $this.click(function() {
          if ($this.attr('href') && $this.attr('href') == tipAttribute && !opts.clickThrough) {
            return false;
          }
        });
        //set up mouse tracking
        var mouseTracks = function(evt) {
          if (opts.tracking == true) {
            var trackX = posX - evt.pageX;
            var trackY = tipY ? tipY - evt.pageY : posY - evt.pageY;
            $this.mousemove(function(evt) {
              $cluetip.css({left: evt.pageX + trackX, top: evt.pageY + trackY });
            });
          }
        };
        if ($.fn.hoverIntent && opts.hoverIntent) {
          $this.mouseover(function() {$this.attr('title',''); })
          .hoverIntent({
            sensitivity: opts.hoverIntent.sensitivity,
            interval: opts.hoverIntent.interval,  
            over: function(event) {
              activate(event);
              mouseTracks(event);
            }, 
            timeout: opts.hoverIntent.timeout,  
            out: function(event) {inactivate(event); $this.unbind('mousemove');}
          });           
        } else {
          $this.hover(function(event) {
            activate(event);
            mouseTracks(event);
          }, function(event) {
            inactivate(event);
            $this.unbind('mousemove');
          });
        }
      }
    });
  };
  
/*
 * options for clueTip
 *
 * each one can be explicitly overridden by changing its value. 
 * for example: $.fn.cluetip.defaults.width = 200; 
 * would change the default width for all clueTips to 200. 
 *
 * each one can also be overridden by passing an options map to the cluetip method.
 * for example: $('a.example').cluetip({width: 200}); 
 * would change the default width to 200 for clueTips invoked by a link with class of "example"
 *
 */
  
  $.fn.cluetip.defaults = {  // set up default options
    width:            275,      // The width of the clueTip
    height:           'auto',   // The height of the clueTip
    cluezIndex:       97,       // Sets the z-index style property of the clueTip
    positionBy:       'auto',   // Sets the type of positioning: 'auto', 'mouse','bottomTop', 'fixed'
    topOffset:        15,       // Number of px to offset clueTip from top of invoking element
    leftOffset:       15,       // Number of px to offset clueTip from left of invoking element
    local:            false,    // Whether to use content from the same page for the clueTip's body
    localPrefix:    null,       // string to be prepended to the tip attribute if local is true
    hideLocal:        true,     // If local option is set to true, this determines whether local content
                                // to be shown in clueTip should be hidden at its original location
    attribute:        'rel',    // the attribute to be used for fetching the clueTip's body content
    titleAttribute:   'title',  // the attribute to be used for fetching the clueTip's title
    splitTitle:       '',       // A character used to split the title attribute into the clueTip title and divs
                                // within the clueTip body. more info below [6]
    escapeTitle:      false,    // whether to html escape the title attribute
    showTitle:        true,     // show title bar of the clueTip, even if title attribute not set
    cluetipClass:     'default',// class added to outermost clueTip div in the form of 'cluetip-' + clueTipClass.
    hoverClass:       '',       // class applied to the invoking element onmouseover and removed onmouseout
    waitImage:        true,     // whether to show a "loading" img, which is set in jquery.cluetip.css
    cursor:           'help',
    arrows:           false,    // if true, displays arrow on appropriate side of clueTip
    dropShadow:       true,     // set to false if you don't want the drop-shadow effect on the clueTip
    dropShadowSteps:  6,        // adjusts the size of the drop shadow
    sticky:           false,    // keep visible until manually closed
    mouseOutClose:    false,    // close when clueTip is moused out
    activation:       'hover',  // set to 'click' to force user to click to show clueTip
                                // set to 'focus' to show on focus of a form element and hide on blur
    clickThrough:     false,    // if true, and activation is not 'click', then clicking on link will take user to the link's href,
                                // even if href and tipAttribute are equal
    tracking:         false,    // if true, clueTip will track mouse movement (experimental)
    delayedClose:     0,        // close clueTip on a timed delay (experimental)
    closePosition:    'top',    // location of close text for sticky cluetips; can be 'top' or 'bottom' or 'title'
    closeText:        'Close',  // text (or HTML) to to be clicked to close sticky clueTips
    truncate:         0,        // number of characters to truncate clueTip's contents. if 0, no truncation occurs

    // effect and speed for opening clueTips
    fx: {             
                      open:       'show', // can be 'show' or 'slideDown' or 'fadeIn'
                      openSpeed:  ''
    },     

    // settings for when hoverIntent plugin is used             
    hoverIntent: {    
                      sensitivity:  3,
              			  interval:     50,
              			  timeout:      0
    },

    // function to run just before clueTip is shown.           
    onActivate:       function(e) {return true;},

    // function to run just after clueTip is shown.
    onShow:           function(ct, c){},
    // function to run just after clueTip is hidden.
    onHide:           function(ct, c){},
    // whether to cache results of ajax request to avoid unnecessary hits to server    
    ajaxCache:        true,  

    // process data retrieved via xhr before it's displayed
    ajaxProcess:      function(data) {
                        data = data.replace(/<s(cript|tyle)(.|\s)*?\/s(cript|tyle)>/g, '').replace(/<(link|title)(.|\s)*?\/(link|title)>/g,'');
                        return data;
    },                

    // can pass in standard $.ajax() parameters, not including error, complete, success, and url
    ajaxSettings: {
                      dataType: 'html'
    },
    debug: false
  };


/*
 * Global defaults for clueTips. Apply to all calls to the clueTip plugin.
 *
 * @example $.cluetip.setup({
 *   insertionType: 'prependTo',
 *   insertionElement: '#container'
 * });
 * 
 * @property
 * @name $.cluetip.setup
 * @type Map
 * @cat Plugins/tooltip
 * @option String insertionType: Default is 'appendTo'. Determines the method to be used for inserting the clueTip into the DOM. Permitted values are 'appendTo', 'prependTo', 'insertBefore', and 'insertAfter'
 * @option String insertionElement: Default is 'body'. Determines which element in the DOM the plugin will reference when inserting the clueTip.
 *
 */
   
  var insertionType = 'appendTo', insertionElement = 'body';
  $.cluetip = {};
  $.cluetip.setup = function(options) {
    if (options && options.insertionType && (options.insertionType).match(/appendTo|prependTo|insertBefore|insertAfter/)) {
      insertionType = options.insertionType;
    }
    if (options && options.insertionElement) {
      insertionElement = options.insertionElement;
    }
  };
  
})(jQuery);


/*
** movierollover.js
**
** plugin for displaying more info about a movie via a popup when they mouseover
** a movie.
**
** underlying popup uses cluetip: http://plugins.learningjquery.com/cluetip/
**
** required:  jquery.js, jquery.dimension.js, jquery.cluetip.js
**
*/
;(function($){
	
	/*
	** mouserollover
	**
	** displays the hidden information about a movie in a popup.  
	*/
	$.fn.movierollover = function( settings ) {
		
		// add only if we need settings
		if ( settings ) $.extend( $.fn.movierollover.settings, settings );
		
		// global variables for all the rollovers on a page.
		var parentElement 			= null;
		var parentElementOffset = null;
		var leftBoundry    			= null;
		var rightBoundry   			= null;
		
		
		this.each( function() {

			var _movie 				= $(this);
			
			// we only need to set this up once for all rollovers on a page.
			if ( !parentElement ) {
				parentElement = _movie.parent( $.fn.movierollover.settings.parentContainerSelector );
				parentElementOffset = parentElement.offset();

				leftBoundry    = parentElementOffset.left;
				rightBoundry   = parentElementOffset.left + parentElement.width();
			}
			
			/*
				if the user moves the mouse out of main movie element, or
				cluetip then close the cluetip.
			*/
			_movie.handleMouseOut = function( event ) {
				var x = event.pageX, y = event.pageY;
				if( !mouseInMovieAndCluetip( _movie, x, y ) ) {
					_movie._cluetip.hide();
				}
			};
			
			/*
				explicitly removes the hidden class from .movie-popup.
				this is for Safari, it wasn't showing the cluetip if
				this was hidden.
				
				NOTE: don't think we need explicitly hide .movie-popup.
				I believe the plugin is doing that.
			*/
			_movie.handleOnShow = function( ct, c ) {
				var cluetip = $(ct);
				cluetip.find('.movie-popup').removeClass("hidden");
			
				_movie._cluetip = cluetip;
			
				// let's adjust the popup window position based on the
				// movie and the parent container boundries.
				var movieOffset 	= _movie.offset();
				var cluetipWidth 	= cluetip.width();
				var cluetipTop  	= movieOffset.top + $.fn.movierollover.settings.topOffset;
				var cluetipLeft   = movieOffset.left;
				var cluetipRight  = cluetipLeft + cluetipWidth;
				
				if ( cluetipLeft <= leftBoundry ) {
					cluetipLeft = leftBoundry + 50;
				}
				if ( cluetipRight >= (rightBoundry-20) ) {
					cluetipLeft = rightBoundry-cluetipWidth-50;
				}
				
				cluetip.find('.truncate_115').truncate( 115, {
		      chars: /\s/,
		      trail:  [ " (<a href='#' class='truncate_show'>more</a>)", " (<a href='#' class='truncate_hide'>less</a>)" ]
		    });
			
				cluetip.css({'top': cluetipTop + "px", 'left': cluetipLeft});
				
				// attach other events
				_movie.mouseout( _movie.handleMouseOut );
				cluetip.mouseout( _movie.handleMouseOut );
			};
			
			_movie.cluetip({
				local: true,
				sticky: true, /* we want it to be sticky, so we can click in it */
				dropShadow: false,
				cluetipClass: 'movie',
				mouseOutClose: true,
				width: '460',
				topOffset: -25,
				showTitle: false,
				positionBy: 'mouse',
				cluezIndex: 300,
				hoverIntent: {
					interval: 200
				},
				onShow: _movie.handleOnShow
			});
			
		});
		
		function mouseInMovieAndCluetip(movie, x, y ) {
			var movieX = movie.offset().top, movieY = movie.offset().left;
			var movieH = movie.height(), movieW = movie.width();
			
			var popup = movie._cluetip.find('.movie-popup');
			var cluetipX = popup.offset().top, cluetipY = popup.offset().left;
			var cluetipH = popup.height(), cluetipW = popup.width();
			
			return $.ui.isOver( y, x, movieX, movieY, movieH, movieW ) || $.ui.isOver( y, x, cluetipX, cluetipY, cluetipH, cluetipW );
		}
	};
	
	
	$.extend( $.fn.movierollover, {
		settings: {
			parentContainerSelector: '#results',
			topOffset: 50
		}
	});
	

	


	
	
})(jQuery);

(function(F){var E=[],L=[],J=activeItem=null,C=F("<div class=\"menu-div outerbox\" style=\"position:absolute;top:0;left:0;display:none;\"><div class=\"shadowbox1\"></div><div class=\"shadowbox2\"></div><div class=\"shadowbox3\"></div></div>")[0],B=F("<ul class=\"menu-ul innerbox\"></ul>")[0],K=F("<li style=\"position:relative;\"><div class=\"menu-item\"></div></li>")[0],I=F("<img class=\"menu-item-arrow\" />")[0],H=F("<div id=\"root-menu-div\" style=\"position:absolute;top:0;left:0;\"></div>"),D={showDelay:200,hideDelay:200,hoverOpenDelay:0,offsetTop:0,offsetLeft:0,minWidth:0,onOpen:null,onClose:null,onClick:null,arrowSrc:null,addExpando:false,copyClassAttr:false};F(function(){H.appendTo("body")});F.extend({MenuCollection:function(M){this.menus=[];this.init(M)}});F.extend(F.MenuCollection,{prototype:{init:function(M){if(M&&M.length){for(var N=0;N<M.length;N++){this.addMenu(M[N]);M[N].menuCollection=this}}},addMenu:function(N){if(N instanceof F.Menu){this.menus.push(N)}N.menuCollection=this;var M=this;F(N.target).hover(function(){if(N.visible){return }for(var O=0;O<M.menus.length;O++){if(M.menus[O].visible){M.menus[O].hide();N.show();return }}},function(){})}}});F.extend({Menu:function(O,M,N){this.menuItems=[];this.subMenus=[];this.visible=false;this.active=false;this.parentMenuItem=null;this.settings=F.extend({},D,N);this.target=O;this.$eDIV=null;this.$eUL=null;this.timer=null;this.menuCollection=null;this.openTimer=null;this.init();if(M&&M.constructor==Array){this.addItems(M)}}});F.extend(F.Menu,{checkMouse:function(N){var M=N.target;if(L.length&&M==L[0].target){return }while(M.parentNode&&M.parentNode!=H[0]){M=M.parentNode}if(!F(L).filter(function(){return this.$eDIV[0]==M}).length){F.Menu.closeAll()}},checkKey:function(R){switch(R.keyCode){case 13:if(activeItem){activeItem.click(R,activeItem.$eLI[0])}break;case 27:F.Menu.closeAll();break;case 37:if(!J){J=L[0]}var N=J;if(N&&N.parentMenuItem){var P=N.parentMenuItem;P.$eLI.unbind("mouseout").unbind("mouseover");N.hide();P.hoverIn(true);setTimeout(function(){P.bindHover()})}else{if(N&&N.menuCollection){var S,O=N.menuCollection.menus;if((S=F.inArray(N,O))>-1){if(--S<0){S=O.length-1}F.Menu.closeAll();O[S].show();O[S].setActive();if(O[S].menuItems.length){O[S].menuItems[0].hoverIn(true)}}}}break;case 38:if(J){J.selectNextItem(-1)}break;case 39:if(!J){J=L[0]}var M,N=J,Q=activeItem?activeItem.subMenu:null;if(N){if(Q&&Q.menuItems.length){Q.show();Q.menuItems[0].hoverIn()}else{if((N=N.inMenuCollection())){var S,O=N.menuCollection.menus;if((S=F.inArray(N,O))>-1){if(++S>=O.length){S=0}F.Menu.closeAll();O[S].show();O[S].setActive();if(O[S].menuItems.length){O[S].menuItems[0].hoverIn(true)}}}}}break;case 40:if(!J){if(L.length&&L[0].menuItems.length){L[0].menuItems[0].hoverIn()}}else{J.selectNextItem()}break}if(R.keyCode>36&&R.keyCode<41){return false}},closeAll:function(){while(L.length){L[0].hide()}},setDefaults:function(M){F.extend(D,M)},prototype:{init:function(){var M=this;if(!this.target){return }else{if(this.target instanceof F.MenuItem){this.parentMenuItem=this.target;this.target.addSubMenu(this);this.target=this.target.$eLI}}E.push(this);this.$eDIV=F(C.cloneNode(1));this.$eUL=F(B.cloneNode(1));this.$eDIV[0].appendChild(this.$eUL[0]);H[0].appendChild(this.$eDIV[0]);if(!this.parentMenuItem){F(this.target).click(function(N){M.onClick(N)}).hover(function(N){M.setActive();if(M.settings.hoverOpenDelay){M.openTimer=setTimeout(function(){if(!M.visible){M.onClick(N)}},M.settings.hoverOpenDelay)}},function(){if(!M.visible){F(this).removeClass("activetarget")}if(M.openTimer){clearTimeout(M.openTimer)}})}else{this.$eDIV.hover(function(){M.setActive()},function(){})}},setActive:function(){if(!this.parentMenuItem){F(this.target).addClass("activetarget")}else{this.active=true}},addItem:function(M){if(M instanceof F.MenuItem){if(F.inArray(M,this.menuItems)==-1){this.$eUL.append(M.$eLI);this.menuItems.push(M);M.parentMenu=this;if(M.subMenu){this.subMenus.push(M.subMenu)}}}else{this.addItem(new F.MenuItem(M,this.settings))}},addItems:function(M){for(var N=0;N<M.length;N++){this.addItem(M[N])}},removeItem:function(M){var N=F.inArray(M,this.menuItems);if(N>-1){this.menuItems.splice(N,1)}M.parentMenu=null},hide:function(){if(!this.visible){return }var M,N=F.inArray(this,L);this.$eDIV.hide();if(N>=0){L.splice(N,1)}this.visible=this.active=false;F(this.target).removeClass("activetarget");for(M=0;M<this.subMenus.length;M++){this.subMenus[M].hide()}for(M=0;M<this.menuItems.length;M++){if(this.menuItems[M].active){this.menuItems[M].setInactive()}}if(!L.length){F(document).unbind("mousedown",F.Menu.checkMouse).unbind("keydown",F.Menu.checkKey)}if(J==this){J=null}if(this.settings.onClose){this.settings.onClose.call(this)}},show:function(O){if(this.visible){return }var N,M=this.parentMenuItem;if(this.menuItems.length){if(M){N=parseInt(M.parentMenu.$eDIV.css("z-index"));this.$eDIV.css("z-index",(isNaN(N)?1:N+1))}this.$eDIV.css({visibility:"hidden",display:"block"});if(this.settings.minWidth){if(this.$eDIV.width()<this.settings.minWidth){this.$eDIV.css("width",this.settings.minWidth)}}this.setPosition();this.$eDIV.css({display:"none",visibility:""}).show();if(F.browser.msie){this.$eUL.css("width",parseInt(F.browser.version)==6?this.$eDIV.width()-7:this.$eUL.width())}if(this.settings.onOpen){this.settings.onOpen.call(this)}}if(L.length==0){F(document).bind("mousedown",F.Menu.checkMouse).bind("keydown",F.Menu.checkKey)}this.visible=true;L.push(this)},setPosition:function(){var S,Q,O,M,V,W,R,T=F(window).width(),N=F(window).height(),X=this.parentMenuItem,Y=this.$eDIV[0].clientHeight,P=this.$eDIV[0].clientWidth,U;if(X){Q=X.$eLI.offset();O=Q.left+X.$eLI.width();M=Q.top}else{S=F(this.target);Q=S.offset();O=Q.left+this.settings.offsetLeft;M=Q.top+S.height()+this.settings.offsetTop}if(F.fn.scrollTop){W=F(window).scrollTop();if(N<Y){M=W}else{if(N+W<M+Y){if(X){V=X.parentMenu.$eDIV.offset();U=X.parentMenu.$eDIV[0].clientHeight;if(Y<=U){M=V.top+U-Y}else{M=V.top}if(N+W<M+Y){M-=M+Y-(N+W)}}else{M-=M+Y-(N+W)}}}}if(F.fn.scrollLeft){R=F(window).scrollLeft();if(T+R<O+P){if(X){O-=X.$eLI.width()+P;if(O<R){O=R}}else{O-=O+P-(T+R)}}}this.$eDIV.css({left:O,top:M})},onClick:function(M){if(this.visible){this.hide();this.setActive()}else{F.Menu.closeAll();this.show(M)}},addTimer:function(O,N){var M=this;this.timer=setTimeout(function(){O.call(M);M.timer=null},N)},removeTimer:function(){if(this.timer){clearTimeout(this.timer);this.timer=null}},selectNextItem:function(P){var M,Q=0,N=this.menuItems.length,O=P||1;for(M=0;M<N;M++){if(this.menuItems[M].active){Q=M;break}}this.menuItems[Q].hoverOut();do{Q+=O;if(Q>=N){Q=0}else{if(Q<0){Q=N-1}}}while(this.menuItems[Q].separator);this.menuItems[Q].hoverIn(true)},inMenuCollection:function(){var M=this;while(M.parentMenuItem){M=M.parentMenuItem.parentMenu}return M.menuCollection?M:null},destroy:function(){var N,M;this.hide();if(!this.parentMenuItem){F(this.target).unbind("click").unbind("mouseover").unbind("mouseout")}else{this.$eDIV.unbind("mouseover").unbind("mouseout")}while(this.menuItems.length){M=this.menuItems[0];M.destroy();delete M}if((N=F.inArray(this,E))>-1){E.splice(N,1)}if(this.menuCollection){if((N=F.inArray(this,this.menuCollection.menus))>-1){this.menuCollection.menus.splice(N,1)}}this.$eDIV.remove()}}});F.extend({MenuItem:function(N,M){if(typeof N=="string"){N={src:N}}this.src=N.src||"";this.url=N.url||null;this.urlTarget=N.target||null;this.addClass=N.addClass||null;this.data=N.data||null;this.$eLI=null;this.parentMenu=null;this.subMenu=null;this.settings=F.extend({},D,M);this.active=false;this.enabled=true;this.separator=false;this.init();if(N.subMenu){new F.Menu(this,N.subMenu,M)}}});F.extend(F.MenuItem,{prototype:{init:function(){var O,N,P=this.src,M=this;this.$eLI=F(K.cloneNode(1));if(this.addClass){this.$eLI[0].setAttribute("class",this.addClass)}if(this.settings.addExpando&&this.data){this.$eLI[0].menuData=this.data}if(P==""){this.$eLI.addClass("menu-separator");this.separator=true}else{N=typeof P=="string";if(N&&this.url){P=F("<a href=\""+this.url+"\""+(this.urlTarget?"target=\""+this.urlTarget+"\"":"")+">"+P+"</a>")}else{if(N||!P.length){P=[P]}}for(O=0;O<P.length;O++){if(typeof P[O]=="string"){elem=document.createElement("span");elem.innerHTML=P[O];this.$eLI[0].firstChild.appendChild(elem)}else{this.$eLI[0].firstChild.appendChild(P[O].cloneNode(1))}}}this.$eLI.click(function(Q){M.click(Q,this)});this.bindHover()},click:function(N,M){if(this.enabled&&this.settings.onClick){this.settings.onClick.call(M,N,this)}},bindHover:function(){var M=this;this.$eLI.hover(function(){M.hoverIn()},function(){M.hoverOut()})},hoverIn:function(N){this.removeTimer();var O,Q=this.parentMenu.subMenus,P=this.parentMenu.menuItems,M=this;if(this.parentMenu.timer){this.parentMenu.removeTimer()}if(!this.enabled){return }for(O=0;O<P.length;O++){if(P[O].active){P[O].setInactive()}}this.setActive();J=this.parentMenu;for(O=0;O<Q.length;O++){if(Q[O].visible&&Q[O]!=this.subMenu&&!Q[O].timer){Q[O].addTimer(function(){this.hide()},Q[O].settings.hideDelay)}}if(this.subMenu&&!N){this.subMenu.addTimer(function(){this.show()},this.subMenu.settings.showDelay)}},hoverOut:function(){this.removeTimer();if(!this.enabled){return }if(!this.subMenu||!this.subMenu.visible){this.setInactive()}},removeTimer:function(){if(this.subMenu){this.subMenu.removeTimer()}},setActive:function(){this.active=true;this.$eLI.addClass("active");var M=this.parentMenu.parentMenuItem;if(M&&!M.active){M.setActive()}activeItem=this},setInactive:function(){this.active=false;this.$eLI.removeClass("active");if(this==activeItem){activeItem=null}},enable:function(){this.$eLI.removeClass("disabled");this.enabled=true},disable:function(){this.$eLI.addClass("disabled");this.enabled=false},destroy:function(){this.removeTimer();this.$eLI.remove();this.$eLI.unbind("mouseover").unbind("mouseout").unbind("click");if(this.subMenu){this.subMenu.destroy();delete this.subMenu}this.parentMenu.removeItem(this)},addSubMenu:function(N){if(this.subMenu){return }this.subMenu=N;if(this.parentMenu&&F.inArray(N,this.parentMenu.subMenus)==-1){this.parentMenu.subMenus.push(N)}if(this.settings.arrowSrc){var M=I.cloneNode(0);M.setAttribute("src",this.settings.arrowSrc);this.$eLI[0].firstChild.appendChild(M)}}}});F.extend(F.fn,{menuFromElement:function(N,P,O){var M=function(X){var T=[],V,S,a,Y,U,Z,R,W,Q=null;a=G(X,"LI");for(U=0;U<a.length;U++){V=[];if(!a[U].childNodes.length){T.push(new F.MenuItem("",N));continue}if((Z=A(a[U],"UL"))){V=M(Z);F(Z).remove()}Y=F(a[U]);if(Y[0].childNodes.length==1&&Y[0].childNodes[0].nodeType==3){W=Y[0].childNodes[0].nodeValue}else{W=Y[0].childNodes}if(N&&N.copyClassAttr){Q=Y.attr("class")}S=new F.MenuItem({src:W,addClass:Q},N);T.push(S);if(V.length){new F.Menu(S,V,N)}}return T};return this.each(function(){var R,Q;if(P||(R=A(this,"UL"))){R=P?F(P).clone(true)[0]:R;menuItems=M(R);if(menuItems.length){Q=new F.Menu(this,menuItems,N);if(O){O.addMenu(Q)}}F(R).hide()}})},menuBarFromUL:function(M){return this.each(function(){var O,N=G(this,"LI");if(N.length){bar=new F.MenuCollection();for(O=0;O<N.length;O++){F(N[O]).menuFromElement(M,null,bar)}}})},menu:function(N,M){return this.each(function(){if(M&&M.constructor==Array){new F.Menu(this,M,N)}else{if(this.nodeName.toUpperCase()=="UL"){F(this).menuBarFromUL(N)}else{F(this).menuFromElement(N,M)}}})}});var A=function(N,M){if(!N){return null}var O=N.firstChild;for(;O;O=O.nextSibling){if(O.nodeType==1&&O.nodeName.toUpperCase()==M){return O}}return null};var G=function(O,M){if(!O){return[]}var N=[],P=O.firstChild;for(;P;P=P.nextSibling){if(P.nodeType==1&&P.nodeName.toUpperCase()==M){N[N.length]=P}}return N}})(jQuery);


/*
** movies.js
**
** movie page related javascript for the clerkdogs application.
**
*/
;(function($){
	
	
	/* 
	** movieslider
	**
	** slider functionality for the clerkdogs application.  We will convert the non-js sliders
	** into javascript aware sliders.
	**
	** the expected non javascript format is like so:
	** 
	** <div class='slider'>
	**  <div class='slider_containment'>
	**   <div class='slider_bar bar_size_7'>
	**    <p>Dry Humor</p>
	**   </div>
	**  </div>
	**  <input id='slider_25' type='text' value='7' name='slider[25]'>
	** </div>
	**
	** Required: jquery.js, jquery-ui.js, jquery.menu.js
	**
	** We use the slider plugin from jquery-ui for most of the slider functionality.
	*/
	$.fn.movieslider = function(settings) {
		
		// add only if we need settings
		if( settings ) $.extend( $.fn.movieslider.settings, settings );  
		
		this.each( function() {
			
			/* 
				let's setup the initial view and attach some attributes to slider.
				we want to make not to create the ui if its already there.
			*/
			var _slider = createMovieSlider( this, settings );
			
			
			/*
				sets the current value to the new value supplied,
				and stores the previous current value in the previous
				value.
			*/
			_slider.setCurrentValue = function( value ) {
				_slider.previous_value = _slider.current_value;
				_slider.current_value  = value;				
			};
			
			/*
				updates the slider view and value, if the given value
				is different from the current_value.
				
				issues a $.fn.movieslider.valueChanged callback.
			*/
			_slider.update = function( value ) {
				if ( value != _slider.current_value ) {
					_slider.updateView( value );
					_slider.setCurrentValue( value );
					if ( !_slider.active ) {
						_slider.makeActive();
						if (_slider.onActiveAfterUpdate) _slider.onActiveAfterUpdate.call( _slider );
					}
					if ( _slider.onValueChange ) _slider.onValueChange.call( _slider );					
				}
			};
		
			
			/* 
			** resets the slider, this is a different process then updating the 
			** the slider value. 
			*/
			_slider.reset = function( value ) {
				if ( value != _slider.current_value ) {
					_slider.updateView( value );
					_slider.setCurrentValue( value );
					if ( _slider.onValueReset ) _slider.onValueReset.call( _slider );
				}
			};
			
			/* 
				insertAt - inserts the slider at the given position.  used by the
				history redo.  the default is to do nothing.  if there is a callback
				defined for 'onInsertAt' then that method is called with the slider
				and position.
			*/
			_slider.insertAt = function( position ) {
				if ( _slider.onInsertAt ) _slider.onInsertAt.call( _slider, position );
			};
			
			/*
				removeAt - removes teh slider at the given position. the default is
				not to do anything, only a callback is issued.
			*/
			_slider.removeAt = function( position ) {
				if ( _slider.onRemoveAt ) _slider.onRemoveAt.call( _slider, position );
			};
			
			/*
			** updates the view only with give value
			*/
			_slider.updateView = function( value ) {
				updateSliderBar( _slider.view.slider_bar, value );
			};
			
			
			/* when we are sliding, we need to update the ui.  We need
			   to reposition the handle, and we need to update the bar
			   size.
			*/
			_slider.slide = function( e, ui ) {
				var originalTarget = e.originalEvent.target;
				if( $(originalTarget).hasClass( $.fn.traitselectbox.settings.menuLinkClass )  ) {
					// the menu item is being clicked, so return false ( we don't want to slide )
					return false;
				} else {
					_slider.updateView( ui.value );
				}
			};
			
			// ok, if the value has been changed, then we need to
			// submit the ajax request to update the movie view,
			// and we need to fire an event to alert any classes,
			// watching us that we've been updated.			
			_slider.stop = function ( e, ui ) {
				_slider.update( ui.value );
			};
			
			/*
				just update the trait menu with the new trait id. also sets the 
				current_trait_id to the new_trait_id and the previous_trait_id 
				to previous_trait_id.
				
				There's no callback.
			*/
			_slider.updateTrait = function( new_trait_id, previous_trait_id ) {
				_slider.view.traits_select.val( new_trait_id );
				_slider.current_trait_id = new_trait_id;
				_slider.previous_trait_id = previous_trait_id;				
			};
			
			_slider.updateMenuLabel = function( new_trait_id ) {
				var value = _slider.view.traits_select.find("option:selected").text();
				_slider.find('.menu span').text( value );
			};
			
			/*
				this gets called if the trait menu is available and a customer changes
				the value via the menu
			*/
			_slider.handleTraitChanged = function( new_trait_id, previous_trait_id ) {
				_slider.updateTrait( new_trait_id, previous_trait_id );
				if ( !_slider.active ) {
					_slider.makeActive();
					if (_slider.onActiveAfterUpdate) _slider.onActiveAfterUpdate.call( _slider );
				}
				if (_slider.onTraitChange) _slider.onTraitChange.call( _slider );
			};
			
			_slider.resetTrait = function( new_trait_id, previous_trait_id) {
				_slider.updateTrait( new_trait_id, previous_trait_id );
				_slider.updateMenuLabel( new_trait_id );
				if ( _slider.onTraitReset ) _slider.onTraitReset.call( _slider, new_trait_id, previous_trait_id );
			};
			
			/*
				responsible for handling the clicking on the remove link.
			*/
			_slider.handleRemoveLink = function( event ) {
				if ( _slider.onRemoveLink ) _slider.onRemoveLink.call( _slider );					
				event.preventDefault();
				event.stopPropagation();
			};
			
			_slider.makeActive = function() {
				_slider.active = true;				
				_slider.css( {'opacity':'1.0'} );
				_slider.view.active_input.removeClass( 'active' ).addClass( 'deactive' );				
			};
			_slider.makeInactive = function() {
				_slider.active = false;
				_slider.css( {'opacity':'0.5'});
				_slider.view.active_input.removeClass( 'deactive' ).addClass( 'active' );

			};
			_slider.deactivate = function() {
				_slider.makeInactive();
				if ( _slider.onDeacivation ) _slider.onDeacivation.call( _slider );
			};
			_slider.activate = function() {
				_slider.makeActive();
				if ( _slider.onActivation ) _slider.onActivation.call( _slider );	
			};
			
			/*
				responsible for handling the clicking of the active input (checkbox)
			*/
			_slider.handleActiveLink = function( event ) {
				_slider.active ? _slider.deactivate() : _slider.activate();
				event.stopPropagation();
				event.preventDefault();
			};
			
			/*
				responsible for reseting the ui, gets called on initial setup and
				when a slider gets inserted into the document.
			*/
			_slider.resetUI = function() {
				
				_slider.view.menu_link.show(); // show menu link
				_slider.updateMenuLabel( _slider.current_trait_id );
				_slider.updateView( _slider.current_value );

				// set the view marker, only gets set once.
				updateMarker( _slider.view.marker, _slider.current_value );
				//_slider.view.marker.addClass('bar_marker_' + _slider.current_value);
				

				// if we can remove slider, then add the $.fn.movieslider.settings.removeClass, otherwise
				// hide the control.
				if (_slider.canRemove) {
					_slider.view.remove_link.addClass( $.fn.movieslider.settings.removeClass );
				} else {
					_slider.view.remove_link.hide(); // we don't want to show it, if we can't remove
				}

				// if we can deactivate, then add the $.fn.movieslider.settings.deactivateClass and 
				// make slider active/deactive.
				if ( _slider.canDeactivate ) {
					_slider.view.active_input.addClass( $.fn.movieslider.settings.deactivateClass );
					
					if( _slider.active ) {
						_slider.makeActive();
					} else {
						_slider.makeInactive();
					}
				} 

			};
			
			/* attach the slider code, the slider is a built jquery ui control */
			_slider.view.slider_containment.slider({
				handler: '.slider_handle', 
				min: 0, 
				max: 11,
				value: _slider.current_value,
				stop: _slider.stop,
				slide: _slider.slide
			});
			
			
			/* activate the trait select box, and other controls */
			_slider.resetUI();
			_slider.find("select." + $.fn.movieslider.settings.traitSelectClass).traitselectbox({ onChange: _slider.handleTraitChanged });
			if( _slider.canRemove ) _slider.view.remove_link.click( _slider.handleRemoveLink );
			if( _slider.canDeactivate ) _slider.view.active_input.click( _slider.handleActiveLink );
			
			// we are done initializing, lets notify anyone that wants to be notified.
			if ( _slider.onInitialization ) _slider.onInitialization.call( _slider );
		});
	};
	
	/* 
	   responsible for building the graphic version of the slider.
		
		 the default behavior, expects the original slider element to have
		 a class name of 'simple_slider', which this method removes and adds
		 a class name of 'slider'.
		
		 this method also collects all the select options and hides the select
		 input.  we are going to handle the menu via javascript.
	*/
	$.fn.movieslider.createUI = function( slider ) {
		// change the class name and add basic elements for slider
		slider.removeClass( 'simple_slider_active' );
		slider.removeClass( 'simple_slider_deactive' );
		slider.removeClass( 'simple_slider' ).addClass( $.fn.movieslider.settings.sliderClass );
		
		// add extra slider containment controls, handle and marker.
		slider_containment = slider.find('.slider_containment');	
		has_ui = (slider_containment.find( '.slider_handle' ) || slider_containment.find('.marker') ).length == 0 ? false : true;
		if ( !has_ui ) {
			slider_containment.append("<div class='marker'></div>");
			slider_containment.append("<div class='slider_handle'></div>");
			
			// replace the value text input with a select input
			var current_value_input = slider.find('input.value');
			var current_value       = current_value_input.val();
			var current_value_name  = $(current_value_input).attr("name");
			
			current_value_input.replaceWith( $.fn.movieslider.createValueSelect( current_value_name, current_value ) );
			
			// add activate/deactivate button
			if ( slider.canDeactivate ) {
				slider.after("<input class='active' type='submit' name='value'/>");
			}
		}
		
	};
	
	$.fn.movieslider.createValueSelect = function(name, value) {
		var ui = "<select name='" + name + "' class='" + $.fn.movieslider.settings.valueSelectClass +"'>";
		$(["", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"]).each( function() {
			ui += "<option value='" + this + "'";
			if ( this == value ) {
				ui += " selected='selected'";
			}
			ui += ">" + this + "</option>";
		});
		ui += "</select>";
		return ui;
	};
	
	/*
		 this is called when the value has changed.  if a user moves the slider but
		 ends up at the same value this event is NOT triggered.
		
		 the slider (jquery.slider element), slider unique id (see $.fn.movieslider.findSliderId), the
		 old value, and the new value.
	*/
	$.fn.movieslider.valueChanged = function( slider, slider_id, old_value, new_value ) {
		if (console) {
			if ( slider_id ) {
				console.log( "slider: " + slider_id + " changed from: " + old_value + " to: " + new_value );
			} else {
				console.log( "changed from: " + old_value + " to: " + new_value );
			}
		}
	};
	
	/*
			this gets called when the value is undone method is called.  this is useful for undo, redo
			actions.
	*/
	$.fn.movieslider.resetValue = function( slider, slider_id, old_value, new_value ) {
		if (console) {
			console.log("we are reseting to: " + new_value + " from: " + old_value);
		}
	};
	
	/* 
		 find the id that makes the slider unique, this is passed into
	   the valueChanged method. This allows for multiple sliders on 
	   a page, and to determine which on changed.
	
	   the default behavior is to look for a text input, and get the name
	   of the input.
	*/
	$.fn.movieslider.findSliderId = function( slider ) {
		if ( slider ) {
			return $(slider).find("select." + $.fn.movieslider.settings.valueSelectClass).attr("name");
		}
	};
	
	
	/* 
	** $.fn.movieslider.settings 
	**
	** the only real setting at this time, is the amount of pixels
	** to update the slider handle.
	**
	*/
	$.extend( $.fn.movieslider, {
		settings: {
			handleIncrement: 13.5,
			traitSelectClass: 'traits-select',
			valueSelectClass: 'values-select',
			sliderClass: 'slider',
			defaultSliderValue: 8,
			canDeactivate: true,  			// can deactivate/activate slider
			canRemove: true,						// can remove/add slider
			deactivateClass: 'movieslider_deactivate',  // the class that gets added to the deactivate control
			removeClass: 'movieslider_remove' 					// the class that gets added to the remove control 
		}
	});
	
	/** PRIVATE **/
	
	/*
		this is responsible for creating and initializing the
		movie slider from the given dom element and settings.
		
		the new movie slider is returned.
	*/
	function createMovieSlider( element, settings ) {
		var slider = $(element);
		
		/* setup local variables for current _slider from settings */
		slider.onTraitChange 				= null;
		slider.onTraitReset					= null;
		slider.onValueChange 				= null;
		slider.onValueReset  				= null;
		slider.onRemoveLink  				= null;
		slider.onInsertAt    				= null;
		slider.onRemoveAt						= null;
		slider.onInitialization 		= null;
		slider.onDeacivation    		= null;
		slider.onActivation					= null;
		slider.onActiveAfterUpdate 	= null; // this is when the slider becomes active from some other action then explicit active.
		if ( settings ) {
			// TODO: should get from $.fn.movieslider.settings instead of settings, since $.fn.movieslider.settings gets extended.
			slider.onTraitChange 				= settings.onTraitChange;
			slider.onTraitReset					= settings.onTraitReset;
			slider.onValueChange 				= settings.onValueChange;
			slider.onValueReset  				= settings.onValueReset;
			slider.onRemoveLink  				= settings.onRemoveLink;
			slider.onInsertAt 	 				= settings.onInsertAt;
			slider.onRemoveAt						= settings.onRemoveAt;
			slider.onInitialization 		= settings.onInitialization;
			slider.onDeacivation    		= settings.onDeacivation;
			slider.onActivation					= settings.onActivation;
			slider.onActiveAfterUpdate 	= settings.onActiveAfterUpdate;
		} 
		
		
		/* general settings */
		slider.canDeactivate = $.fn.movieslider.settings.canDeactivate;
		slider.canRemove		 = $.fn.movieslider.settings.canRemove;

		/* setup the initial slider ui */
		$.fn.movieslider.createUI( slider );
		
		/* get the unique slider id */
		slider.slider_id = $.fn.movieslider.findSliderId( slider );

		/* get initial controls, and association with slider.view */
		$.extend( slider, {
			view: {
				traits_select: slider.find( "select." + $.fn.movieslider.settings.traitSelectClass ),
				values_select: slider.find( "select." + $.fn.movieslider.settings.valueSelectClass )				
			}
		});

		/* lets get current input value, and hide the input field */
		slider.current_value        	= slider.view.values_select.hide().val();
		
		var active									= settings.active;
		if ( !active ) active = slider.current_value != "" ? true : false;
		slider.active 							= active;
		
		
		// lets set the default, after the inactive/active has been figured out.
		slider.default_value        	= slider.find('input[type=hidden][name="default_value"]').val();
	  if ( !slider.default_value ) 	slider.default_value = $.fn.movieslider.settings.defaultSliderValue;		
		if (slider.current_value.length == 0) slider.current_value = slider.default_value ;
		slider.previous_value 			= null;
		slider.current_trait_id 		= slider.view.traits_select.val();
		slider.previous_trait_id 		= null;
		
		/* lets obtain handles to the newly created ui items */
		var slider_containment = $(slider).find('.slider_containment');
		$.extend( slider.view, {
				slider_containment: slider_containment,
				slider_handle: slider_containment.find(".slider_handle"),
				slider_bar: slider_containment.find(".slider_bar"),
				marker: slider_containment.find( ".marker" ),
				remove_link: slider.find('input.remove'),
				active_input: slider.next('input.active'),
				menu_link: slider_containment.find("a.menu-link")
		});
		
		/* now lets set some initial values, shall we */
		/* now that we have the slider handle, lets place it in its current spot on the screen */
		// slider.leftPosition         = slider.view.slider_handle.position().left;
		slider.leftPosition = slider.position().left + 13;
		
		// var startingPosition 	= (_mostLeftPosition) + (_value * _increment);
		slider.handlePosition  = getPositionForValue( slider.leftPosition, slider.current_value );

		return slider;
	};
	
		
	/*
		gets the position for the initial position and value.  since the slider
		doesn't really start with a value of 0 for left, the initial position 
		is the initial left position.  value is a number between 0 to 10.
	*/
	function getPositionForValue( initial_position, value ) {
		return (initial_position) + (value * $.fn.movieslider.settings.handleIncrement);
	};
	
	/*
		responsible for updating the bar_size_xx class name based on the new
		value.  the old class name is removed and the new class name is applied.
	*/
	function updateSliderBar( bar, value ) {
		var current_bar_size_class;
		if( bar.length > 0 ){
			$( bar.attr('class').split(" ") ).each( function() {
				if ( match = this.match( /^bar_size_[0-9]+$/) ) {
					current_bar_size_class = match;
				}
			});
			bar.removeClass( current_bar_size_class ).addClass( "bar_size_" + value );
			
			var current_handle_size_class = current_bar_size_class.toString().replace("bar_size_", "bar_handle_");
			handle = bar.siblings('.slider_handle');
			handle.removeClass( current_handle_size_class ).addClass( "bar_handle_" + value );
			
			// let's update the slider handle, based on the current bar setting.
			// 
			// var handle_left = currentSliderBarPosition( bar ) -	( handle.width()/2 );
			// handle.css({'left': handle_left + 'px'});
		}		
	};
	
	function updateMarker( marker, value ) {
		var current_marker_size_class;
		if ( marker.length > 0 ) {
			$( marker.attr('class').split(" ") ).each( function() {
				if ( match = this.match( /^bar_marker_[0-9]+$/) ) {
					current_marker_size_class = match;
					
				}
			});
			// only remove if we find a current marker class
			if ( current_marker_size_class ) {
				marker.removeClass( current_marker_size_class );	
			} 
			marker.addClass( "bar_marker_" + value );	
		}
	};
	
	/*
		gets the current right position of the given 
		slider bar.
	*/
	function currentSliderBarPosition(slider_bar) {
		var left 	= slider_bar.position().left;
		var width = slider_bar.width();
		return left + width;		
	};
	
	/* selectbox
	**
	** handles the managing of the select drop down box, for the slider.
	** tried to use a plugin, but it wasn't playing nice.
	**
	*/
	$.fn.traitselectbox = function(settings) {

		
		this.each( function() {
			
			// get a handle on the select element 
			var _select = $(this);
			var _options = $(this).find('option');
			var _current_selection = $(this).find('option:selected');
			var _current_trait_id = _current_selection.val();
			var _current_label    = _current_selection.text();
       
			var _onChange          = null;
			if ( settings ) {
				_onChange = settings.onChange;
			}
			
			// hide the input, we are making our own ui :)
			_select.hide();
			
			_select.createMenuItems = function() {
				items = [];
				_options.each( function() {
					var trait_id = $(this).val();
					var label    = $(this).text();
					var options  = { src: label, data: trait_id };
					items.push( options );
				});
				return items;
			};
			var _menu_items = _select.createMenuItems();
			
			_select.createUI = function() {
				ui = "<div class='" + $.fn.traitselectbox.settings.menuClass + "'><span>" + _current_label + "</span>";
				ui += "<a href='#' class='" + $.fn.traitselectbox.settings.menuLinkClass + "'></a>";
				//ui += _select.createMenuItems();
				ui += "</div>";
				_select.before( ui );
			};
			// lets create the menu label and icon
			has_ui = _select.prev('.' + $.fn.traitselectbox.settings.menuClass ).length == 0 ? false : true;
			if ( !has_ui ) _select.createUI();

			var _menu 			= _select.prev( "." + $.fn.traitselectbox.settings.menuClass );
			var _menu_link 	= _menu.find("a." + $.fn.traitselectbox.settings.menuLinkClass );
			
			/*
				responsible for updating the slider trait attribute,
				if the supplied trait id is different from the 
				_current_trait_id.
			*/
			_select.updateTrait = function( trait_id, label ) {
				// only update if the trait id has been changed.
				if ( trait_id != _current_trait_id ) {
					_select.find("option:select").removeAttr("selected");
					_select.find( "option" ).each( function() {
						var option = $(this);
						var value  = option.val();
						if ( value == trait_id ) {
							option.attr( 'selected', 'selected' );
						}
					});
					if (_onChange) _onChange( trait_id, _current_trait_id );
					_menu.find("span").text( label );
					_current_trait_id = trait_id;
					_current_label    = label;
				}
			};
			
			
			/*
				responsible for handling the selection of a menu
				item, from the popup menu.
			*/
			_select.handleMenuItemSelect = function( e, item ) {
				var menu = item.parentMenu;
				if ( menu ) menu.hide();
				var trait_id = item.data;
				var label    = item.src;
				_select.updateTrait( trait_id, label );
			};
			
			/*
				responsible for setting the correct active menu item
				when the menu is opened.
			*/
			_select.handleMenuOpen = function() {
				var menu = this;  // the menu 
				_current_trait_id = _select.find("option:selected").val(); // just incase we change outside of the traitselect class.
				$( menu.menuItems ).each( function() {
					var menu_item = this;
					var page_element = $(menu_item.$eLI);
					if ( menu_item.data == _current_trait_id ) {
						page_element.addClass( $.fn.traitselectbox.settings.selectedMenuItemClass );
					} else {
						page_element.removeClass( $.fn.traitselectbox.settings.selectedMenuItemClass );
					}
				});
			};
			

			
			/* 
				let's create the menu.
				
				The menu is handled by jquery.menu.js (see http://p.sohei.org/stuff/jquery/menu/demo/demo.html)
			*/
			$(_menu_link).menu( {
				offsetLeft: -140,
				onClick: _select.handleMenuItemSelect,
				onOpen: _select.handleMenuOpen
			}, _menu_items );
			
		});
		
		
	};
	
	/* 
	** $.fn.traitselectbox.settings
	**
	*/
	$.extend( $.fn.traitselectbox, {
		settings: {
			menuClass: 'menu',
			menuLinkClass: 'menu-link',
			selectedMenuItemClass: 'selected'
		}
	} );

})(jQuery);

/* 
** sliderhistory
**
** responsible for keeping track of the slider history, and reverting the slider to
** a previous state.
*/
var SliderHistory = function(options) {
	_queue 			= new Array;
	_iteration 	= 0;
  _self				= this;

	// lets setup the undo/redo controls.
	_undo       = options.undo_control;
	_redo				= options.redo_control;
	$(_undo).click( this.undo );
	$(_redo).click( this.redo );
	
	return this;
};
SliderHistory.prototype = {
	add: function( slider, action, data ) {
		if ( _iteration != _queue.length ) {
			_queue = _queue.splice(0, _iteration);
		}
		_queue.push( {slider: slider, action: action, data: data} );
		_iteration += 1; 
		_self.updateControls();
	},
	undo: function(event) {
		var item = _queue[(_iteration-1)];
		if ( item && item.slider ) {
			if ( item.action == 'changedvalue' ) {
				item.slider.reset( item.data.from );
			}
			else if ( item.action == 'changedtrait' ) {
				item.slider.resetTrait( item.data.from, item.data.to );
			}
			else if ( item.action == 'added' ) {
				item.slider.removeAt( item.data.position );
			}
			else if ( item.action == 'removed' ) {
				item.slider.insertAt( item.data.position );
			}
			else if ( item.action == 'activated' ) {
				item.slider.deactivate();
			} else if ( item.action == 'deactivated' ) {
				item.slider.activate();
			}
		}
		_iteration -= 1;
		_self.updateControls();
		event.preventDefault();
		event.stopPropagation();
	},
	redo: function(event) {
		var item = _queue[(_iteration)];
		if ( item && item.slider ) {
			if ( item.action == 'changedvalue' ) {
				item.slider.reset( item.data.to );
			}
			else if ( item.action == 'changedtrait' ) {
				item.slider.resetTrait( item.data.to, item.data.from );
			}
			else if ( item.action == 'added' ) {
				item.slider.insertAt( item.data.position );
			}
			else if ( item.action == 'removed' ) {
				item.slider.removeAt( item.data.position );
			} 
			else if ( item.action == 'activated' ) {
				item.slider.activate();
			} else if ( item.action == 'deactivated' ) {
				item.slider.deactivate();
			}			
		}
		_iteration += 1;
		_self.updateControls();
		event.preventDefault();
		event.stopPropagation();
	},
	updateControls: function() {
		if( _iteration > 0 ) {
			if( $(_undo).hasClass( "disabled") ) {
				$(_undo).removeClass("disabled").addClass("active");		
			}
		} else {
			if ( $(_undo).hasClass("active") ) {
				$(_undo).removeClass("active").addClass( "disabled" );
			}
		}
		if( _queue.length > 0 ) {
			if ( _iteration < _queue.length ) {
				if ( $(_redo).hasClass( "disabled") ) {
					$(_redo).removeClass("disabled").addClass("active");
				}
			} else {
				if ( $(_redo).hasClass("active") ) {
					$(_redo).removeClass("active").addClass("disabled");
				}
			}
		}
	}
};

/*
** mashit.js
**
** this javascripts get loaded by the movie mash it and supermatch page.  the core of the functionality comes
** from the movieslider, see movie.js (which needs to be loaded before this file).
**
**
*/
;(function($){

	/*  mashit
	**
	**  responsible for managing the mashit controls on the mash_it page.  usage:
	**
	**  $('form#mash_it').mashit();
	*/
	$.fn.mashit = function( settings ) {
		
		// add only if we need settings
		if( settings ) $.extend( $.fn.mashit.settings, settings );  		
		
		this.each( function() {
			// TODO: _mashit should be local variables and not global, but lets
			// change that later.  this works for now, since there is only one
			// mashit on the page.
			
			// lets get a handle on the form the mashit was attached to.
			_mashit 					= $(this);

			_mashit.sliders   = new Array;

			// sets the maximum number of sliders allowed.
			_mashit.max_sliders = $.fn.mashit.settings.maxNumberOfSliders;
			_mashit.next_slider_position = _mashit.max_sliders; 

			// lets hide "Mash It!" button, not need for javascript
			_mashit.find(".ending_controls .button").hide();
			
			// lets setup the history, if we need to.
			// we check to see if there are .previous and .next anchors contained in the form.
			previous_link = _mashit.find('.previous')[0];
			next_link     = _mashit.find('.next')[0];
			
			_mashit.add_attribute = _mashit.find('.add_attribute');
			_mashit.add_attribute.css( {width: '202px'} );
			_mashit.add_input			= _mashit.add_attribute.find("input.add");
			_mashit.genre_input		= _mashit.find("#genre_id");
			
			_mashit.canDeactivate = $.fn.mashit.settings.canDeactivate;
			_mashit.canRemove     = $.fn.mashit.settings.canRemove;
			
			/*
				update controls, responsible for taking the current state of
				the mashit control and updating the view.  For example, if
				a customer removes an attribute, then we need to make sure
				there's an add new attribute link. or if we have a the maximum
				number of sliders, then we hide the add attribute control.
			*/
			_mashit.updateControls = function() {
				var sliders = _mashit.find('.slider');
				if ( sliders.length < _mashit.max_sliders ) {
					_mashit.add_attribute.show();
				} else {
					_mashit.add_attribute.hide();
				}
			};
			
			/* 
			  handles the value change for a slider.
			*/
			_mashit.handleValueChange = function() {
				var slider = this;
				$.fn.mashit.sliderChanged( slider );
			};
			
			/*
				handles the value reset for a slider.
			*/
			_mashit.handleValueReset = function() {
				var slider = this;
				$.fn.mashit.sliderReset( slider );
			};
			
			/*
				handles the trait change.  we don't really need to anything with the slider, represented as "this".
				we just want to submit form.
			*/
			_mashit.handleTraitChange = function() {
				var slider = this;
				$.fn.mashit.traitChanged( slider );
			};
			
			/*
				handles when the trait gets resetted.
			*/	
			_mashit.handleTraitReset = function(to_trait_id, from_trait_id) {
				var slider = this;
				$.fn.mashit.traitReset( slider, to_trait_id, from_trait_id );
			};
			
			/*
				gets called when the trait is removed.
			*/
			_mashit.handleTraitRemoved = function() {
				var slider = this;
				$.fn.mashit.traitRemoved( slider );
			};
			
			/*
				handleSliderInsertAt - gets called when the slider is asked to insert itself
				at supplied position.
			*/
			_mashit.handleSliderInsertAt = function( position ) {
				var slider = this;
				$.fn.mashit.sliderInsertAt( slider, position );
			};
			
			_mashit.handleSliderRemovedAt = function( position ) {
				var slider = this;
				$.fn.mashit.sliderRemovedAt( slider, position );
			};
			
			/*
				gets the currently selected traits, among all sliders
			*/
			_mashit.selectedTraits = function() {
				var selectedTraits = [];
				_mashit.find( "." + $.fn.mashit.settings.traitSelectClass + " option:selected" ).each( function() {
					var option = $(this);
					selectedTraits.push(option.val().toString());
				});
				var sliderOrderTraits = [];
				// TODO: need to add any in the slider_order, we don't want to add.
				var sliderOrderValues = _mashit.find( "#sliders_order").val().toString().replace(/\s/g, '').split(",");
				$(sliderOrderValues).each( function() {
					sliderOrderTraits.push( this.toString() );
				});
				return $.merge( selectedTraits, sliderOrderTraits );
			};
			
			_mashit.addSlider = function( slider ) {
				// TODO: we might need to make sure we don't add duplicates.
				_mashit.sliders.push( slider );
			};
			
			_mashit.removeSlider = function( slider ) {
				// TODO: iterate through all the sliders, and find the given slider.
				// if found remove it.
			};
			
			_mashit.setSliderValue = function( slider, value ) {
					slider.find('.' + $.fn.mashit.settings.valueSelectClass ).val( value );
			};
			
			/*
				responsible for deactivating all the other sliders.  we 
				want only one slider active at a time.
			*/
			_mashit.deactivateAllSlidersExcept = function( slider ) {
				$(_mashit.sliders).each( function() {
					if ( this.slider_id != slider.slider_id ) {
						if ( this.active ) {
							this.makeInactive();
							_mashit.setSliderValue( this, "" );
						}
					}
				});
			};
			
			
			_mashit.handleSliderActiveAfterUpdate = function() {
				var slider = this;
				_mashit.deactivateAllSlidersExcept( slider );
			};
			
			/*
				handles the case where the slider is deactivated.
			*/
			_mashit.handleSliderDeactivated = function() {
				var slider = this;
				$.fn.mashit.sliderDeactivated( slider );
			};
			
			/*
				handles the case where the slider is activated.
			*/
			_mashit.handleSliderActivated = function() {
				var slider = this;
				$.fn.mashit.sliderActivated( slider );
			};
			
			/*
				handleAddAttribute - handles customer clicks on the add input.
			*/
			_mashit.handleAddAttribute = function(event) {
				// Clone an existing slider -- NOTE: what happens when we have no sliders (do we even allow it).
				var last_slider = $('.sliders .slider:last');

				var clone_slider = last_slider.clone();
				last_slider.after( "<div class='" + $.fn.mashit.settings.sliderClass + "'></div>" );

				var element = last_slider.next("." + $.fn.mashit.settings.sliderClass );
				element.html( clone_slider.html() );
				
				var current_trait_id 	= null;
				var selected_traits 	= _mashit.selectedTraits();
				for( key in _mashit.availableTraits ) {
					if( $.inArray( key.toString(), selected_traits ) == -1 ) {
						current_trait_id = key;
						break;
					}
				}
				
				// let's update the select fields for traits and values.
				var name     = null;
				var position = _mashit.next_slider_position;
				var trait_select = element.find('.' + $.fn.mashit.settings.traitSelectClass );
				trait_select.val( current_trait_id );
				name = trait_select.attr('name').replace(/[0-9]+/, position);
				trait_select.attr( 'name', name );
				
				var value_select = element.find('.' + $.fn.mashit.settings.valueSelectClass );
				value_select.val( $.fn.mashit.settings.defaultSliderValue );
				name = value_select.attr('name').replace(/[0-9]+/, position);
				value_select.attr( 'name', name );
				value_select.attr( 'name', name );

				// lets update the remove link
				var remove_link = element.find("input.remove");
				name = remove_link.val().replace(/[0-9]+/, current_trait_id );
				remove_link.val( name );

				var new_slider = null;
				var options = {
					onInitialization: function() {
						new_slider = this;
					},
					active: true
				};
				$.extend( options, $.fn.mashit.sliderOptions() );
				element.movieslider( options );		
				_mashit.addSlider( new_slider );
				
				_mashit.next_slider_position += 1;
				
				submitForm( {
					slider: new_slider,
					onSuccess: $.fn.mashit.handleAddAttributeSuccess
				});
				
				event.preventDefault();
				event.stopPropagation();
			};
			
			_mashit.handleGenreChange = function(event) {
				submitForm();
				event.stopPropagation();
			};
			
			_mashit.clearSettings = function(event) {
				window.location = _mashit.clear_setting_url;
				return false;
			};
			
			_mashit.handleClearSettings = function(event) {
				$.facebox( $.fn.mashit.clearSettingsPopup() );
				$('#facebox button.clear_settings').click( _mashit.clearSettings );
				return false;
			};
			
			
			/*
				if we have previous and next link, then we need to keep track of history.
			*/
			if ( previous_link && next_link ) {
				_history						= new SliderHistory({undo_control: previous_link, redo_control: next_link});	
			}
		
			// lets setup the sliders
			var slider = null;
			var options = {onInitialization: function() { _mashit.addSlider( this ); }};
			$.extend( options, $.fn.mashit.sliderOptions() );
			_mashit.find(".simple_slider").movieslider( options );

						
			_mashit.availableTraits = {};
			_mashit.find( "." + $.fn.mashit.settings.traitSelectClass + " option" ).each( function() {
				var option = $(this);
				if ( option.val().length != 0 ){ // we don't want any blank values, such as "-" or "choose a value..."
					_mashit.availableTraits[ option.val() ] = option.text();	
				}
			});
			
			// if clear settings button, attach handleClearSettings.
			var clear_settings_span = _mashit.find('span.clear_settings');
			_mashit.clear_setting_url = clear_settings_span.find('a').attr('href');
			clear_settings_span.click( _mashit.handleClearSettings );
			
			// bind any events
			_mashit.add_input.click( _mashit.handleAddAttribute );
			_mashit.genre_input.change( _mashit.handleGenreChange );
			
		});
		
		_mashit.handleError = function( html ) {
			_mashit.find('.header').append( html );
		};
		
		
	};
	
	/*
		represents the slider ui
	*/
	$.fn.mashit.sliderUI = function() {
		var ui = "<div class='simple_slider simple_slider_active'>";
		ui += "<div class='slider_containment'>";
		
		// menu
		ui += "<div class='menu'>";
		ui += "<span>Dry Humor</span>";
		ui += "<a class='menu-link' href='#'/>";
		ui += "</div>"; // end .menu
		
		// traits select
		ui += "<select name='slider_traits[0]' id='slider_traits_0' class='traits-select'>";
		// TODO: need options
		ui += "</select>"; // end .traits-select
		ui += "<div class='slider_bar bar_size_7'/>"; 
		
		ui += "</div>"; // end .slider_containment
		
		ui += "<input type='text' value='7' size='1' name='slider_values[0]' id='slider_values_0' class='value'/>";
		ui += "<input type='submit' value='remove_25' title='Remove this trait.' name='commit' class='remove' alt='Remove this trait.'/>";
		ui += "</div>"; // end .simple_slider
		return ui;
	};
	
	$.fn.mashit.sliderOptions = function() {
		return {
			onTraitChange: _mashit.handleTraitChange,
			onTraitReset:  _mashit.handleTraitReset,
			onValueChange: _mashit.handleValueChange,
			onValueReset:  _mashit.handleValueReset,
			onRemoveLink:  _mashit.handleTraitRemoved,
			onInsertAt:    _mashit.handleSliderInsertAt,
			onRemoveAt:    _mashit.handleSliderRemovedAt,
			onDeacivation: _mashit.handleSliderDeactivated,
			onActivation:  _mashit.handleSliderActivated,
			canDeactivate: _mashit.canDeactivate,
			canRemove:     _mashit.canRemove,
			onActiveAfterUpdate: _mashit.handleSliderActiveAfterUpdate
		};
	};
	
	/* 
		gets called when a slider changed.  the default is to update the text input
		represented by the slider_id, then call ajaxSubmit on the form.
		
		NOTE: there might be a case where we want to queue the changes, and push
		the ajax request at a less frequency then everytime the slider changes.
	*/
	$.fn.mashit.sliderChanged = function( slider ) {
		updateInputAndSubmitForm({
			slider: slider, 
			slider_id: slider.slider_id, 
			old_value: slider.previous_value, 
			new_value: slider.current_value, 
			onSuccess: $.fn.mashit.sliderChangedSuccess 
		});
	};
	$.fn.mashit.sliderChangedSuccess = function( slider ) {
		if( _history ) {
			_history.add( slider, "changedvalue", {to: slider.current_value, from: slider.previous_value} );	
		}
	};
	
	/*
		gets called when the slider is being reset, via the history buttons.
	*/
	$.fn.mashit.sliderReset = function( slider, slider_id, old_value, new_value ) {
		updateInputAndSubmitForm({
			slider: slider, 
			slider_id: slider.slider_id, 
			old_value: slider.previous_value, 
			new_value: slider.current_value
		});
	};
	
	/*
		gets called when the trait has changed, via drop down menu
	*/
	$.fn.mashit.traitChanged = function( slider ) {
		updateInputAndSubmitForm({
			slider: slider,
			slider_id: slider.slider_id,
			old_value: slider.previous_value,
			new_value: slider.current_value,
			onSuccess: $.fn.mashit.traitChangedSuccess
		});		
	};
	$.fn.mashit.traitChangedSuccess = function( slider ) {
		// we need to update the submit button input for the remove button.
		slider.find("input.remove").val("remove_" + slider.current_trait_id);
		if ( _history ) {
			_history.add( slider, 'changedtrait', {to: slider.current_trait_id, from: slider.previous_trait_id});
		}
	};
	
	$.fn.mashit.traitReset = function( slider, to_trait_id, from_trait_id ) {
		submitForm();
	};
	
	/*
		gets called when the trait is removed.
	*/
	$.fn.mashit.traitRemoved = function( slider ) {
		submitForm({
			slider: slider,
			onSuccess: $.fn.mashit.traitRemovedSuccess,
			data: {
				commit: slider.view.remove_link.val()
			}
		});
	};
	$.fn.mashit.traitRemovedSuccess = function( slider ) {
		if (_history) {
			_history.add( slider, 'removed', {position: currentSliderPosition( slider )} ); 
		}
		// need to remove after getting valuable info, such as position.
	  slider.remove();
		_mashit.updateControls();
	};
	
	/*
		handles sliderInsertAt
	*/
	$.fn.mashit.sliderInsertAt = function( slider, position ) {
		current_trait_id = slider.current_trait_id;
		previous_trait_id = slider.previous_trait_id;
		
		// let's re-insert the slider html into the current document, and get a handle on this newly inserted element.
		_mashit.find('.' + $.fn.mashit.settings.sliderClass + ':nth-child(' + position + ')' ).before( "<div class='" + $.fn.mashit.settings.sliderClass + "'></div>" );
		var element = _mashit.find('.' + $.fn.mashit.settings.sliderClass + ':nth-child(' + position + ')' );
		element.html( slider.html() );
		
		element.find('.' + $.fn.mashit.settings.traitSelectClass ).val( current_trait_id );
		element.find('.' + $.fn.mashit.settings.valueSelectClass ).val( slider.current_value );
				
		element.movieslider( $.fn.mashit.sliderOptions() ); 
		submitForm({
			onSuccess: $.fn.mashit.sliderInsertAtSuccess
		}); // NOTE: we don't want to record as history, since "remove" was the original action -- otherwise history gets out of synch
	};
	$.fn.mashit.sliderInsertAtSuccess = function() {
			_mashit.updateControls();
	};
	
	/*
		handles sliderRemovedAt
	*/
	$.fn.mashit.sliderRemovedAt = function( slider, position ) {
		// NOTE: the slider passed in as an attribute is the slider from the queue, which has been removed from
		// the current document.  we need to get the existing slider from the document via the position.  we
		// still need to get teh remove_link value from the original slider.
		newslider = _mashit.find('.' + $.fn.mashit.settings.sliderClass + ':nth-child(' + position + ')' );
		submitForm({
			slider: newslider,
			data: {
				commit: slider.view.remove_link.val()
			},
			onSuccess: $.fn.mashit.sliderRemovedAtSuccess
		});
	};
	$.fn.mashit.sliderRemovedAtSuccess = function( slider ) {
		slider.remove();
		_mashit.updateControls();
	};
	
	
	$.fn.mashit.handleAddAttributeSuccess = function( slider ) {
		if (_history) {
			_history.add( slider, 'added', {position: currentSliderPosition( slider )} ); 
		}
		_mashit.updateControls();
	};
	
	/*
		the slider was deactivated, we need to update the value with ''
		and submit the ajax form.
	*/
	$.fn.mashit.sliderDeactivated = function( slider ) {
		_mashit.setSliderValue( slider, "" );
		submitForm({
			slider: slider,
			onSuccess: $.fn.mashit.sliderDeactivatedSucess
		});
	};
	$.fn.mashit.sliderDeactivatedSuccess = function( slider ) {
		if( _history ) {
			_history.add( slider, 'deactivated' );
		}
	};
	
	/*
		the slider was activated, we need to reset the value with the previous value.
		if there's no previous value then we need to set to $.fn.mashit.settings.defaultSliderValue
	*/
	$.fn.mashit.sliderActivated = function( slider ) {
		var value = slider.current_value || $.fn.mashit.settings.defaultSliderValue.toString();
		_mashit.setSliderValue( slider, value );
		
		_mashit.deactivateAllSlidersExcept( slider );
		
		submitForm({
			slider: slider,
			onSuccess: $.fn.mashit.sliderActivatedSuccess
		});
	};
	$.fn.mashit.sliderActivatedSuccess = function( slider ) {
		if( _history ) {
			_history.add( slider, 'activated' );
		}
	};
	
	$.fn.mashit.clearSettingsPopup = function() {
		var ui = "<h2>Clear Settings</h2>";
		ui += "<p>Clear settings removes your starting movie, attributes and results so you can start from scratch. Are you sure you want to clear settings?</p>";
		ui += "<button class='clear_settings'>Clear settings</button>";
		return ui;
	};
	
	function clearErrors() {
		_mashit.find('.header .errors').remove();
	};
	
	function updateInputAndSubmitForm( options ) {
		var input;
		
		options   = options || {};
		slider 		= options.slider;
		slider_id = options.slider_id;
		new_value = options.new_value;
		old_value = options.old_value;
		onSuccess = options.onSuccess || function() {};
		
		/* lets update the select value to the new value */
		$(slider).find("select." + $.fn.mashit.settings.valueSelectClass + " option").each( function() {
			var option = $(this);
			if ( option.val() == new_value ) {
				option.attr("selected", "selected");
			} else {
				option.removeAttr( 'selected' );
			}
		});

		submitForm({
			slider: slider,
			onSuccess: onSuccess
		});		
	};
	
	/* 
		just submits the form and handles updating the view.  
		the options are:
		
			slider: the slider that caused the update/form submission
		  onSuccess: the method that gets called on success (must pass in a slider value too)
		  onError: the method that gets called on error (must pass in a slider value too)
		  data: optional data that gets passed with the form.
	*/
	function submitForm(options) {
		clearErrors(); // let's clear any errors we may have.
		var options = options || {};
		options['dataType'] = 'html';
		
		onSuccess = options['onSuccess'];
		onError   = options['onError'];
		slider		= options['slider'];
		data			= options['data'];
		
		ajax_options = {};
		ajax_options['success']  = function( response ) {
			$( $.fn.mashit.settings.resultsElement ).replaceWith( response );
			$('.truncate' ).truncate( 300, {
	      chars: /\s/,
	      trail:  [ " (<a href='#' class='truncate_show'>more</a>)", " (<a href='#' class='truncate_hide'>less</a>)" ]
	    });
			if( onSuccess && slider ) {
				onSuccess( slider ); 
			} else if ( onSuccess) {
				onSuccess();
			}
		};
		ajax_options['error'] = function( request, status, exception ) {	
			_mashit.handleError( request.responseText );
			if( onError && slider ) onError( slider );
		};
		if ( data ) ajax_options['data'] = data;
		
		ajax_options['beforeSend'] = function(request) {
			$.facebox( "<img src='/facebox/loading.gif' class='waiting'> Please wait, loading results...");
		};
		ajax_options['complete'] = function( request, status ) {
			$(document).trigger('close.facebox'); // close the popup.
		};
		
		/* now that the input has been updated, lets submit the form via ajax */
		_mashit.ajaxSubmit(ajax_options);		
	};
	
	/*
		determines the current slider position of all the sliders.
		slider 1 would have position of 1.
	*/
	function currentSliderPosition( slider ) {
		var current  = 1;
		var position = 0;
		_mashit.find('.' + $.fn.mashit.settings.sliderClass ).each( function() {
			var slider_element = $(this);
			var slider_id = slider_element.find("select." + $.fn.mashit.settings.valueSelectClass).attr("name");
			if ( slider_id == slider.slider_id ) {
				position = current;
			}
			current += 1;
		});
		return position;
	};
	
	/*
	** $.fn.mashit.settings
	**
	** the basic settings for the mashit controller.  
	**
	**  - resultsElement, this is the dom element for the results. its what gets replaced.
	*/
	$.extend( $.fn.mashit, {
		settings: {
			resultsElement: '#results',
			traitSelectClass: $.fn.movieslider.settings.traitSelectClass,
			valueSelectClass: $.fn.movieslider.settings.valueSelectClass,
			sliderClass: $.fn.movieslider.settings.sliderClass,
			maxNumberOfSliders: 5,
			defaultSliderValue: 8,
			canDeactivate: true, // can deactivate/activate sliders
			canRemove: true      // can remove/add sliders
		}
	});
	
	
})(jQuery); 

// try and attach to form#mashit or form#supermatch
$(document).ready( function() {

	if ( $('form#mashit').length > 0 ) {
		$('form#mashit').mashit({canDeactivate: false});
	}
	if ( $('form#supermatch').length > 0 ) {
		
		$('form#supermatch').mashit({canRemove: false});	
	}
});


/* 
  On the top of this file are some newer, simpler to read versions of the movie popup stuff. 
  
  The second section has similar functionality with the functions plugged into jQuery.
  
  Also, the new version ajaxes the popup content for faster page loads. This seemed
  prudent given the longer load times for tag parsing.
   
*/ 

/*  ------------------------------------------------------------------------------
 show_movie_details: pops open a detail view from links on the Mash-it results list, 

 Ajaxed for faster page loading!
 Ajax request is a get request to the same url as the current page, 
 with the addition of the result movie id. It is a show action in the controller.
 To implement this with no changes to javascript in Supermatch, just add a similar
 action to that controller, with routes, of course  

*/
function show_movie_details(event, elem){ 
  // stop event bubbling
  event.preventDefault();
	
	// initializing all the necessaries
  var link, content_holder;
  
  link = $(elem);
  content_holder = $( link.next(".movie_details") );

  var methods = {
    get_content: function(){ 
      content_holder.append('<li class="box spinner"><p><img src="/facebox/loading.gif"/></p></li>') // show spinner 
      var url = methods.detail_url();
      // get html from show action
      $.ajax({
         type: "GET",
         url: url,
         timeout: 5000, 
         success: function( data ){
           content_holder.find('.spinner').remove(); // delete spinner 
           content_holder.append( data ); // append content to the content_holder
           methods.add_close_link(); // add close link, not in partial
           methods.ajax_netflix_link();
           event.stopPropagation(); 
         },
         // redirect to movie info page if the request doesn't work
         error: function(XMLHttpRequest, textStatus, errorThrown){
           content_holder.find('.spinner').remove(); // delete spinner 
           window.location.replace(link.attr('href'));
         } 
      });  
    },
    
    ajax_netflix_link: function(){ 
      var cms_popup_link = $(content_holder.find('.navigation a.cms_popup'));
      cms_popup_link.click( function(event){
        load_cms_page(event, this);
      });
    },
    
    add_close_link: function(){
      content_holder.find('li.list_view').prepend( "<div class='close'><a href='#' class='close'>x</a></div>" );
      content_holder.find( "a.close" ).click( function(event) {
        hide_movie_details( event, this );
      });
	  },
	  
	  show: function(){
	    link.hide();
	    // this.add_close_link(); // this is temp for testing close functionality
      content_holder.removeClass('hidden');
	  },
	  
	  detail_url: function(){
	    var movie_id, url, movie_info_url; 
      movie_info_url = link.attr('href');
      movie_id = movie_info_url.match(/\/movies\/(\d*)/)[1];
      url = window.location + '/' + movie_id
	    return url;
	  }
	}; 
  
  // getting content if not yet loaded
  if( !(content_holder.children().length > 0 ) ){
    methods.get_content(); 
  } else {
    event.stopPropagation(); 
	} 
  
  // changing the display
  methods.show();
};

// hides the movie detail popup
function hide_movie_details(event, elem){ 
  // stop event bubbling
  event.preventDefault();
	event.stopPropagation(); 
	
	var link = $(elem);
	var content_holder = link.parents('.list_view').parent();
	content_holder.addClass('hidden');
	content_holder.prev('a.show_details').show();
};

function ajaxify_tag_forms() {
  $("#tag_filter_form,#tag_return_form").ajaxForm({
    success: function(data, statusText){
      var results = $("#results");
      results.replaceWith(data);
      ajaxify_tag_forms(); // doubling up ensures that on result reload the form still works
    }       
  });  
};

// automatically loads 
$(document).ready(function() { 
  /*  
      this stuff has been moved to the results partial to avoid 
      having to load it call it in the js each time the results
      are loaded (from either the tags form or the slider form)
  */
  
  // popup movie details on click of list links in mash-it
  // $("a.show_details").click( function(event) {
  //   show_movie_details( event, this ); 
  // });
  
  // // ajax submission of submit tags form
  // $("#tag_filter_form").ajaxForm({
  //   success: function(data, statusText){
  //     var results = $("#results");
  //     results.replaceWith(data);
  //       
  //   }
  // }); 
});   

/* -------------------------------------------------------------------------------
** movieexpand.js
** plugin for expanding a movie information.
** required:  jquery.js
*
*/
( function($) {
	$.fn.movieexpand = function( settings ) {
 		this.each( function() {
			var movie_link 	= $(this);
			var content			= movie_link.next(".hidden");
			
			
			// add a close link into the hidden div.
			var close_link = $.fn.movieexpand.addCloseElement(content);
			if ( close_link ) {
				close_link.click( function(event){
					movie_link.collapseContent();
					event.preventDefault();
					event.stopPropagation();
				});
			}
			
			movie_link.expandContent = function() {
				movie_link.hide();
				content.show();
			};
			
			movie_link.collapseContent = function() {
				movie_link.show();
				content.hide();
			};
			
			movie_link.handleClick = function(event) {
				if( movie_link.next(".hidden:visible").length > 0 ) {
					movie_link.collapseContent();
				} else {
					movie_link.expandContent();
				}
				event.preventDefault();
				event.stopPropagation();
			};
			
			// attach events
			movie_link.click( movie_link.handleClick );
			
		});
	};
	
	/*
		responsible for adding a close element to the content.
		each content structure might be a little different, and
		this allows one to overwrite without having to redo the
		whole expand javascript.
		
		the default is to add the element in the li.list_view 
		as a <div class='close'><a href='#' class='close'>x</a></div>
		
		the close element must be returned, otherwise the click
		event will not be attached.
	*/
	$.fn.movieexpand.addCloseElement = function(content) {
		content.find('li.list_view').prepend("<div class='close'><a href='#' class='close'>x</a></div>");
		return content.find( "a.close" );
	};
	
})(jQuery);


