// JavaScript Document

//Clase global que tiene utilidades y funciones
function BlockAPIClass(){

	this.replaceAll = function(str, r, w){
		if(str)
			return str.replace('/'+r+'/g', w);
		else
			return str;
	};
	
	this.containerInstances = new Array();

	this.addContainer = function(id, cont){
		this.containerInstances[id] = cont;
	};
	
	this.getContainer = function(contId){
		if(this.containerInstances[contId])
			return this.containerInstances[contId];
		else
			return null;
	};
	
	this.getContainerByKey = function(key){
		var res = new Array();
		for(var c in this.containerInstances)
			if(this.containerInstances[c].block.getKey() == key)
				res.push(this.containerInstances[c]);
		return res;
	};
	
	this.callbacks = new Array();
	this.loaded = false;
	this.loading_jquery = false;
	this.loading_boxy = false;
	this.host = '';
	
	this.isLoaded = function(){
		return this.loaded;
	};
	
	this.init = function(callback){
		if(callback)
			this.callbacks.push(callback);
		
		if(!this.loaded){
			
			var self = this;
			if(typeof(jQuery) == 'undefined' && !this.loading_jquery){
				this.loading_jquery = true;
				this.loadScript('js/jquery.js', function(){ 
					alert('listo');
					this.loading_jquery = false;
					self.init(null);
				});
				return;
			}
			/*else if(typeof(Boxy) == 'undefined' && !this.loading_boxy){
				this.loading_boxy = true;
				this.loadScript('js/boxy/javascripts/jquery.boxy.js', function(){ 
					this.loading_boxy = false;
					self.init(null);
				});
				return;
			}*/
		}
		
		if(!this.loaded && /*typeof(Boxy) != 'undefined' &&*/ typeof(jQuery) != 'undefined'){
			this.loaded = true;
			for(var n = 0; n < this.callbacks.length; n++)
				this.callbacks[n]();
			this.callbacks = new Array();
		}
	};
	
	this.loadScript = function(url, callback){
		var script = document.createElement("script");
		script.type = "text/javascript";
		if (script.readyState){  //IE
			  script.onreadystatechange = function(){
				if(script.readyState == "loaded" || script.readyState == "complete"){
					script.onreadystatechange = null;
					callback();
				}
			};
		} else {  //Others
			script.onload = function(){
				callback();
			};
		}
		script.src = url;
		document.getElementsByTagName('head')[0].appendChild(script);
	};
}	


var BlockAPI = (BlockAPI != null)?BlockAPI:new BlockAPIClass();

