/**
 *	Static apc main class
 *	
 *	APC PHPKOD FRAMEWORK
 *	Core Group
 *
 *	Cette classe founis les propriétés et méthodes de base pour faciliter l'utilisation de l'API.
 *	
 *	************************
 *	(c) 2011 / AP netCONCEPT
 *	All Rights Reserved
 *	http://www.apconcept.net
 *	contact@apconcept.net
 *	Author : Antoni Paligot
 *	************************
 *	
 *	@package	Core
 *	@author		Antoni Paligot <contact@apconcept.net>
 *	@since		5.8
 *	@version	0.0.1
 *	@revision	alpha
 */
var apc = {
	
	/**
	 * Version of this class
	 */
	version : '0.0.2',
	/**
	 ***********
	 * Caches
	 ***********
	 */
	/**
	 * Cache de l'appilation en cours
	 */
	_appInstanceCache : null,
    
    /**
	 * Array des instances en cours
	 */
    _i : [],
    /**
	 * Index des instances en cours
	 */
    _in : [],
    /**
	 * URl des scripts chargés dans la page
	 */
	 _dls : [],
    /**
	 * Retourne une instance d'un objet
	 */
	
    GI : function(iName, args)
        {
            if(!apc._i)
                {
                    apc._i = new Array();
                    apc._in = new Array();
                }
            for(var i in apc._i)
                if(apc._in[i] === iName)
                    return apc._i[i];
            
            apc.trace('Creating new instance of '+iName);
            if(typeof window[iName] !== 'function')
                {
                    return null;
                    apc.trace(iName+' is not a valid function');
                }
            var o = new window[iName](args);
            this._i.push(o);
            this._in.push(iName);
            return o;
            
        },
	 
	/**
	 * 	Output a debug element to browser console.
	 *	First arg must be text output reported to the console's browsner
	 *	Second argument deine if the output must be show to user.
	 *	If yes, could be an alert or any rompt on page (overwrite apc.msg function fot that)
	 */
    trace: function(data, report)
        {
            
            if(typeof(console) !== 'undefined' && typeof(console.log) == 'function')
                console.log('oJs : '+data);
            if(report === true)
                apc.msg(data);
        },
	
	/**
	 * 	Send alert to final user
	 */
	msg : function( msg )
		{
			alert(msg);
		},
	
	/**
	 * 	Initioalise la classe statique apc.
	 *	Inscrit les évnèement et écouteurs par défaut.
	 */
	initialize : function()
		{
			
            apc.trace('APC Class initialize...');
            apc.trace('(c) 2011 AP netCONCEPT / Antoni Paligot');
            apc.trace('All rights reserved');
            apc.trace('***');
            apc.trace('support@apconcet.net');
            apc.trace('http://www.apconcept.fr');
            apc.trace('***');
            apc.trace('version '+apc.version+'');
            apc.trace('***');
            apc.trace('Setting default events.');
			apc.events.setEvents(  );
			
		},
	
	/**
	 * Return instance of main application
	 */
	app : function(o)
		{
			if(!o && apc._appInstanceCache !== null)
				return apc._appInstanceCache
			
			var pt = new ApcApp(o);
			apc.app._appInstanceCache = pt;
			return pt;
		},
	
	/**
	 * 	Charge un fichier JS ou CSS dans la page en cours.
	 *	Inspiré de la fonction sur http://wiip.fr/content/chargement-dynamique-de-plusieurs-scripts-javascript
	 */
	loadScript : function(url, callback) 
		{
			apc.trace('Loading file '+url);
			opts = (typeof(callback) === 'object') ? callback : {};
			var fcallback = (typeof(callback) === 'object') 
						? ((typeof(callback.callback) === 'function') ? function(e){ callback.callback(e); } : function(){ } )
						: ((typeof(callback) === 'function') ? function(e){ callback(e); } : function(){ } );
			var e = document.createElement("script");
    		e.src = url;
			if(opts.hack === true)
				e.src +=  + "?" + Math.random();
			e.type = "text/javascript";
			if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
			  e.onreadystatechange = function(){
				if (this.readyState == 'loaded' || this.readyState == 'complete')
					{
						apc.trace('File loaded.');
						fcallback();
					}
				else if(this.readyState != 'loading')
					apc.trace('Could not load file '+url+' return : '+this.readyState);
			  }
			} else 
				e.onload = function(){ apc.trace('File loaded.'); fcallback(); };
				
			document.getElementsByTagName("head")[0].appendChild(e);
			apc._lds.push(url);
		
		},
	
	/**
	 *	Idem loadScriptOnce, mais ne le charge qu'une fois.
	 */
	loadScriptOnce : function( url, callback )
		{
			apc._lds = apc._lds || new Array();
			if(typeof(url) == 'string')
				{
					if (apc._lds.indexOf(url) !== -1) 
						{
							apc.trace('File '+url+' already loaded.');
							return -1;
						}
					return apc.loadScript( url, callback );
				}
			else
				{
					var q = new ApcQueue;
					for( var i in url )
						{
							if(apc._lds.indexOf(url) !== -1)
								continue;
							q.queue( url[i] );
						}
					if(typeof(callback) == 'function')
						q.onComplete = callback;
					else if(typeof(callback) == 'object' && typeof(callback.callback) == 'function')
						q.onComplete = callback.callback;
						
					q.load();
				}
		},
	/**
	 * 	Charge les librairies courantes.
	 *	Liste des librairies disponibles :
	 *	
	 *	jquery		Librairie JQuery (CDN jQuery)
	 *	jqueryui	Librairie JQery UI
	 *	jquerytools	Librairie jQuery Tools
	 *	googleapi	API Google
	 *				Insérer votre clé Google API à la place du
	 *				paramètre version
	 *
	 * 	Le CDN de Google est utilisé.
	 *	Liste des adresse ici :
	 *	http://code.google.com/intl/fr-FR/apis/libraries/devguide.html#load_the_javascript_api_and_ajax_search_module
	 */
	lib : function( lib, version, opts )
		{
			apc.trace('Inclusion de la librairie '+lib);
			opts = (typeof(version) === 'object') ? version : ((typeof(opts) === 'object') ? opt : {});
			opts.callback = opts.callback ||  function(){};
			version = ( typeof(version) === 'object' ) ? (version.object ? version.object : null) : version;
			switch(lib)
				{
					case 'googleapi' :
						apc.loadScriptOnce( 'https://www.google.com/jsapi?key='+version, opts.callback );
						break;
						
					case 'jquery' :
						apc.loadScriptOnce( 'http://code.jquery.com/jquery-'+( version ? version : '1.6.4' )+'.min.js', opts.callback );
						break;
						
					case 'jqueryui' :
						apc.lib( 'jquery', { callback:function(){ apc.loadScriptOnce( 'https//ajax.googleapis.com/ajax/libs/jqueryui/'+( version ? version : '1.2.6' )+'/jquery-ui.min.js', opts.callback ); } } );
						break;
						
					case 'jquerytools' :
						apc.lib( 'jquery', { callback:function(){ apc.loadScriptOnce( 'http://cdn.jquerytools.org/'+( version ? version : '1.2.6' )+'/full/jquery.tools.min.js', opts.callback ); } } );
						break;
						
					case 'chrome-frame' :
						apc.loadScriptOnce( 'https://ajax.googleapis.com/ajax/libs/chrome-frame/'+( version ? version : '1.0.2' )+'/CFInstall.min.js', opts.callback );
						break;
						
					case 'ext-core' :
						apc.loadScriptOnce( 'https://ajax.googleapis.com/ajax/libs/ext-core/'+( version ? version : '3.1.0' )+'/ext-core-debug.js', opts.callback );
						break;
						
					case 'mootools' :
						apc.loadScriptOnce( 'https://ajax.googleapis.com/ajax/libs/mootools/'+( version ? version : '1.4.1' )+'/mootools-yui-compressed.js', opts.callback );
						break;
						
					case 'prototype' :
						apc.loadScriptOnce( 'https://ajax.googleapis.com/ajax/libs/prototype/'+( version ? version : '1.7.0.0' )+'/prototype.js', opts.callback );
						break;
						
					case 'scriptaculous' :
						apc.lib( 'prototype', { callback:function(){ apc.loadScriptOnce( 'https://ajax.googleapis.com/ajax/libs/scriptaculous/'+( version ? version : '1.9.0' )+'/scriptaculous.js', opts.callback ) } } );
						apc.loadScriptOnce( 'https://ajax.googleapis.com/ajax/libs/scriptaculous/'+( version ? version : '1.9.0' )+'/scriptaculous.js', opts.callback );
						break;
						
					case 'SWFObject' :
						apc.loadScriptOnce( 'https://ajax.googleapis.com/ajax/libs/swfobject/'+( version ? version : '2.2' )+'/swfobject.js', opts.callback );
						break;
						
					case 'webfont' :
						apc.loadScriptOnce( 'https://ajax.googleapis.com/ajax/libs/webfont/'+( version ? version : '1.0.22' )+'/webfont.js', opts.callback );
						break;
						
					case 'cufon' :
						apc.loadScriptOnce( 'http://cufon.shoqolate.com/js/cufon-yui.js', opts.callback );
						break;
					
					default :
						apc.trace('Aucune librairie correspondante');
						return false;
						break;
				}
			
			return true;
		},
	
	
	/**
	 * 	Charge des fichiers d'un plugin
	 *	Liste des plugins disponibles :
	 *	
	 *	jquery		Librairie JQuery (CDN jQuery)
	 *	jqueryui	Librairie JQery UI
	 *	jquerytools	Librairie jQuery Tools
	 *	googleapi	API Google
	 *				Insérer votre clé Google API à la place du
	 *				paramètre version
	 *
	 * 	Le CDN de Google est utilisé.
	 *	Liste des adresse ici :
	 *	http://code.google.com/intl/fr-FR/apis/libraries/devguide.html#load_the_javascript_api_and_ajax_search_module
	 */
	plugin : function( lib, version, opts )
		{
			apc.trace('Inclusion d\'un plugin '+lib);
			opts = opts || {}
			opts.callback = opts.callback || function(){};
			switch(lib)
				{
					/*case 'googleapi' :
						apc.loadScript( 'https://www.google.com/jsapi?key='+version, opts.callback );
						break;*/
					
					default :
						apc.trace('Aucun plugin correspondant');
						return false;
						break;
				}
			
			return true;
		},
	
	/**
	 * 	Static class apc.events
	 *
	 *	Gere les évènements par défaut de la page (type window.onLoad...)
	 *
	 */
	events : {
		
		/**
		 * Définit les écouteurs par défaut
		 */
		setEvents : function()
			{
				/**
				 *	Fired when apc initialized
				 * 	Define here required events for apc.
				 */
				 apc.events.addListener( window, 'load', apc.events.domLoaded );
			},
		
		/**
		 * Ajoute un écouteur
		 */
		addListener : function( $obj, $event, $func )
			{
				/**
				 * Opera, Netscape, FF, Chrome
				 */
				if(typeof( $obj.addEventListener ) === 'function')
					{
						return $obj.addEventListener( $event, $func, false );
					}
				/**
				 * IE 8-
				 */
				else if(typeof( $obj.attachEvent ) === 'object')
					{
						return $obj.attachEvent( "on"+$event, $func );
					}
				/**
				 * Could not support DOM Level < 2.0
				 */
				else
					{
						apc.trace('[!] Adding events is not suported by your browsner (Dom Level 2 support required)');
						return false;
					}
			},
		
		/**
		 *	Just for output "Dom is loaded"...
		 */
		domLoaded : function()
			{
				apc.trace('Dom loaded, page is ready.');
			}
	},
	
	plugins : {
		
		ga : {
			
			stat:function(url)
				{
					this.trace('stat with Google Analytics URL '+url);
					if(pageTracker)
						{	
							try {
								pageTracker._trackPageview(url);
							} catch(err) {}
						}
					else
						{
							app.trace('[!] Google Analytics is not instancied');
						}
				}

			
		}
		
	}
}

