/* * * * * * * * * * * * * * * * * * *
*
*	Author: Alex Cruikshank
*	07.27.2006
*	License
*	Copyright (c) 2006 CNET Networks, Inc.
*
*	Permission is hereby granted, free of charge, to any person obtaining a copy of 
*	this software and associated documentation files (the "Software"), to deal in the
*	Software without restriction, including without limitation the rights to use, copy, 
*	modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
*	and to permit persons to whom the Software is furnished to do so, subject to the 
*	following conditions:
*
*	The above copyright notice and this permission notice shall be included in all copies
*	or substantial portions of the Software.
*
*	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
*	INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
*	PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
*	FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
*	OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
*	DEALINGS IN THE SOFTWARE.
*
* * * * * * * * * * * * * * * * * * */	


Prototypify = function(){};

Prototypify.prototypified = false;

// store then remove functions from prototypes of native objects
Prototypify.arrayFunctionHolder = new Object();
for(x in Array.prototype){
  Prototypify.arrayFunctionHolder[x] = Array.prototype[x];
  delete Array.prototype[x];
}

Prototypify.stringFunctionHolder = new Object();
for(x in String.prototype){
  Prototypify.stringFunctionHolder[x] = String.prototype[x];
  delete String.prototype[x];
}

Prototypify.numberFunctionHolder = new Object();
for(x in Number.prototype){
  Prototypify.numberFunctionHolder[x] = Number.prototype[x];
  delete Number.prototype[x];
}


Prototypify.proxy = function( f, proxyArguments ){

  return function(){
    
    var needsPrototypes = ! Prototypify.prototypified;
    if( needsPrototypes ){
      Prototypify.prototypified = true;
      for (var x in Prototypify.arrayFunctionHolder){
        Array.prototype[x] = Prototypify.arrayFunctionHolder[x];
      }
      for (var x in Prototypify.stringFunctionHolder){
        String.prototype[x] = Prototypify.stringFunctionHolder[x];
      }
      for (var x in Prototypify.numberFunctionHolder){
        Number.prototype[x] = Prototypify.numberFunctionHolder[x];
      }
    }

    if( proxyArguments ){
      for(var i=0; i < arguments.length; i++ ){
        if (typeof arguments[i] == 'function'){
          arguments[i] = Prototypify.proxy( arguments[i], proxyArguments );
        }
      }
    }

    var out = f.apply( this, arguments );

    if ( needsPrototypes ){
      for (var x in Array.prototype ){
        delete Array.prototype[x];
      }
      for (var x in String.prototype ){
        delete String.prototype[x];
      }
      for (var x in Number.prototype ){
        delete Number.prototype[x];
      }
      Prototypify.prototypified = false;
    }
    return out
    }
};


Prototypify.instrument = function( clazz, proxyArguments ){
  for(var prop in clazz.prototype ){
      if(typeof clazz.prototype[prop] == 'function'){
      clazz.prototype[ prop ] = Prototypify.proxy( clazz.prototype[ prop ], proxyArguments );
    }
  }
};


Prototypify.instrumentStatic = function( clazz, proxyArguments ){
  for (var prop in clazz){
    if(typeof clazz[prop] == 'function'){
      clazz[ prop ] = Prototypify.proxy( clazz[ prop ], proxyArguments );
    }
  }
};


/* * * * * * * * * * * * * * * * * * *
*
*  Modify Prototype Methods
*   - That contain setTimeout
*
* * * * * * * * * * * * * * * * * * */

Abstract.Insertion.prototype.initialize = function(element, content){
  this.element = $(element);
    this.content = content.stripScripts();

  if(this.adjacency && this.element.insertAdjacentHTML){
    try{
      this.element.insertAdjacentHTML(this.adjacency, this.content);
    }catch(e){
      var tagName = this.element.tagName.toLowerCase();
      if(tagName == 'tbody' || tagName == 'tr') {
        this.insertContent(this.contentFromAnonymousTable());
      }else{
        throw e;
      }
    }
  }else{
    this.range = this.element.ownerDocument.createRange();
    if(this.initializeRange) this.initializeRange();
    this.insertContent([this.range.createContextualFragment(this.content)]);
  }

  setTimeout(Prototypify.proxy(function(){content.evalScripts()}), 10);
};


Ajax.Request.prototype.request = function(url) {
  var parameters = this.options.parameters || '';
  if(parameters.length > 0) parameters += '&_=';

  try{
    this.url = url;
    if(this.options.method == 'get' && parameters.length > 0){
      this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
    }
    
    Ajax.Responders.dispatch('onCreate', this, this.transport);

    this.transport.open(this.options.method, this.url, this.options.asynchronous);

    if(this.options.asynchronous){
      this.transport.onreadystatechange = this.onStateChange.bind(this);
      setTimeout(Prototypify.proxy((function(){this.respondToReadyState(1)}).bind(this)), 10);
    }

    this.setRequestHeaders();

    var body = this.options.postBody ? this.options.postBody : parameters;
    this.transport.send(this.options.method == 'post' ? body : null);

  }catch(e){
    this.dispatchException(e);
  }
};


Object.extend(Element.Methods,{
  
  update : function(element, html){
    $(element).innerHTML = html.stripScripts();
    setTimeout( Prototypify.proxy(function(){html.evalScripts()}), 10);
  },
  
  replace : function(element, html){
    element = $(element);
    
    if(element.outerHTML){
      element.outerHTML = html.stripScripts();
    }else{
      var range = element.ownerDocument.createRange();
      range.selectNodeContents(element);
      element.parentNode.replaceChild(
      range.createContextualFragment(html.stripScripts()), element);
    }
    
    setTimeout( Prototypify.proxy(function(){html.evalScripts()}), 10);
  }
});