//Clase que representa a un bloque, a traves de esta clase se puede obtener el contenido del bloque
/*
	Tiene los siguientes métodos públicos:
		- bind(event, function) : Adjunta una función a un evento. La función es llamada cada vez que ocurre el evento
		- refresh() : Actualiza el contenido del bloque. Cuando se termina de cargar se ejecuta el evento "load"
		- login(username, password, remember_me) : Intenta loguear al usuario. Cuando se termina de loguear se ejecuta el evento "login"
		- last() : Carga la ultima versión del bloque. Se ejecuta el evento "load" al terminar de cargar.
		- prev() : Carga la versión previa del bloque. Se ejecuta el evento "load" al terminar de cargar.
		- next() : Carga la versión posterior del bloque. Se ejecuta el evento "load" al terminar de cargar.
*/
function Block(key, version, options, host){

	//Configuracion para obtener los datos del bloque
	this.host = host;
	this.key = key;
	this.version = version;
	this.original_css = 0;
	this.versionId = 0;

	//Propiedades del bloque
	this.content = ''; //Contenido del bloque
	this.date = ''; //Fecha de creacion del bloque completa
	this.dateDistance = '';//Fecha de creacion del bloque relativa
	this.blockOptions = {}; //Opciones del bloque
	this.owner_id = '';
	this.max_version = 1;
	
	//Opciones establecidas para esta instancia
	this.options = (options==null)?{}:options;
	
	//Opciones finales
	this.realOptions = {};
	
	//Propiedades del usuario
	this.logged_in = false;
	this.is_admin = false;
	this.id_usuario = 0;
	
	//Variables internas de la clase
	this.ajaxCall = null; //Variable de la llamada ajax
	this.refreshInterval = false;
	this.logging_in = false;
	
	//Estado interno
	this.errors = new Array();
	this.errors[0] = 'ajaxError';
	this.errors[1] = 'inexistentBlock';
	this.errors[2] = 'inexistentVersion';
	
	//Estados posibles del bloque
	this.statuses = new Array();
	this.statuses[0] = 'initializing', //Inicializando la clase
	this.statuses[1] = 'ready'; //Clase lista para cargar una página
	this.statuses[2] = 'loading'; //Ejecutando el llamado ajax para cargar una página
	this.statuses[3] = 'unknown'; //Estado desconocido

	this.status = this.statuses[0];

	
	//Manejo de propiedades de la conexion
	this.getHost = function(){ return this.host; };
	this.setHost = function(host){ this.host = host; };
	
	//Manejo de propiedades del bloque
	this.getKey = function(){ return this.key; };
	this.getVersion = function(){ return this.version; };
	this.getVersionId = function(){ return this.versionId; };
	this.getMaxVersion = function(){ return this.max_version; };
	this.setContent = function(c){ this.content = c; };
	this.getContent = function(){ return this.content; };
	this.getOptions = function(){ return this.realOptions; };
	this.setOption = function(n, v){ if(this.options) this.options[n] = v; };
	this.getDate = function(){ return this.date; };
	this.getDateDistance = function(){ return this.dateDistance; };
	this.userId = function(){ return this.id_usuario; };
	this.getOriginalCss = function(){ return this.original_css; };
	this.setOriginalCss = function(v){ this.original_css = parseInt(v); };
	
	
	//Manejo de propiedades del usuario
	this.loggedIn = function(){ return this.logged_in; };
	this.isOwner = function(){ return this.isAdmin() || this.userId() != '' && this.userId() == this.owner_id; };
	this.isAdmin = function(){ return this.is_admin; };
	
	//Manejo de eventos
	this.bindings = new Array(); //Lista de eventos
	this.bind = function(evt, fn){ 
		if(evt != ''){
			if(!this.bindings[evt])
				this.bindings[evt] = new Array();
			this.bindings[evt].push(fn);
		}
	};
	//Dispara el evento a todos los que lo estan recibiendo, siempre se pasa como parametro el objeto Block
	this.fireEvent = function(evt, param){
		if(evt != '' && this.bindings[evt]){
			for(var n = 0; n < this.bindings[evt].length; n++)
				this.bindings[evt][n](this, param);
		}
	};
	
	//Manejo del estado del bloque
	this.getStatus = function(){
		return this.status;
	};
	
	this.setStatus = function(n){
		n = parseInt(n);
		if(n >= this.statuses.length)
			n = this.statuses.length-1;
		if(this.statuses[n] != this.status){
			this.status = this.statuses[n];
			this.fireEvent('status_change', this.status);
		}
	};
	
	//Carga el contenido del bloque en la clase
	this.load = function(key, version, options, host){
		this.stopRefresh();
		this.key = key;
		this.version = version;
		if(options)
			for(var opt in options)
				this.setOption(opt, options[opt]);
		if(host != null)
			this.host = host;
		this.refresh();
	};
	
	this.stopRefresh = function(){
		if(this.ajaxCall)
			this.ajaxCall.abort();
	};
	
	this.refresh = function(){
		this.setStatus(2);
		var self = this;
		this.stopRefresh();
		this.ajaxCall = $.ajax({
			url:'Host/getJSON',
			data:{'k':this.key, 'v':this.version, 'r':Math.random()},
			dataType: "json",
			error: function(xhr, textStatus, errorThrown){
				//Error
			},
			processData:true,
			success: function(data){
				self.refreshCallback(data);
			},
			timeout: 15000,
			type:"GET"
		});
	};

	this.refreshCallback = function(data){
		
		if(this.getKey() != data['block']['id'] || this.getVersion() != parseInt(data['version'])) //No es el bloque esperado
			return;

		var c = data['block_content']['Contenido'];
		c = BlockAPI.replaceAll(c, '&lt;', '<');
		c = BlockAPI.replaceAll(c, '&gt;', '>');

		this.date = data['block']['Fecha_creacion'];
		this.dateDistance = data['actualizado'];
		this.version = parseInt(data['version']);
		this.versionId = parseInt(data['block_content']['id']);
		this.max_version = parseInt(data['max_version']);
		this.owner_id = data['block']['Usuario'];
		this.setContent(c);
		this.blockOptions = data['block']['Opciones'];
		var oldInterval = parseInt(this.getOptions()['AutoRefresh']);
		
		this.realOptions = this.options;

		for(var opt in this.blockOptions){
			if(typeof(this.realOptions[opt]) == 'undefined'){
				this.realOptions[opt] = this.blockOptions[opt];
			}
		}

		if(!this.logging_in){
			this.id_usuario = data['id_usuario'];
			this.logged_in = data['logged_in'];
			this.is_admin = data['is_admin'];
		}

		
		var self = this;
		if(this.getOptions()['AutoRefresh'])
			var ar = parseInt(this.getOptions()['AutoRefresh']);
		else
			var ar = 0;
		if(ar >= 15 && ar != oldInterval){
			if(this.refreshInterval)
				clearInterval(this.refreshInterval);
			this.refreshInterval = setInterval(function(){ self.refresh(); }, ar*1000);
		}
		this.setStatus(1);
		this.fireEvent('load', c);
	};
	
	//Carga la ultima version del bloque
	this.last = function(){
		this.load(this.getKey(), 1);
	};
	
	//Carga la version anterior a la actual
	this.prev = function(){
		if(this.getVersion() == this.getMaxVersion()){
			return false;
		}else{
			this.load(this.getKey(), this.getVersion()+1);
			return true;
		}
	};
	
	//Carga la version posterior a la actual
	this.next = function(){
		if(this.getVersion() == 1){
			return false;
		}else{
			this.load(this.getKey(), this.getVersion()-1);
			return true;
		}
	};
	
	this.login = function(username, password, remember_me){
		this.logging_in = true;
		var self = this;
		$.getJSON("Host/getJSON?action=login&username="+username+"&password="+password+"&remember_me="+remember_me+"&r="+Math.random()+"&callback=?", null,
			function(data){
				self.loginCallback(data);
			});	
	};
	
	this.loginCallback = function(data){
		this.logged_in = data['logged_in'];
		this.id_usuario = data['id_usuario'];
		this.is_admin = data['is_admin'];
		this.logging_in = false;
		this.fireEvent('login', data['resultado']);
	};
	
	this.init = function(){
		this.setStatus(1);
	};

	this.init();
}
