//prototype.js

/*

obj.addEventListener( event_anme, function(){...}, [true|false] );

obj.addEventListener({
  onevent1: function(){...},
  onevent2: function(){...},
  before  : (true|false)]
})
			
*/

var iClassBase = Class.create();
iClassBase.prototype = {

	execAfterEvents: function(){
	  var args = $A( arguments );
	  var event = args.shift();
		for( var i = 0; i < this.AfterEventsList[event].length; i++ ) {
			this.AfterEventsList[event][i].apply( this, args.first() );
		} // for	
	}, // execAfterEvents

	execBeforeEvents: function(){
	  var args = $A( arguments );
	  var event = args.shift();
		for( var i = 0; i < this.BeforeEventsList[event].length; i++ ) {
			this.BeforeEventsList[event][i].apply( this, args.first() );
		} // for	
	}, // execBeforeEvents
  
  clearListeners: function( event ) {
    if ( this.BeforeEventsList && this.BeforeEventsList[event] ) {
      this.BeforeEventsList[event] = null;
      var flagB = true;
      for( key in this.BeforeEventsList ) {
        if ( this.BeforeEventsList[key] && this.BeforeEventsList[key].constructor == Array && this.BeforeEventsList[key].length ) flagB = false;
      } // for
      if ( flagB ) this.BeforeEventsList.execAttached = false;
    } // if
    if ( this.AfterEventsList && this.AfterEventsList[event] ) { 
      this.AfterEventsList[event]  = null;
      var flagA = true;
      for( key in this.AfterEventsList ) {
        if ( this.AfterEventsList[key] && this.AfterEventsList[key].constructor == Array && this.AfterEventsList[key].length ) flagA = false;
      } // for
      if( flagA ) this.AfterEventsList.execAttached = false;
    } // if
    if ( this.firstborn ) {
      if (  this.firstborn[event] ) this[event] = this.firstborn[event];
      else this[event] = Prototype.emptyFunction;
    } // if  

    this[event]
  }, // clearListeners
	
	addEventListener: function( event, func , before, enableEqualFunctions ) {
	  if ( typeof event == 'object' && !func ) {
		  var args = event;
			for ( event in args ) {
			  if ( args[event].constructor == Function ) {
			    this.addEventListener( event, args[event], args['before'] );
				}	// if
			} // for
		return;	
		} // if
    before = before || false;
		if( !this[event] ) {
      this.clearListeners( event );
      this[event] = Prototype.emptyFunction;
    } // if
    if ( ( this[event] == Prototype.emptyFunction ) || /.*\{[\s]*\}\)$/.test( this[event].toSource() )) this.clearListeners( event );
		var self = this;
		if( before ) {
	    if ( !this.BeforeEventsList ) this.BeforeEventsList = {execAttached: false};
	    if( !this.BeforeEventsList[event] ) this.BeforeEventsList[event] = [];
	    if( !this.BeforeEventsList.execAttached ) this.BeforeEventsList.execAttached = true;
			var flag = true;
			for ( var i = 0; i < this.BeforeEventsList[event].length; i++ ) {
				if( this.BeforeEventsList[event][i].toSource() == func.toSource() ) {
          flag = false;
          this.BeforeEventsList[event][i] = func;
        } // if 
			} // for
			if ( flag ) this.BeforeEventsList[event].unshift( func );
			else return;

	    if( this.BeforeEventsList[event] && this.BeforeEventsList[event].length == 1 ) {	
        if ( !this.firstborn ) this.firstborn = {};
        this.firstborn[event] = this[event];
			  this[event] = function(){
					self.execBeforeEvents.call( self, event, arguments );
					self.firstborn[event].call( self, arguments );
				};
		  } // if
		} else {
	    if ( !this.AfterEventsList ) this.AfterEventsList = {execAttached: false};
	    if ( !this.AfterEventsList[event] ) this.AfterEventsList[event] = [];
			if ( !this.AfterEventsList.execAttached ) this.AfterEventsList.execAttached = true;
			var flag = true;
			for ( var i = 0; i < this.AfterEventsList[event].length; i++ ) {
				if ( this.AfterEventsList[event][i].toSource() == func.toSource() ) {
          if ( !enableEqualFunctions ) {
            flag = false;
            this.AfterEventsList[event][i] = func;          
          }
        } // if 
			} // for
		  if ( flag )  this.AfterEventsList[event].push( func );
			else return;

	    if ( this.AfterEventsList[event] && this.AfterEventsList[event].length == 1 ) {
        if ( !this.firstborn ) this.firstborn = {};
        this.firstborn[event] = this[event];
			  var tempFunc = this[event];
			  this[event] = function(){
					self.firstborn[event].call( self, arguments );
					self.execAfterEvents.call( self, event, arguments );
				};
		  } // if
		} // if	
	}, // addEventListener
	
	removeEventListener: function( event, func ) {
		if( this.AfterEventsList && this.AfterEventsList[event] ) {
			for( var i = 0; i < this.AfterEventsList[event].length; i++ ) {
			  if( this.AfterEventsList[event][i].toSource() == func.toSource() ) {
				  this.AfterEventsList[event] = this.AfterEventsList[event].without( this.AfterEventsList[event][i] );
					return func;
				}  // if
			} // for
		} // if	
		if( !this.BeforeEventsList || !this.BeforeEventsList[event] )return;
		for( var i = 0; i < this.BeforeEventsList[event].length; i++ ) {
		  if( this.BeforeEventsList[event][i].toSource() == func.toSource() ) {
			  this.BeforeEventsList[event] = this.BeforeEventsList[event].without( this.BeforeEventsList[event][i] );
				return func;
			} // if
		} // for
	} // removeEventListener
}; // iClassBase

