var $ = YAHOO.util.Dom.get;

ApplicationClass = function(config) {
	var texts = {};
	this.config = config || {};
  this.DEFAULT_HEADER = 'Working, please wait..';
  this.dlgWorking = null;
  this.loaders = [];
  this.loadingsStarted = 0;
  this.loadingsStartedElements = [];
  this.yui_path = this.config.yui_path || './yui/';
  this.app_path = this.config.app_path || '../app/';
  this.APPLICATION_MODULES =   [
    {name:'application.lang', type:'js', path: this.app_path + 'lang.js', requires:[]},
    {name:'application.text', type:'js', path: this.app_path + 'text.js', requires:[]},
    {name:'application.dom', type:'js', path: this.app_path + 'dom.js', requires:['dom', 'application.lang']},
    {name:'application.data', type:'js', path: this.app_path + 'data.js', requires:['application.lang']},
    
    {name:'application.connection', type:'js', path: this.app_path + 'connection.js', requires: ['application.dom', 'json', 'connection', 'application.lang']},
    {name:'application.form', type:'js', path: this.app_path + 'form.js', requires: ['connection', 'application.dom', 'application.lang', 'application.connection']},
    {name:'application.dialog', type:'js', path: this.app_path + 'dialog.js', requires: ['dom', 'container', 'dragdrop', 'button', 'application.lang', 'application.text', 'application.dom', 'application.connection', 'application.form']},

    {name:'application.tooltip', type:'js', path: this.app_path + 'widget/tooltip.js', requires: ['dom', 'container']},
    {name:'application.combo', type:'js', path: this.app_path + 'widget/combo.js', requires: []},
    {name:'application.combo_chain', type:'js', path: this.app_path + 'widget/combo_chain.js', requires: ['application.combo', 'json', 'application.connection', 'application.text']},
    {name:'application.treeview', type:'js', path: this.app_path + 'widget/treeview.js', requires: ['treeview']},
    {name:'application.calendar', type:'js', path: this.app_path + 'widget/calendar.js', requires: ['container', 'calendar']},
    {name:'application.calendar_dialog', type:'js', path: this.app_path + 'widget/calendar_dialog.js', requires: ['application.calendar', 'application.lang']},
    {name:'application.date_edit', type:'js', path: this.app_path + 'widget/date_edit.js', requires: ['application.calendar_dialog']},
    {name:'application.datatable', type:'js', path: this.app_path + 'widget/datatable.js', requires: ['application.lang', 'datasource', 'connection', 'element', 'json', 'get', 'dragdrop', 'datatable', 'paginator']},
    {name:'application.autocomplete', type:'js', path: this.app_path + 'widget/autocomplete.js', requires: ['container','datasource', 'autocomplete', 'element', 'button', 'connection', 'json', 'application.lang']},
  
    {name:'application.validation', type:'js', path: this.app_path + 'validation.js', requires:['application.lang', 'application.form']},
    {name:'application.validators', type:'js', path: this.app_path + 'validators.js', requires:['application.validation']}
  ];
  
  this.LoadingMode = {GLOBAL: 0, ELEMENT: 1, AUTO: 2, DISABLED: 3};
  
  this.isLoaderReady = function() {return this.loaders.length == 0};
 
  this.namespace = function() {
    var a=arguments, o=null, i, j, d;
    for (i=0; i<a.length; i=i+1) {
        d=(""+a[i]).split(".");
        o=Application;

        // Application is implied, so it is ignored if it is included
        for (j=(d[0] == "Application") ? 1 : 0; j<d.length; j=j+1) {
            o[d[j]]=o[d[j]] || {};
            o=o[d[j]];
        }
    }

    return o;
  }
   
  this.startLoading = function(element, text) {
    if (element === Application.LoadingMode.DISABLED) return null;
  	var el = $(element);
  	
  	if (!el || element === Application.LoadingMode.GLOBAL) {
  	  if (this.loadingsStarted++ > 0) {return null;}
  	  if (!this.dlgWorking) this.createLoadingPanel();
	    if (this.dlgWorking) {
	      this.dlgWorking.setHeader(text || this.getTextDef('APP.LOADING', this.DEFAULT_HEADER));
	      this.dlgWorking.show();
	    }
  	} else {	  	
	  	YAHOO.util.Dom.addClass(el, 'loading');
	  	this.loadingsStartedElements.push(el);
  	}
  	return null;
  }
  
  this.endLoading = function(element) {
    if (element === Application.LoadingMode.DISABLED) return null;
    var el = $(element);
    
    if (!el || element === Application.LoadingMode.GLOBAL) {
      if (this.loadingsStarted-- > 1) {return null;}
      if (this.dlgWorking) this.dlgWorking.hide();
    } else {      
	    var isLoadingFinished = null;
	    for (var i = (this.loadingsStartedElements.length - 1); i >= 0 ; i--) {
	    	if (this.loadingsStartedElements[i] === el) {
	    		if (isLoadingFinished === null) {
	    			this.loadingsStartedElements.splice(i, 1);
	    			isLoadingFinished = true;
	    		} else if (isLoadingFinished === true) 
	    		  isLoadingFinished = false;
	    	}
	    }
      if (isLoadingFinished) YAHOO.util.Dom.removeClass(el, 'loading');	    
    }   	
    return null;
  }	

  this.clearStartedLoadings = function(element){
    var el = $(element);
    if (!el) {this.loadingsStarted = 0;} else {
      for (var i = (this.loadingsStartedElements.length - 1); i >= 0 ; i--) {
        if (this.loadingsStartedElements[i] === el) {
            this.loadingsStartedElements.splice(i, 1);
        }
      }
    }
  }

  this.createLoadingPanel = function() {   
    if (typeof YAHOO.widget.Panel !== 'undefined') {
      this.dlgWorking = new YAHOO.widget.Panel('dlgWorking', {width: '240px',fixedcenter: true,visible: false,close: true, zIndex: 10000,  modal: true,constraintoviewport: true} );
      this.dlgWorking.setHeader(this.getTextDef('APP.LOADING', this.DEFAULT_HEADER));
      this.dlgWorking.setBody('');
      YAHOO.util.Dom.addClass(this.dlgWorking.body, 'loading');
      this.dlgWorking.hideEvent.subscribe(function() {Application.loadingsStarted = 0; });
      this.dlgWorking.render(document.body);
    }
  }

  this.init = function() {
    this.createLoadingPanel();
  }
  
  //възможно е да извикаме повече от веднъж => в this.readyHandler имаме unsubscribeAll - за да не се извикат два пъти прикачените лисънъри
  this.load = function(require, modules) {
    var found = false;
    var i;
    

    var cfgLoader = {  
        base: this.yui_path,
        require: require,
        onSuccess: function() {
        	var loaderIndex = -1;
        	for (var i = 0; i < Application.loaders.length; i++) if (this === Application.loaders[i]) {loaderIndex = i; break;}
        	if (loaderIndex != -1) Application.loaders.splice(loaderIndex, 1);
        	Application.readyHandler(this);
		    },
		    onFailure: function(msg, xhrobj) {  
          throw ('Loader failure');
        }  
      }
    if (this.config.isDebug) cfgLoader['filter'] = 'DEBUG';
    var loader = new YAHOO.util.YUILoader(cfgLoader);
      
    for (i = 0; i < this.APPLICATION_MODULES.length ; i++) {
    	loader.addModule(this.APPLICATION_MODULES[i]);
    }
      
    if (modules) {  
    	for (i = 0; i < modules.length ; i++) {
    		loader.addModule(modules[i]);  
    	}
    }
          
    this.loaders.push(loader);
    if (this.loaders.length == 1) loader.insert();
  }
  
  this.addText = function(id, value) {
  	texts[id] = value;
  }
  
  this.getText = function(id, defaultValue) {
  	if (typeof texts[id] != 'undefined') return texts[id];
  	if (typeof defaultValue != 'undefined') return defaultValue;
  	return id;
  }
  
  this.getTextDef = function(id, defaultValue) {
  	if (typeof texts[id] != 'undefined') return texts[id];
  	return (! defaultValue ? null : defaultValue);
  }  
  
  this.addTexts = function(textsObject) {
  	for (var id in textsObject) {
  		this.addText(id, textsObject[id]);
  	}
  }
  
  //---- event -----
  
  this.DOMReadyEvent = new YAHOO.util.CustomEvent("DOMReady", YAHOO.application);
  this.LoaderSuccessEvent = new YAHOO.util.CustomEvent("LoaderSuccess", YAHOO.application);
  this.ReadyEvent = new YAHOO.util.CustomEvent("Ready", YAHOO.application);
  
  this.readyHandler = function(loader) {
  	//$('log').innerHTML += 'Application.readyHandler'  + '<br />';
    var func = null;
    
    if (this.isLoaderReady()) {
      this.LoaderSuccessEvent.fire();
      this.LoaderSuccessEvent.unsubscribeAll();
    } else if (loader != null) { 
    	if (Application.loaders.length > 0) Application.loaders[0].insert();
    }
    
    if (YAHOO.util.Event.DOMReady) {
      this.DOMReadyEvent.fire();
      this.DOMReadyEvent.unsubscribeAll();
    }    
    
    if (YAHOO.util.Event.DOMReady && this.isLoaderReady()) {
      this.ReadyEvent.fire();
      this.ReadyEvent.unsubscribeAll();
    }
  }
  
  this.onReady = function(fn, obj, overrideContext) {
    if (YAHOO.util.Event.DOMReady && this.isLoaderReady()) {
      setTimeout(function() {
        var s = window; if (overrideContext) {if (overrideContext === true) {s = obj;} else {s = overrideContext;}}
        fn.call(s, "Ready", [], obj);
      }, 0);
    } else {
      this.ReadyEvent.subscribe(fn, obj, overrideContext);
    }
  }
  
  this.onLoaderSuccess = function(fn, obj, overrideContext) {
    if (this.isLoaderReady()) {
      setTimeout(function() {
        var s = window; if (overrideContext) {if (overrideContext === true) {s = obj;} else {s = overrideContext;}}
        fn.call(s, "LoaderSuccess", [], obj);
      }, 0);
    } else {
      this.LoaderSuccessEvent.subscribe(fn, obj, overrideContext);
    }
  }
  
  this.onDOMReady = function(fn, obj, overrideContext) {
    if (YAHOO.util.Event.DOMReady) {
      setTimeout(function() {
        var s = window; if (overrideContext) {if (overrideContext === true) {s = obj;} else {s = overrideContext;}}
        fn.call(s, "DOMReady", [], obj);
      }, 0);
    } else {
        this.DOMReadyEvent.subscribe(fn, obj, overrideContext);
    }
  }
  
  YAHOO.util.Event.onDOMReady(function() {this.readyHandler();}, null, this);
  this.onReady(this.init, null, this);
}
