//First of all find javascript base path by searching in DOM


/**
 * Every Component will be observable because and observable object would
 * have external connections to any scope other than its class scope, this way
 * you can add intercepting codes to this component to customize it without changing
 * any code for the component.
 * @class
 **/
var Observable = Class.create({
   initialize : function(){
      this.observerTypeList = new Object();
   },
   /**
    * Remove all observers that observe this object
    */
   removeAllObservers : function(){
      for(var i in this.observerTypeList){
         delete this.observerTypeList[i];
      }
   },
   /**
    * Add observer to this object for being notified on a specific event type.
    */
   addObserver : function(newObserver, eventType){
      if(this.observerTypeList[eventType] == null){
         this.observerTypeList[eventType] = new Array();
      }
      this.observerTypeList[eventType].push(newObserver);
   },
   /**
    * Remove observer which is registered for a specific event type before.
    */
   removeObserver : function(newObserver, eventType){
      var typeArray = this.observerTypeList[eventType];
      if(typeArray == null){
         throw "No observer for event type "+eventType;
      }
      typeArray.removeItem(newObserver);
      if(typeArray.length == 0){delete this.observerTypeList[eventType];}
   },
   
   /**
    * Notify observers that a specific event type occurred on this object.
    * @param eventType event type that occurred.
    * @param args arguments for notification, can be null
    */
   notifyObservers : function(eventType, args){
      var list = this.observerTypeList[eventType];
      if(typeof list == 'undefined'){
         return;
      }
        
      for(var i=0;i<list.length;i++){
         list[i].notifyObserver(eventType, this, args);
      }
   }
});

/**
 * Observer is any class that can be registered to an Observable with the type
 * specified. same observer can be used for more than one event type.
 * @class
 */
var Observer = Class.create({
   initialize : function(){
      
   },
   notifyObserver : function(eventType, eventSubject, args){
      alert("NotifyObserver method must be overridden by subclass");
   }
});

/**
 * Component is every reusable class in your code, it is not only a gui component.
 * @class
 * @augments Observable
 */
var Component = Class.create(Observable,{
    initialize : function($super){
        $super();
        this.id = Component.$GLOBAL_COUNTER++;
        Component.$COMPONENT_LIST[this.id] = this;
    }
});
Component.$BASE_PATH="";
Component.$GLOBAL_COUNTER=0;
Component.$COMPONENT_LIST = new Array();
Component.getComponent = function(id){
   return Component.$COMPONENT_LIST[id];
}
Event.observe(window,'load',function(){
	$$('script').each(function(scriptElement){
		var regEx = /GlobalClasses.js/;
		if(regEx.test(scriptElement.src)){
			var temp=scriptElement.src.lastIndexOf('/base');
			Component.$BASE_PATH = scriptElement.src.substring(0,temp);
		}
	});
});

/**
 * Logging functionality class for all.
 * @class
 */
var Logger = Class.create({
   initialize : function(){
      this.level = Logger.LEVEL_DEBUG;
   },
   /**
    * debug level logging
    * @param {String} [logText] the log text for displaying in console
    * @param {String} [className] name of the class Logger is used
    * @param {String} [functionName] name of the function Logger is used 
    */
   debug : function(){
      var params = this.evaluateParams(arguments);
      if(this.level <= Logger.LEVEL_DEBUG)
         if(typeof console != "undefined"){console.log(this.createLogText('DEBUG', params));}
   },
   /**
    * info level logging
    * @param {String} [logText] the log text for displaying in console
    * @param {String} [className] name of the class Logger is used
    * @param {String} [functionName] name of the function Logger is used 
    */
   info : function(){
      var params = this.evaluateParams(arguments);
      if(this.level <= Logger.LEVEL_INFO)
         if(typeof console != "undefined"){console.log(this.createLogText('INFO', params));}
   },
   /**
    * error level logging
    * @param {String} [logText] the log text for displaying in console
    * @param {String} [className] name of the class Logger is used
    * @param {String} [functionName] name of the function Logger is used 
    */
   error : function(){
      var params = this.evaluateParams(arguments);
      if(this.level <= Logger.LEVEL_ERROR)
         if(typeof console != "undefined"){console.log(this.createLogText('ERROR', params));}
   },
   evaluateParams : function(argumentArray){
      var result = new Logger.FunctionParams();
      result.logText = argumentArray[0];
      result.className = argumentArray[1];
      result.functionName = argumentArray[2];
      return result;
   },
   createLogText : function(type, funcParams){
      var str = type+" : ";
      if(funcParams.className != null){str += funcParams.className;}
      if(funcParams.functionName != null){str += funcParams.functionName;}
      if(funcParams.logText != null){str += funcParams.logText;}
      
      return str;
   }
});

Logger.FunctionParams = Class.create({
	initialize : function(){
	   this.logText = null;
	   this.className = null;
	   this.functionName = null;
   }
})

/**
 * DEBUG Level, value is 0
 * @constant
 */
Logger.LEVEL_DEBUG = 0;
/**
 * INFO Level, value is 1
 * @constant
 */
Logger.LEVEL_INFO = 1;
/**
 * ERROR Level, value is 2
 * @constant
 */
Logger.LEVEL_ERROR = 2;

/**
 * the static singleton instance of Logger
 */
Logger.$SINGLETON = null;

/**
 * Singleton instance method
 */
Logger.getInstance = function(){
   if(Logger.$SINGLETON == null){
      Logger.$SINGLETON = new Logger();
   }
   return Logger.$SINGLETON;
}

var DomUtil = Class.create({
	initialize : function(){
   },
   
	removeAllChildren : function(node){
	   if (node.hasChildNodes()){
	      var children = node.childNodes;
	      for (var i = 0; i < children.length; i++) {
	         node.removeChild(children[i--]);
	      };
	   };
	}
});

