/**
 * The Shadowbox (v3.x) ajax player class. jQuery ONLY!
 *
 * @version 1.1
 *
 * Retrieves and displays partial HTML from server via Ajax
 * (where 'partial' implies valid HTML, but not a full web page!)
 *
 * To use:
 *   Include 'ajax' as a player in the Shadowbox.init() call options
 *      eg. Shadowbox.init({players;['img','ajax']});
 *   Set the link's player to 'ajax'
 *     eg. < a href='ajaxpartial.php' rel='shadowbox;player=ajax'>Link< /a>
 *   By default, the expected response format is HTML
 *
 * The ajax() call options can be overriden by setting Shadowbox options.ajax
 * to an object containing Options as defined on http://docs.jquery.com/Ajax/jQuery.ajax#options
 * eg. to set a JSON data type (instead of HTML)
 *   var myAjaxHandler = function(data, responseText){
 *       this.html = '<div>'+data.text+'</div>';
 *       this.ready = true;
 *     };
 *   var opts = { ajax : { dataType:'json', success:myAjaxHandler }
 *              , players: ['ajax']
 *              };
 *   Shadowbox.init(opts);
 * Be warned : there are numerous options available for the jQuery.ajax() method, and
 *             experimenting with them could easily cause the call to fail!
 * NOTE : If overridden, the success, error and complete callbacks get scope of the Shadowbox.ajax
 *        instance, in place of the XMLHtmlRequest that is usually the context for jQuery.
 *        The callbacks - especially success - are expected/required to set this.html to
 *        hold the displayable HTML, and this.ready=true to indicate that the ajax call
 *        is complete and ready to be shown.
 *
 * There is one extra option available - ajaxload - which is not part of jQuery's ajax() options
 * but is provided here as a callback option for when the HTML has been inserted into the DOM.
 * The sequence of events is:
 *   ajax completion : DOM insertion : ajaxload callback : loading toggled : onFinish callback
 * So ajaxload is simply called slightly earlier than Shadowbox's onFinish.
 *
 * ajaxload : function(){ 
 *     this; // shadowbox.ajax instance
 *   }
 *
 * The ajaxload callback option can be specified as either an additional ajax option,
 * or as an option in its own right, with the latter taking precendence (and link-level taking
 * precedence over init() level).
 * For example:
 *   var myAjaxIsLoaded = function(){
 *       this.container.find('a').shadowbox();
 *     };
 *
 * At init()...
 * (A)   var opts = { ajax : { dataType:'json', ajaxload:myAjaxIsLoaded }
 *                  , players: ['ajax']
 *                  };
 *   Shadowbox.init(opts);
 * ...OR...
 * (B)   var opts = { ajax : { dataType:'json' }
 *                  , ajaxload: myAjaxIsLoaded
 *                  , players: ['ajax']
 *                  };
 *   Shadowbox.init(opts);
 *
 * At link level...
 * (C)   <a href='___' rel = 'shadwobox;player=ajax;options={ajax:{ajaxload:myAjaxIsLoaded}}'>___</a>
 * ...OR...
 * (D)   <a href='___' rel = 'shadwobox;player=ajax;options={ajaxload:myAjaxIsLoaded}'>___</a>
 *
 * CAUTION : If you specify ajax options at link-level, eg options={ajax:{___}}, you MUST specify
 *           them in their entirety! In other words, any ajax:{___} options specified at init()
 *           level will NOT be applied! This is because Shadowbox only does a shallow copy of
 *           link-level options onto init() level options, so the ajax options at init() level
 *           actually get completely overwritten by the link-level ones.
 *           For example, applying both (A) and (C) above, will wipe out the dataType:'json'
 *           property for when (C) is activated!
 */
if(typeof jQuery == 'undefined'){
  throw 'Unable to load Shadowbox Ajax player, jQuery library not found';
}else{
	(function(S){
		if(!S.options.ajax){
			S.options.ajax = {};
		}
    S.ajax = function(obj){ //constructor
        this.obj = obj; //cache object
        this.height = this.obj.height ? parseInt(this.obj.height, 10) : 300; //default to 300
        this.width = this.obj.width ? parseInt(this.obj.width, 10) : 500; //default to 500
        this.html = ''; //will be set from the ajax response
        this.ready = false; //make Shadowbox wait for the ajax call to return
				this.options = {};
        var me = this
        	, opts = jQuery.extend( { type:'GET', url:obj.content, success:this.ajaxSuccess }
																, S.options.ajax
																, S.options.ajaxload ? { ajaxload:S.options.ajaxload } : null
																, this.obj.options ? this.obj.options.ajax||null : null
																, this.obj.options && this.obj.options.ajaxload ? { ajaxload:this.obj.options.ajaxload } : null
																);
        jQuery.each(opts, function(k,v){
        	  var V = v;
 	          //wrap function so as to change callback's scope from the XMLHttpRequest to this Shadowbox.ajax instance...
   	        //NB success callback (at least) MUST assign this.html, and set this.ready=true
     	      me.options[k] = {complete:1,error:1,success:1}[k] ? function(){ V.apply(me, arguments); } : V;
   	      });
        jQuery.ajax(this.options); //Go For It!
    	};

    S.ajax.prototype = {
        /**
         * Appends this object to the document.
         *
         * @param   HTMLElement     body    The body element
         * @param   String          id      The content id
         * @param   Object          dims    The current Shadowbox dimensions
         * @return  void
         * @public
         */
        append: function(body, id, dims){
            this.id = id;
            // give 'html' class to enable scrolling, plus 'html_ajax' just in case it's needed
            this.container = jQuery('<div></div>').attr({id:this.id}).addClass('html html_ajax').html(this.html);
						jQuery(body).append(this.container);
						if(this.options.ajaxload){
							this.options.ajaxload.call(this);
						}
        } //end append()
        /**
         * Removes this object from the document after clearing any cache entries
         *
         * @return  void
         * @public
         */
      , remove: function(){
					this.container.find('a,area').each(function(){
     	  		  if(typeof this.shadowboxCacheKey != 'undefined'){
     	    			var k = this.shadowboxCacheKey;
			  			  if(S.cache[k]){ S.cache[k] = {X:1}; }
                try{ delete this.shadowboxCacheKey; }
                catch(e){ if(this.removeAttribute){ this.removeAttribute('shadowboxCacheKey'); } }
              }
            }).end().remove();
					var trunc = true, i = S.cache.length;
					while(trunc && i--){ trunc = !!S.cache[i].X; }
          if(trunc){ S.cache = []; }
          this.container = null;
        } //end remove()
        /**
         * Default ajax() success callback
         *
         * @param   HTML string
         * @return  void
         * @public
         */
      , ajaxSuccess: function(data){
	      	this.html = jQuery.trim(data);
					this.ready = true;
				} //end ajaxSuccess()
      }; //end prototype
	})(Shadowbox);
} //end of test for jQuery

