var _scripts = [];
var JsonP={Response : null,ScriptTag: null, DataManaged: null};

/**
 * @param (String) url
 * @param (Array)  options
 */
JsonP.Base = Class.create({
  initialize: function(options) {
    this.options = {
      runAtCreation: true,
      method:       'get',
      encoding:     'UTF-8',
      timeout:     	20,
      parameters:   '',
      methodeName:  'instrumentDetailResponse',
      onSuccess:    '',
      onException:  function(e){}
    };
    
    Object.extend(this.options, options || { });

    this.options.method = this.options.method.toLowerCase();

	this.id = JsonP.Manager.newId();

    if (Object.isString(this.options.parameters))
      this.options.parameters = this.options.parameters.toQueryParams();
    else if (Object.isHash(this.options.parameters))
      this.options.parameters = this.options.parameters.toObject();
  }
});


JsonP.Request = Class.create(JsonP.Base, {
	  _complete: false,

	  initialize: function($super, url, options) {
	    $super(options);
	    this.url = url;
	    this.transport = new JsonP.Transport();
	    
	    window[this.options.methodeName] = function(data){
	    	JsonP.Response = data;
				
			if(JsonP.DataManaged == null)
				JsonP.DataManaged = new Hash();
	
			JsonP.DataManaged.set(this.id,data);
	    	
		}
	    
	    //Manage TimeOut
	    if(this.options.runAtCreation)
	    	this.request();
	    
	  },

	  request: function() {
		 
		  this.method = this.options.method;
		  var params = Object.clone(this.options.parameters);
		  
		  
		  this.parameters = params;
		  if (params = Object.toQueryString(params)) {
  		  	if(this.url != undefined){
  		    	this.url += (this.url.include('?') ? '&' : '?') + params;
        	}
      	  }
      	  
	      try {
	        this.transport.open(this.url);
	        this.transport.onreadystatechange = this.onStateChange.bind(this);
	        this.transport.send(params);
	        //JsonP.Timer = setTimeout(this.requestTimeOut(),this.options.timeout); 
	      }catch (e) {
	        this.options['onException'](e);
	      }
	  },
	  
      onStateChange: function(event) {
		this.transport.readyState = 2;
		if(!event ||( event.type == 'readystatechange' && $(Event.element(event)).readyState != 'loaded'))
			return;
		
		if(JsonP.DataManaged != null && JsonP.DataManaged.size() != 0){
			var value = JsonP.DataManaged.get(this.options.parameters.id)
		  	this.onScriptLoaded(value);
		  	//JsonP.DataManaged.shift();
		  }
	  },

	  onScriptLoaded : function(data){
	  	  clearTimeout(JsonP.Timer);
		  if(data != undefined && data != null)
			  try{
				  this.options.onSuccess(data);
			  }catch(e){
				  this.options['onException']();
			  }
	  },
	  
	  requestTimeOut : function(){
	  		this.transport.stop();
	  		try{
	  			 this.options['onSuccess']();
	  		}catch(e){
	  			this.options['onException']();
	  		}
	  }
});

JsonP.Request.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];  

JsonP.Transport = Class.create({
  initialize: function(){
    this.readyState = 0;
    this.url;
    
	if(JsonP.ScriptTag == null)	JsonP.ScriptTag = new Hash();
  },
  open:function(url){
    this.url = url;
    this.readyState = 0;
    
    var tag = JsonP.ScriptTag.unset(url);
	if(tag)	document.getElementsByTagName('head')[0].removeChild(tag);
  },
  onreadystatechange: function (){},
  send:function(data){
    this.createScript();
    this.readyState=1;
  },
  update:function(data){
    this.updateScript(this.url);
    this.readyState=1;
  },
  stop:function(){
	var jsNode = JsonP.ScriptTag.unset(this.url);
	document.getElementsByTagName('head')[0].removeChild(jsNode);
  },
  createScript: function(){
	var jsNode = new Element("script");
	jsNode.onload = this.onreadystatechange.bindAsEventListener(this);
	jsNode.onreadystatechange = this.onreadystatechange.bindAsEventListener(this);
	document.getElementsByTagName('head')[0].appendChild(jsNode);
	jsNode.defer="defer";
	jsNode.type = "text/javascript";
	jsNode.charset = "utf-8";
	jsNode.src = this.url;
	JsonP.ScriptTag.set(this.url,jsNode); 
  }
});

JsonP.Manager = {
	currentId: 0,
	newId: function() {
		return ++this.currentId;
	}
};