var iClass = {
  create: function() {
    var parent = null, properties = $A(arguments);
    if (Object.isFunction(properties[0]))
      parent = properties.shift();

    function klass() {
      Object.extend(this, iClassBase.prototype);
      this.initialize.apply(this, arguments);
      this.createArguments = arguments;
    }
   
    Object.extend(klass, Class.Methods);
    klass.superclass = parent;
    klass.subclasses = [];

    if (parent) {
      var subclass = function() { };
      subclass.prototype = parent.prototype;
      klass.prototype = new subclass;
      parent.subclasses.push(klass);
    }

    for (var i = 0; i < properties.length; i++)
      klass.addMethods(properties[i]);
		  klass.addMethods(iClassBase.prototype)

    if (!klass.prototype.initialize)
      klass.prototype.initialize = Prototype.emptyFunction;

    klass.prototype.constructor = klass;

    return klass;
  }, // create
	
	define: function( inheritedClass ) {
     var res = function() {
      if( this.body )Object.extend( this, this.body );
			Object.extend( this, iClassBase.prototype );
        if( inheritedClass ){
				  this.Super = function(){
				    var args = [];
					  if( !arguments[0] || ! arguments[0].prototype )return;
				    for( var i = 0; i < arguments.length - 1; i++ )
					  {
					    args[i] = arguments[i + 1];
					  }
				    if( arguments[0] && arguments[0].prototype && arguments[0].prototype.body )
					    arguments[0].prototype.body.initialize.apply( this, args )
					  else
					    arguments[0].prototype.initialize.apply( this, args );	 
				  };
				};	
      this.initialize.apply( this, arguments );
    };
	  Object.extend( res.prototype, iClassBase.prototype );
	  Object.extend( res, iClassBase.prototype );
		if( inheritedClass ){
		  Object.extend( res.prototype, inheritedClass.prototype );
		  Object.extend( res.prototype, inheritedClass );
		  if( inheritedClass.prototype.body )Object.extend( res.prototype, inheritedClass.prototype.body );
		}	
		 return res;
  }, // define
  
  parseCreateArgs: function( args ) {
    var res;
    var argsType = typeof( args );
    argsType = argsType.toUpperCase();
    
    if ( args.constructor == Array ) {
      res = [];
      for ( var i=0; i < args.length; i++ ) {
        res.push( this.parseCreateArgs( args[i] ) );
      } // for
    } else if ( argsType == 'OBJECT' && !args.className ) {
      res = {};
      
      for ( argName in args ) {
        var arg = args[argName];
        res[argName] = this.parseCreateArgs( arg );
      } // for
    } else if ( argsType == 'OBJECT' && args.className ) {
      res = this.smartCreate( args );
    } else {
      res = args;
    } // if
    
    return res;
  }, // parseCreateArgs
  
  smartCreate: function( objekt ) {
    var createArgs = objekt.createArguments;
    var className  = objekt.className;
    var resObj     = null;
    
    if ( className ) {
      var args = ( createArgs && createArgs.length == 1 ) ? createArgs[0] : null;
      if ( args ) args = this.parseCreateArgs( args );
        
      var klass = eval( className );
      resObj = new klass( args );
    } // if
    
    return resObj;
  } // smartCreate
}; // iClass