apc.initialize();

var ApcQueue = function(){ this.initialize(); return this; }

ApcQueue.prototype = {
	
	_items : [],
	_current : 0,
	
	initialize : function(){
		this._items = new Array();
	},
	
	onComplete : function(){ apc.trace('Queue complete'); },
	
	onError : function(){ apc.trace('Unable to load file'); },
	
	queue : function( script ){
		
		apc.trace('adding '+script+' in queue');
		this._items.push( script );
		
	},
	
	next : function(){
		this._current++;
		if(!this._items[this._current])
			return this.onComplete();
		
		this.load();
	},
	
	current : function(){
		return this._items[this._current];
	},
	
	load : function(){
		var _i = this;
		apc.loadScriptOnce( this.current(), {callback:function(){ _i.next(); }, onError:function(){ _i.onError(); }} );
	}
	
}

/**
 * On étend la clase Array avec une fonction indexOf
 */
if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(elt /*, from*/)
  {
    var len = this.length;

    var from = Number(arguments[1]) || 0;
    from = (from < 0)
         ? Math.ceil(from)
         : Math.floor(from);
    if (from < 0)
      from += len;

    for (; from < len; from++)
    {
      if (from in this &&
          this[from] === elt)
        return from;
    }
    return -1;
  };
}

var ApcAPP = function()
	{
		this.initialize(o);
		return this;
	}
	