DomUtil.getInstance = function(){
   if(DomUtil.$SINGLETON == null){
   	DomUtil.$SINGLETON = new DomUtil();
   }
   return DomUtil.$SINGLETON;
}


/**
 * this class is for importing css files statically by using <i>document.write</i> function 
 * or dynamically by using DOM functions. This gives us the ability to track our css imports. 
 * When we track the imports we eliminate the possibility of importing one css file twice with
 * this Class. This class is singleton so its Global variable name will be CssImporter
 */
CssImporter = Class.create({
   initialize : function($super){
	   this.logger = Logger.getInstance();
	   this.loadArray = new Array();
	},
	
	/**
	 * 
	 */
	importStatic : function(src){
	   if(this.isImportedBefore(src)){
	      this.logger.info(src+" is imported before", "CssImporter", "import()");
	      return;
	   }
	   //second argument is parameter for static resource
	   var urlParam='';
	   if(arguments[1] != null){
	   	urlParam = arguments[1];
	   }
	   
	   document.writeln('<style type="text/css" media="all">');
	   document.writeln('@import "'+src+'";');
	   document.writeln('</style>');
	   
	   this.loadArray[src] = true;
	},
	
	importDynamic : function(src){
	   if(this.isImportedBefore(src)){
	      this.logger.info(src+" is imported before", "CssImporter", "import()");
	      return;
	   }
	   var head = document.getElementsByTagName('head')[0];
	   var cssLink = new Element('link', {id: ++JsImporter.$LOAD_COUNTER, rel: 'stylesheet', type: 'text/css', href: src});
	   head.appendChild(cssLink);
	   this.loadArray[src] = true;
	},
	isImportedBefore : function(src){
	   return (typeof this.loadArray[src] != 'undefined' && this.loadArray[src] != null);
	}
});

/**
 * the static singleton instance of CssImporter.
 */
CssImporter.$SINGLETON = null;
/**
 * Css load counter, holds amount of css file loaded dynamically or statically.
 */
CssImporter.$LOAD_COUNTER = 0;

/**
 * Singleton instance method
 */
CssImporter.getInstance = function(){
   if(CssImporter.$SINGLETON == null){
   	CssImporter.$SINGLETON = new CssImporter();
   }
   return CssImporter.$SINGLETON;
}

/**
 * this class is for importing js files statically by using <i>document.write</i> function 
 * or dynamically by using DOM functions. This gives us the ability to track our js imports. 
 * When we track the imports we eliminate the possibility of importing one js file twice with
 * this Class. This class is singleton so its Global variable name will be JsImporter not 
 * _JsImporter.
 */
var JsImporter = Class.create({
   initialize : function($super){
      this.logger = Logger.getInstance();
      this.loadArray = new Array();
   },
   
   /**
    * 
    */
   importStatic : function(src){
      if(this.isImportedBefore(src)){
         this.logger.info(src+" is imported before", "JsImporter", "import()");
         return;
      }
      //second argument is parameter for static resource
      var urlParam='';
      if(arguments[1] != null){
      	urlParam = arguments[1];
      }
      document.write('<script src="', src+urlParam, '" language="javascript" type="text/javascript"><\/script>');
      this.loadArray[src] = true;
   },
   
   importDynamic : function(src){
      if(this.isImportedBefore(src)){
         this.logger.info(src+" is imported before", "JsImporter", "import()");
         return;
      }
      var head = document.getElementsByTagName('head')[0];
      var script = new Element('script', {id: ++JsImporter.$LOAD_COUNTER, type: 'text/javascript', src: src});
      head.appendChild(script);
      this.loadArray[src] = true;
   },
   isImportedBefore : function(src){
      return (typeof this.loadArray[src] != 'undefined' && this.loadArray[src] != null);
   }
});

/**
 * the static singleton instance of JsImporter.
 */
JsImporter.$SINGLETON = null;
/**
 * Js load counter, holds amount of js file loaded dynamically or statically.
 */
JsImporter.$LOAD_COUNTER = 0;

/**
 * Singleton instance method
 */
JsImporter.getInstance = function(){
   if(JsImporter.$SINGLETON == null){
      JsImporter.$SINGLETON = new JsImporter();
   }
   return JsImporter.$SINGLETON;
}

var FormElement = Class.create(Component, {
   initialize : function(){
      
   },
   
   setValue : function(){
      alert('setValue() must be overriden!');
   },
   
   getValue : function(){
      alert('getValue must be overridden!');
   },
   
   clearElement : function(){
      alert('clearElement must be overridden!');
   },
   
   disableElement : function(){
      alert('disableElement must be overridden!');
   }
});

var UserRole = Class.create({
   initialize : function(){
      this.canSendMessage = null;
   }
});

var AppContext = Class.create({
   initialize : function(){
      this.userRole = null;
      this.cityId = null;
      this.cityName = null;
      this.loggedUserId = null;
      this.loggedUserName = null;
      this.profileLevel = null;
      this.captchaColorParams = null;
   },
   
   initParams : function(userRole, cityId, cityName, userId, userName, profileLevel,
                         captchaColorParams){
      this.userRole = userRole;
      this.cityId = cityId;
      this.cityName = cityName;
      this.loggedUserId = userId;
      this.loggedUserName = userName;
      this.profileLevel = profileLevel;
      this.captchaColorParams = captchaColorParams;
   }
});

/**
 * Singleton instance method
 */
AppContext.getInstance = function(){
   if(AppContext.$SINGLETON == null){
      AppContext.$SINGLETON = new AppContext();
   }
   return AppContext.$SINGLETON;
}