ApcAPP.prototype = {
    
    version : '0.1',
    
    opts : {},
    
    page : null,
    
    // Retourne l'instance de la page en cours
    GP : function()
        {
            if(!this.page)
                this.trace('Page object is not initialized yet. Please wait for MainLoad event');
            else
                return this.page;
        },
    


        
    initialize: function(o)
        {
            this.trace('*********************************************');
            this.trace('Begin new session with '+o.length+' arguments');
            var _o = o || {  };
            this.opts = {
                page : _o.page || null,
            }
            this.onLoad();
        },
    
    /*
     * fire just after app initialize function.
     */
    onLoad : function()
        {
            /*
             * fire onLoaded events when DOM is loaded
             */
            $(function(){ getApp().onDomLoaded(); });
            $(window).trigger('app:domLoad');
            
        },
    
    /*
     * Fire when DOM is loaded
     */
    onDomLoaded: function()
        {
            this.trace('DOM loaded');
            $(window).trigger('app:domLoaded');
            this.trace('begin loading contents');
            this.loadContents();
        },
    
    loadContents : function()
        {
            $(window).trigger('app:mainLoad');
            this.initializePage();
            this.onDocumentReady();
        },
    
    /*
     * Init page
     */
    initializePage : function()
        {
            if(!this.pages[this.opts.page])
                {
                    this.page = this.pages.unknown;
                }
            else
                {
                    this.page = this.pages[this.opts.page];
                }               
            this.pages['common'].initialize();
            this.page.initialize()
        },
    
    /*
     * Called when everything on the main routine is done and complete
     */
    onDocumentReady : function()
        {
            this.trace('Document loading complete, page is ready');
            $(window).trigger('app:pageReady');
        }
    
}
