/**
 * CSS Browser Selector   v0.2.5
 * Documentation:         http://rafael.adm.br/css_browser_selector
 * License:               http://creativecommons.org/licenses/by/2.5/
 * Author:                Rafael Lima (http://rafael.adm.br)
 * Contributors:          http://rafael.adm.br/css_browser_selector#contributors
 */
var css_browser_selector = function() {
	var
		ua=navigator.userAgent.toLowerCase(),
		is=function(t){return ua.indexOf(t) != -1;},
		h=document.getElementsByTagName('html')[0],
		b=(!(/opera|webtv/i.test(ua))&&/msie (\d)/.test(ua))?('ie ie'+RegExp.$1):is('gecko/')? 'gecko':is('opera/9')?'opera opera9':/opera (\d)/.test(ua)?'opera opera'+RegExp.$1:is('konqueror')?'konqueror':is('applewebkit/')?'webkit safari':is('mozilla/')?'gecko':'',
		os=(is('x11')||is('linux'))?' linux':is('mac')?' mac':is('win')?' win':'';
	var c=b+os+' js';
	h.className += h.className?' '+c:c;
}();


/**
 * Locale settings
 */
var gt = new Gettext({});
function _(msg) {return gt.gettext(msg);}


var check_requirements = function() {
	var html = $$("html")[0];

	if (html.hasClassName("ie6") || html.hasClassName("ie7")) {
		var msg = _("Su navegador no es compatible con DigitalDOCU.\nLos navegadores soportados y sus versiones mínimas son:")
			+ "\n\n\t- Mozilla FireFox 3.5\n"
			+ "\t- Microsoft Internet Explorer 8\n"
			+ "\t- Google Chrome 3\n"
			+ "\t- Apple Safari 4";
		alert(msg);
	}
}();

/**
 * Show document previews
 * 
 * This function must be accesible as a JS standard function so it can be call
 * from the parent to an iframe
 */
var showDocumentPreview = function() {
	$$("iframe.TrueIframe").each(function(elm) {
		elm.show();
	});

	var iframe = $("closesFrame");
	if (iframe != null) {
		iframe.contentWindow.showDocumentPreview();
	}
};

/**
 * Hide document previews
 * This function must be accesible as a JS standard function so it can be call
 * from the parent to an iframe
 */
var hideDocumentPreview = function() {
	$$("iframe.TrueIframe").each(function(elm) {
			elm.hide();
	});

	var iframe = $("closesFrame");
	if (iframe != null) {
		iframe.contentWindow.hideDocumentPreview();
	}
};


/**
 * Merge method for js objects
 */
Object.extend(Object, {
	isObject: function (object) {
		return object && object.constructor === Object;
	},
	merge: function( dest, source ) {
		for( var x in source ) {
			if ( Object.isObject(source[x]) ) {
				if ( !dest[x] ) {dest[x] = {}}
				Object.merge(dest[x], source[x]);
			} else {
				dest[x] = source[x];
			}
		}
		return dest;
	}
});

/**
 * Check if string is suitable to be a file name
 */
String.prototype.isValidFilename = function()
{
	return !(this.search(/(\\)|(\/)|(\?)|(\*)|(:)|(<)|(>)/) > 0);
};

String.prototype.getFileExtension = function()
{
	if (this.empty()) {
		return "";
	}

	var pos = this.lastIndexOf(".");
	return (pos > 0) ? this.substring(pos, this.length) : "";
};

/**
 * Split camelized strings into words
 */
String.prototype.uncamelize = function(separator)
{
	var sep = separator || '-';
	return this.replace(/[a-zA-Z][A-Z0-9]|[0-9][a-zA-Z]/g, function(match) {
		return match.charAt(0) + sep + match.charAt(1);
	});
};

/**
 * Serialize an array into PHP serialize formatted string
 */
Array.prototype.serialize = function()
{
    var res = 'a:' + this.length + ':{';
    for(i = 0; i < this.length; i++)
    {
        res += 'i:' + i + ';s:' + this[i].length + ':"' + this[i] + '";';
    }
    res += '}';

    return res;
};

Array.prototype.findIndex = function(value)
{
    var ctr = -1;
    for (var i = 0; i < this.length; i++) {
        // use === to check for Matches. ie., identical (===), ;
        if (this[i] == value) {
            return i;
        }
    }
    return ctr;
};

/**
 * Base64 encoder/decoder class
 */
var Base64 = {
	_keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

	/**
	 * Encode a string
	 *
	 * @param {String} input
	 * @return {String}
	 */
	encode: function(input)
	{
		var output = "";
		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
		var i = 0;

		input = Base64._utf8_encode(input);

		while (i < input.length) {
			chr1 = input.charCodeAt(i++);
			chr2 = input.charCodeAt(i++);
			chr3 = input.charCodeAt(i++);

			enc1 = chr1 >> 2;
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
			enc4 = chr3 & 63;

			if (isNaN(chr2)) {
				enc3 = enc4 = 64;
			} else if (isNaN(chr3)) {
				enc4 = 64;
			}

			output = output + this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
				this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
		}

		return output;
	},

	/**
	 * Decode a string
	 *
	 * @param {String} input
	 * @return {String}
	 */
	decode: function(input)
	{
		var output = "";
		var chr1, chr2, chr3;
		var enc1, enc2, enc3, enc4;
		var i = 0;

		input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

		while (i < input.length) {
			enc1 = this._keyStr.indexOf(input.charAt(i++));
			enc2 = this._keyStr.indexOf(input.charAt(i++));
			enc3 = this._keyStr.indexOf(input.charAt(i++));
			enc4 = this._keyStr.indexOf(input.charAt(i++));

			chr1 = (enc1 << 2) | (enc2 >> 4);
			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
			chr3 = ((enc3 & 3) << 6) | enc4;

			output = output + String.fromCharCode(chr1);

			if (enc3 != 64) {
				output = output + String.fromCharCode(chr2);
			}
			if (enc4 != 64) {
				output = output + String.fromCharCode(chr3);
			}
		}

		output = Base64._utf8_decode(output);
		return output;
	},

	/**
	 * Encode UTF-8 strings
	 *
	 * @param {String} string
	 * @return {String}
	 */
	_utf8_encode : function (string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";

		for (var n = 0; n < string.length; n++) {
			var c = string.charCodeAt(n);

			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}
		}

		return utftext;
	},

	/**
	 * Decode UTF-8 strings
	 *
	 * @param {String} utftext
	 * @return {String}
	 */
	_utf8_decode: function(utftext)
	{
		var string = "";
		var i = 0, c = 0, c2 = 0, c3 = 0;

		while (i < utftext.length) {
			c = utftext.charCodeAt(i);

			if (c < 128) {
				string += String.fromCharCode(c);
				i++;
			}
			else if((c > 191) && (c < 224)) {
				c2 = utftext.charCodeAt(i+1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}
			else {
				c2 = utftext.charCodeAt(i+1);
				c3 = utftext.charCodeAt(i+2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}
		}

		return string;
	}
};


/**
 * Global AJAX responders.
 * Adds a timeout callback that is fired when the AJAX request doesn't respond for a while.
 * If timeout is fired, the request is cancelled.
 */
Ajax.Responders.register({
	/* Set a timeout observer for each new AJAX request */
	onCreate: function(request) {
		if (request.options['wait']) {
			var wait = parseInt(request.options['wait'], 10);

			request['timeoutId'] = window.setTimeout(
				function() {
					// If we have hit the timeout and the AJAX request is active, abort it and let the user know
					var state = request.transport.readyState;
					if (state == 1 || state == 2 || state == 3) {
						request.transport.abort();
						// Run the onTimeout method if we set one up when creating the AJAX object
						if (request.options['onTimeout']) {
							request.options['onTimeout'](request.transport, request.json);
						}
					}
				},
				wait
			);
		}
	},
	/* Clear the observer timeout on successful requests */
	onComplete: function(request) {
		if (request['timeoutId']) {
			window.clearTimeout(request['timeoutId']);
		}
		request.onreadystatechange = Prototype.emptyFunction; // avoid memory leak in MSIE: clean up
	}
});

/**
 * Global AJAX error message.
 * Deal with customized IE error messages and standard HTTP error codes.
 */
Ajax.showError = function(req)
{
	var msg;
	var target = req.request.url;
	switch( req.status ) {
		case 12029:
			msg = 'ERROR_INTERNET_CANNOT_CONNECT';
		case 12030:
			msg = 'ERROR_INTERNET_CONNECTION_ABORTED';
		case 12031:
			msg = 'ERROR_INTERNET_CONNECTION_RESET';
		case 12152:
			msg = 'ERROR_HTTP_INVALID_SERVER_RESPONSE';
		case 12159:
			msg = "ERROR_INTERNET_TCPIP_NOT_INSTALLED: "
				+ _("Se perdió la comunicación con el servidor local.\nNo se pudo acceder a la url")
				+ " \"" + target + "\".";
			break;
		case 404:
			msg = _("No existe la url") + " \"" + target + "\".\n" + req.responseText;
			break;
		case 403:
			msg = _("Acceso denegado al intentar acceder a la url") + "\"" + target
				+ "\".\n" + req.responseText;
			break;
		default:
			msg = "Error status code: " + req.status + "\n" + req.responseText;
	}
	alert(msg);
};

/**
 * Validates a date string
 *
 * @param {String}	value
 *
 */
var validate_date = function(value){
    var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/;
    if(!regex.test(value)) return false;
        var d = new Date(value.replace(regex, '$2/$1/$3'));
        return ( parseInt(RegExp.$2, 10) == (1+d.getMonth()) ) &&
               ( parseInt(RegExp.$1, 10) == d.getDate()) &&
               ( parseInt(RegExp.$3, 10) == d.getFullYear() );
};


/**
 * Main application class
 */
var DigitalDocu = Class.create({
	/**
	 * @constructor
	 */
	initialize: function()
	{
		// holds tab objects
		this.tabs = {scan: null, archive: null, view: null, closes: null};
		this.currentTabName = "";

        if ($("logout")){
            $("logout").down("a").observe("click", function(ev){
                window.onbeforeunload = null; //Disable unload event when user does logout
                window.location = ev.target.href;
            });
        }

        //checks if the client is updated with the las version of the phar
        var checker = new DigitalDocu.Checks();
        
        // if any error pops up, the tabs are not displayed
        if (checker.execute(false, this)) {
            this.enableMainTabs();
        }
        else {
            // hides the tabs, if the user updates it will trigger the applicationcallback
            $("main-tabs").select("a").each(function(item) {
                item.hide();
            }.bind(this));
        }
	},
    
    /**
     * Enables the main tabs
     */
    enableMainTabs: function() {
        
        $("main-tabs").select("a").each(function(item) {
            item.show();
        }.bind(this));
        
        // add listeners on tabs
        $("main-tabs").select("a").each(function(item) {
            item.observe("click", this.toggleTab.bindAsEventListener(this));

            if (item.hasClassName("current")) {
                this.currentTabName = item.id.substring(0, item.id.length-4)
            }
        }.bind(this));

        this.dispatch(this.currentTabName);
    },

	/**
	 * Gets the pointers to JS objects of each application tab.
	 *
	 * @return {Array}
	 */
	getTabObjects: function()
	{
		return this.tabs;
	},

	/**
	 * Toggle between main tabs.
	 *
	 * @param {Event}	ev
	 * @param {String}	tab		Tab id
	 */
	toggleTab: function(ev, tab)
	{
		if (ev == null && tab != undefined) {
			tab = $(tab + "-tab");
		}
		else {
			tab = ev.findElement('a');
			Event.stop(ev);
		}

		var tabName = tab.id.substring(0, tab.id.length-4);
		var content = $$("div." + tab.id)[0];

		if (tab.hasClassName("current")) { // is current tab, do nothing
			Event.stop(ev);
			return;
		}

		// hide previous selected tab
		var cur = $("main-tabs").down("a.current");
		if (cur != null) {
			var curTabName = cur.id.substring(0, cur.id.length-4);

			if (this.tabs[curTabName]["hide"]) {
				this.tabs[curTabName]["hide"](); // custom hide callback
			}
			else {
				$$("div." + cur.id)[0].hide();
			}

			cur.removeClassName("current");
		}

		// show selected tab
		tab.addClassName("current");
		this.currentTabName = tabName;

		if (this.tabs[tabName] && this.tabs[tabName]["show"]) {
			this.tabs[tabName]["show"](); // custom show callback
		}
		else {
			content.show();
		}

		// instantiate tab object
		if (this.tabs[tabName] == null) {
			this.dispatch(tabName);
		}
		else {
			this.tabs[tabName].repaint();
		}
		
		// reset the message information everytime the tab changes
		new MessageDD().show(null);
	},

	/**
	 * Instantiate one tab object.
	 *
	 * @param {String} name
	 */
	dispatch: function(name)
	{
		this.currentTabName = name;
		switch(name) {
			case "scan":
				this.tabs.scan = new Scan();
                this.tabs.scan.setApplicationCallback(this);
				this.tabs.scan.repaint();
				break;
			case "archive":
				this.tabs.archive = new Archive();
				this.tabs.archive.setApplicationCallback(this);
				this.tabs.archive.update();
				this.tabs.archive.repaint();
				break;
			case "view":
				this.tabs.view = new View();
				this.tabs.view.setApplicationCallback(this);
				this.tabs.view.update();
				this.tabs.view.repaint();
				break;
			case "closes":
				this.tabs.closes = new ClosesTab();
				this.tabs.closes.setApplicationCallback(this);
                this.tabs.closes.repaint();
				break;
            case "mail":
				this.tabs.mail = new Mail();
				/*this.tabs.mail.setApplicationCallback(this);
				this.tabs.mail.update();
				this.tabs.mail.repaint();*/
				break;
		}
	}
    });
    
    
var MessageDD = Class.create({  
    
    /**
	 * @construct
	 */
	initialize: function()
	{
        this.info = $("info");
		this.iframe = false;
    },
	
	/**
	 * Determines wheather the message is in an iframe or not
	 *
	 * @param {bool} isIframe
	 */
	setIframe: function(isIframe)
	{
		this.iframe = isIframe;
	},
    
    /**
	 * Displays the information contained in an object in the page header.
	 *
	 * @param {Object} json
	 */
	show: function(json)
	{		
		var MAX_LENGTH = 130;
		var WAIT_TIME = 10;
		
		if (this.info == null) {
			if (json != null)
				alert(json._message);
		}
		else {
			
			if (json == null) {
				this.info.update();
				$jQ(this.info).fadeOut("slow");
			}
			else {
				// adds the new message
				var img = null;
				var timerFlag = false;
				switch (json._message_type) {
					case "error":
						img = new Element("img", {src: "/img/ico-error.png"})
						this.info.className = "error";
						break;
					case "info":
						img = new Element("img", {src: "/img/ico-info.png"})
						timerFlag = true;
						this.info.className = "info";
						break;
					case "warn":
						img = new Element("img", {src: "/img/ico-alert.png"})
						this.info.className = "warn";
						break;
				}

				var msg = json._message;
				var msgDisplayed = (json._message.length > MAX_LENGTH) ? 
					json._message.substring(0, MAX_LENGTH - 4) + " ..." :
					json._message;
				var txt = new Element("span", {title: msg}).insert(msgDisplayed.replace("\n", "<br/>"));

				this.info.update(img)
					.insert(txt);

				// sets the message id
				var messageId = Math.floor(Math.random()*11);
				this.setID(messageId);

				// the info messages must vanish after some seconds
				if (timerFlag) {
					new PeriodicalExecuter(this.hide.bind(this, messageId), WAIT_TIME);
				}

				$jQ(this.info).fadeIn("slow");
			}
		}
	},
	
	/**
	 * Hides the current message if it matchs with the one passed as param
	 *
	 * @param {String} messageId MessageId to be deleted
	 * @param {PeriodicalExecuter} pe Periodical executer object
	 */
	hide: function(messageId, pe ) {
		
		// only if the message that is currently showing up is the
		// one triggered by event
        $jQ("#info."+messageId).fadeOut("slow");
		// stops the periodical executer
		pe.stop();
	},
    
    /**
	 * Sets the id of the current message that it's displayed
	 * 
	 * @param {floor} id Message id
	 */
	setID: function(id) {
		this.messageId = id;
        this.info.addClassName(id);
	},
	
	/**
	 * @return floor
	 */
	getID: function() {
		return this.messageId;
	}
});

/**
 * Abstract class with common method for tab objects.
 */
var BaseTab = Class.create({
	/**
	 * @construct
	 */
	initialize: function()
	{
		window.onresize = this.repaint.bind(this);
		var cont = this.getTabContainer();
		
		if (cont != null && !this.isLoaded()) { // load tab content
			var options = {
				onFailure: Ajax.showError,
				onException: function(req, ex) {
					alert(_("Error al crear objeto AJAX: ") + ex.message);
				},
				onCreate: function(req) {
					var l = new Element("img", 
                        {className: "loading-bar",src: "/img/loading-bar.gif", alt: _("Cargando")});
					cont.update(l);
				},
				onSuccess: function(req, json) {
					cont.replace(req.responseText);
                    $jQ('.ddscrollbar').jScrollPane({verticalGutter:0});
				},
				asynchronous: false,
				requestHeaders: {Accept: "text/html"}
			};

			new Ajax.Request(this.getBaseUrl(), options);
		}
        
		this.setControlDefaultText();
	},
    
    attachListeners: function()
    {
        var btnHideSidebar = $('closesidebar');
        if ( btnHideSidebar ) {
            btnHideSidebar.stopObserving();
            btnHideSidebar.observe('click',this.toggleSidebar.bind(this));
        }
    },
    
    toggleSidebar: function()
    {
        if ( $('closesidebar').hasClassName('close') ){
            $('content').setStyle({'left':'352px'});
            $('sidebar').setStyle({'left':'0'});
            $('closesidebar').removeClassName('close');
        }
        else {
            $('content').setStyle({'left':'30px'});
            $('sidebar').setStyle({'left':'-322px'});
            $('closesidebar').addClassName('close');
        }
        this.repaint();
    },

	/**
	 * Gets the element of active tab.
	 */
	setControlDefaultText: function() {
		$jQ('input.defaultText').focus(function(){
            if ($jQ(this).val() == $jQ(this)[0].title)
            {
                $jQ(this).removeClass("defaultTextActive");
                $jQ(this).val("");
            }
        });

        $jQ("input.defaultText").blur(function()
        {
            if ($jQ(this).val() == "")
            {
                $jQ(this).addClass("defaultTextActive");
                $jQ(this).removeClass("selected");
                $jQ(this).removeClass("document");
                $jQ(this).val($jQ(this)[0].title);
            }
        });

        $jQ('input.defaultText').blur();
	},

	/**
	 * Gets the element of active tab.
	 *
	 * @return {Element}
	 */
	getTabContainer: function()
	{
		var aux = $$("div." + this.getTabName() + "-tab"); // div.name-tab
		if (aux.size() > 0) {
			return aux[0];
		} else {
			return null;
		}
	},

    /**
	 * Opens selected menu item in a modal window.
	 *
	 * @param {Event}	ev
	 * @param {String}	target
	 */
	showMenu: function(ev, target)
	{
		var aux = target.split("/");

		switch (aux[aux.length-1]) {
			case "Entity":
				var e = new Entity();
				e.setApplicationCallback(this.getApplication());
				break;

			case "Category":
				var c = new Category();
				c.setApplicationCallback(this.getApplication());
				break;

			case "Type":
				var t = new Type();
				t.setApplicationCallback(this.getApplication());
				break;

			case "Subtype":
				var s = new Subtype();
				s.setApplicationCallback(this.getApplication());
				break;
		}

		if (ev != undefined) {
			Event.stop(ev);
		}
	},

	/**
	 * Checks if tab's content is loaded
	 *
	 * @return {Boolean}
	 */
	isLoaded: function()
	{
		var cont = this.getTabContainer();
		if (cont == null || cont.innerHTML.stripTags().strip() == "" || 
			cont.down(".error") != null || cont.down(".loading") != null) {
			return false;
		}

		return true;
	},

	/**
	 * Sets the controller base url of current menu option.
	 *
	 * @param {String} url
	 */
	setBaseUrl: function(url)
	{
		this.baseUrl = new String(url);
	},

	/**
	 * Gets the controller base url for current tab.
	 * Ex. /index.php/Archive
	 *
	 * @return {String}
	 */
	getBaseUrl: function()
	{
		return this.baseUrl;
	},

	/**
	 * Sets the tab name
	 *
	 * @param {String} name
	 */
	setTabName: function(name)
	{
		this.tabName = new String(name);
	},

	/**
	 * @return String
	 */
	getTabName: function()
	{
		return this.tabName;
	},

	/**
	 * @param {DigitalDocu} callback
	 */
	setApplicationCallback: function(callback)
	{
		this.application = callback;
	},

	/**
	 * @return DigitalDocu
	 */
	getApplication: function()
	{
		return this.application;
	},	

    /**
     * @return {Boolean} entitySelected
     */
    isEntitySelected: function()
    {
      var entityName = $("__entityName").value;
        
        if (entityName == "") { // entity not selected, popup entity selector
			this.showMenu(Prototype.emptyFunction(), "/index.php/Entity");
            return false;
		}
        else{
            return true;
        }
    },

    /**
	 * @return {String}
	 */
	_requestTaskId: function(msg, ssid)
	{
		var taskId = "";
		var options = {
			onFailure: Ajax.showError,
			onException: function(req, ex) {alert(_("Error al crear objeto AJAX: ") + ex.message);},
			onSuccess: function(req, json) {
				var msg = new Message(req.responseText);
				taskId = msg.getMessageId();
			},
			onTimeout: function(req) {alert("timeout View::_requestTaskId()");},
			wait: 10000,
			parameters: {
				Action: "SendMessage",
				MessageBody: msg,
				MessageId: ""
			},
			requestHeaders: {Accept: "text/xml"},
			asynchronous: false
		};

		if (ssid != null) {
			options.parameters.ssid = ssid;
		}

		var target = "/index.php/mqs/ProgressTask";
        
        // in closes, the queue's call is redirected to the DD server
		if (this.getTabName() == "closes") {
            target = this.closesParams.ddUrl + target;
		}

		new Ajax.Request(target, options);
		return taskId;
	},
		
    
    /**
     * Get the value of an input, taking care of "defaultText" property
     * @param {String} id Input identifier
     */
    getInputValue: function( id )
    {
        if ( $(id).hasClassName("defaultTextActive") ) {
            return "";
        }
        else {
            return $F(id);
        }
    }
});

/**
 *
 */
var Scan = Class.create(BaseTab, {
	/**
	 * @constructor
	 */
	initialize: function($super)
	{
		this.setBaseUrl("/index.php/Scan");
		this.setTabName("scan");

		var isSafari = $$("html")[0].hasClassName("safari");

		if (!isSafari && !deployJava.versionCheck("1.6+")) { // check Java availability
			deployJava.setInstallerType("kernel");
			deployJava.installLatestJRE();
		}

		//$super(); // BaseTab::initialize();
		window.onresize = this.repaint.bind(this);
		var cont = this.getTabContainer();

		if (!this.isLoaded()) { // load tab content
			var options = {
				onFailure: Ajax.showError,
				onException: function(req, ex) {
					alert(_("Error al crear objeto AJAX: ") + ex.message);
				},
				/*onCreate: function(req) {
					var l = new Element("div", {className: "scanloading"}).insert(new Element("br"))
						.update(_("Por favor, espere mientras se carga la página ..."));
					cont.update(l);
				},*/
				onSuccess: function(req, json) {
					cont.replace(req.responseText);
				},
				asynchronous: true,
				requestHeaders: {Accept: "text/html"}
			};

			new Ajax.Request(this.getBaseUrl(), options);

			//show loading while applets loads
			new PeriodicalExecuter(function(pe) {
				if (this.isAppletLoaded()){
					if ($("scanLoading") != undefined){
						$("scanLoading").hide();
					}
					if (this.application.currentTabName == "scan"){
						$("scanApplet").setStyle({visibility: "visible"});
						this.repaint();
					}
					pe.stop();
				}
			}.bind(this), 1);
		}
	},

	isAppletLoaded: function()
	{
		var applet = this.getTabContainer().down("applet");
		var loaded = false;

		//try-catch becausse IE throws exception if applet has loaded successfully
		try {
			loaded = (applet.isActive != undefined);
            if (Prototype.Browser.IE)
                {
                    loaded = true;
                }
		}
		catch (err) {
			if (Prototype.Browser.IE) {
				loaded = true;
			}
		}
		if (loaded && applet.isActive()){
			return true;
		}
		else
			return false;
	},

	/**
	 *
	 */
	repaint: function()
	{
        this.isEntitySelected();

        var applet = this.getTabContainer().down("applet");

        if (applet != null) {
            var coord0 = $("main-tabs").viewportOffset();
            var coord1 = document.viewport.getHeight();
            var _h = coord1 - (2 + coord0.top + $("main-tabs").getHeight());

            if (Prototype.Browser.IE) {
                _h = _h - 7;
            }

            applet.setStyle({
                height: _h + "px",
                width: document.viewport.getWidth()
            });
        }
	},

	/**
	 *
	 */
	hide: function()
	{
		var container = this.getTabContainer();

		if ($("scanLoading") != undefined) {
			$("scanLoading").hide();
		}

		if (!Prototype.Browser.IE) {
			var applet = this.getTabContainer().down("applet");
			if (applet != null) {
				container.down("applet").setStyle({height: "1px", width: "1px"});
				container.setStyle({margin: "-74px 0 0 -72px"});
			}			
		}
		else {
			container.hide();
		}
	},

	/**
	 *
	 */
	show: function()
	{
		var container = this.getTabContainer();

		if (this.isAppletLoaded()){
			if ($("scanLoading") != undefined){
				$("scanLoading").hide();
			}
			$("scanApplet").setStyle({visibility: "visible"});
		}
		else{
			if ($("scanLoading") != undefined) {
				$("scanLoading").show();
			}
		}

		if (!Prototype.Browser.IE) {
			this.repaint();
			var applet = this.getTabContainer().down("applet");
			if (applet != null) {
				container.down("applet").setStyle({width: "100%"});
				container.setStyle({margin: "0px"});
			}
		}
		else {
			container.show();
		}

	}
});


/**
 * Close invoices
 */
var ClosesTab = Class.create(BaseTab, {
	/**
	 * @contruct
	 */
	initialize: function($super)
	{
		this.setBaseUrl("/index.php/Closes");
		this.setTabName("closes");

		$super(); // BaseTab::initialize();
	},

	/**
	 *
	 */
	repaint: function()
	{
		var iframe = this.getTabContainer().down("iframe");
		if (iframe != null) {
			var coord0 = $("main-tabs").viewportOffset();
			var coord1 = document.viewport.getHeight();
			var _h = coord1 - (coord0.top + $("main-tabs").getHeight());

			if (Prototype.Browser.IE) {
				_h = _h - 7;
			}

			iframe.setStyle({height: _h + "px"});
		}

		this.isEntitySelected();
	}
});

/**
 * Mails
 */
var Mail = Class.create(BaseTab, {
	/**
	 * @contruct
	 */
	initialize: function($super)
	{
		this.setBaseUrl("/index.php/Mail");
		this.setTabName("mail");

		$super(); // BaseTab::initialize();
        
        this.repaint();
	},

	/**
	 *
	 */
	repaint: function()
	{
        //Hacer el wrappercontent que tenga la altura justa
        var mailviewer = this.getTabContainer().down('.wrappercontent');
        if ( mailviewer ) {
            var _h = document.viewport.getHeight() - mailviewer.viewportOffset().top - 50;
            //console.log("Altura: " + _h);
            mailviewer.setStyle({height: _h + "px"});
        }
        
        //this.attachListeners();
	},
    
    /**
     *
     */
    attachListeners: function()
    {
        //$("closesidebar").stopObserving('click');
        //$("closesidebar").observe('click',this.toggleSidebar.bindAsEventListener(this));
    }
});

/**
 * Modal popups base class
 */
var Modal = Class.create({
	/**
	 * @constructor
	 */
	initialize: function()
	{
	},

	/**
	 * Show the modal window.
	 *
	 * @param {Integer} width	Modal window width.
	 * @param {Integer} height	Modal window height.
	 * @return {Element} Pointer to popup window.
	 */
	open: function(width, height)
	{
            // given dimensions must fit on viewport
            if (width > document.viewport.getWidth()) {
                    width = document.viewport.getWidth() - 50;
            }

            if (height > document.viewport.getHeight()) {
                    height = document.viewport.getHeight() - 50;
            }

            this.container = null;
            var b = $(document.body);

			// hides document preview so the modal is shown properly
			hideDocumentPreview();
			
            var isScan = ($("scan-tab") != null && $("scan-tab").hasClassName("current"));

            $$("applet").each(function(elm) { // hide applets
                    if (isScan) {elm.setStyle({visibility: "hidden"});}
            }.bind(this));
            
            // background panel
            var background = new Element("div").addClassName("modal-background").update("&nbsp;");
            b.insert(background);

            // modal window
            var win = new Element("div").addClassName("modal");
            this.container = new Element("div", {className: "content"});
            
            var msgcontainer = new Element('div',{'id':'msgcontainer'});

            var close = new Element("div").addClassName("close")
                    .insert(new Element("a", {href: "#", title: "Cerrar"})
                            .observe("click", this.close.bind(this))
                            .insert(new Element("img", {src: "/img/close.png", alt: "close"})));

            var h = document.viewport.getHeight();
            var w = document.viewport.getWidth();

            win.setStyle({
                    top: (parseInt(h/2, 10) - parseInt(height/2)) + 'px',
                    left: (parseInt(w/2, 10) - parseInt(width/2)) + 'px',
                    width: width + "px",
                    height: height + "px"
            });

            win.insert(msgcontainer);
            win.insert(close);
            win.insert(this.container);

            b.insert(win);

            document.observe("keydown", function(ev) {
                    if (ev.keyCode == Event.KEY_ESC) {
                            this.close();
                    }
            }.bind(this));

            return this.container;
	},

	/**
	 * Shortcut to get the container div panel of modal window.
	 * @return {Element}
	 */
	getContainer: function()
	{
		return this.container;
	},

	/**
	 * Closes the modal window.
	 */
	close: function()
	{
		var elm = $$("div.modal-background");
        var background = null;
		if (elm.length == 1) {
            background = elm[0];
			//elm[0].remove();
		}

		elm = $$("div.modal");
		if (elm.length == 1) {
            $jQ(elm[0]).fadeOut("fast",function(){
                background.remove();
                elm[0].remove();
            });
		}

		showDocumentPreview();

		var isScan = ($("scan-tab") != null && $("scan-tab").hasClassName("current"));

		$$("applet").each(function(elm) { // show applets
			if (isScan) {elm.setStyle({visibility: "visible"});}
		}.bind(this));

		document.stopObserving("keydown");
	},

	/**
	 * Sets a pointer to main application class.
	 *
	 * @param {DigitalDocu} callback
	 */
	setApplicationCallback: function(callback)
	{
		this.application = callback;
	},

	/**
	 * Gets the pointer to main application class
	 *
	 * @return {DigitalDocu}
	 */
	getApplication: function()
	{
		return this.application;
	}
});


/**
 * Administration page menu
 *
 */
DigitalDocu.Admin = Class.create({
	/**
	 * @constructor
	 */
	initialize: function()
	{   
		var __onSuccess = function(req) {
			$('container').replace(req.responseText);
			this.attachEventListeners();
			this.factory("GeneralOptions");
		}.bind(this);

		var options = {
			onFailure: Ajax.showError,
			onexception: function(req, ex) {alert(_("Error al crear objeto AJAX: ") + ex.message);},
			onSuccess: __onSuccess,
			onTimeout: function(req) {alert("timeout DigitalDocu.Admin::initialize()");},
			wait: 5000,
			requestHeaders: {Accept: "application/json"}
		};

		new Ajax.Request("/index.php/admin/GeneralOptions", options);
	},

	/**
	 *
	 */
	attachEventListeners: function()
	{
		$("navbar").observe("click", function(ev) {
			var item = ev.element();

			if (item.tagName.toLowerCase() == "a" && !item.up("li").hasClassName("logout")) {
				ev.stop();
				this.updateContent(item);
			}
		}.bind(this));

        if ( $("clientsSelect") != null ) {
            $("clientsSelect").observe("change",this.loadClient.bindAsEventListener(this));
        }
	},

    /**
	 *
	 */
	loadClient: function(ev)
	{
        var cid = ev.element().value;
        var target = '/index.php/admin/Main/loadClient?cid=' + cid;

        var _onSuccess = function() {
            this.reloads();
        }.bind(this);

		var options = {
			onFailure: Ajax.showError,
			onexception: function(req, ex) {alert(_("Error al crear objeto AJAX: ") + ex.message);},
			onTimeout: function(req) {alert("timeout DigitalDocu.Admin::loadClient()");},
			wait: 5000,
            onSuccess: _onSuccess
		};

		new Ajax.Request(target, options);
    },

    /**
	 *
	 */
    reloads: function()
    {
        var target = $$('div.header ul li.selected a')[0].href;
        var mainsection = target.split("/")[5];
        if ( $$('#container .sidebar li.selected a')[0] != undefined )
            var subsection = $$('#container .sidebar li.selected a')[0].href.split("/")[6];
        var _onSuccess = function(req) {
            var c = $("container");
            if ( req.responseText != '' ) {
                c.replace(req.responseText);
                this.factory(mainsection,subsection);
            }
            else {
                c.update("");
            }
        }.bind(this);

		var options = {
			onFailure: Ajax.showError,
			onexception: function(req, ex) {alert(_("Error al crear objeto AJAX: ") + ex.message);},
			onTimeout: function(req) {alert("timeout DigitalDocu.Admin::loadClient()");},
			wait: 5000,
            onSuccess: _onSuccess
		};
        new Ajax.Request(target,options);
        
    },

	/**
	 *
	 */
	updateContent: function(tabItem)
	{
		var target = tabItem.getAttribute("href");
		var li = tabItem.up("li");

		li.up("ul").select("li").each(function(item) {
			if (item.hasClassName("selected")) {
				item.removeClassName("selected");
			}
		});
		li.addClassName("selected");

		var __onSuccess = function(req, json) {
			var c = $("container");
            if ( req.responseText != '' ) {
                c.replace(req.responseText);
                this.factory(target.split("/")[3]);
            }
            else {
                c.update("");
            }

		}.bind(this);

		var options = {
			onFailure: Ajax.showError,
			onexception: function(req, ex) {alert(_("Error al crear objeto AJAX: ") + ex.message);},
			onSuccess: __onSuccess,
			onTimeout: function(req) {alert("timeout DigitalDocu.Admin::updateContent()");},
			requestHeaders: {Accept: "application/html"}
		};

		new Ajax.Request(target, options);
	},

	/**
	 * Links the Prototype JS Clases with their Tabs to handle
	 */
	factory: function(target,section)
	{
        var _target = $$("#container .sidebar li.selected a")[0].getAttribute("href");
        if ( section == undefined || _target.split("/")[4] != section ) {
            var section = _target.split("/")[4];
        }
		switch (target) {
			case 'GeneralOptions':
				var ge = new GeneralOptions();
				ge.factory(section);
				break;

			case 'Customization':
				new Customization();
				break;

			case 'AccountManager':
				var am = new AccountManager();
				am.factory(section);
				break;

			case 'Taxonomy':
				var t = new Taxonomy();
				t.factory(section);
				break;

			case 'Modules':
				new Modules().factory(section);
				break;

            case 'ClientManager':
				var c = new ClientManager();
				c.factory(section);
				break;
		}
	}
});

/**
 *  Object to create a Editble HTML CELL
 */
var EditableTD = Class.create({
    
    /**
     * Constructor.
     * @param {td} HTMLCell Dom object
     * @param {options} Object with options
     * options = {
     *      tab: Tab object (Archivetab, Viewtab,...)
     *      checkName: function(newName,SelectFile) that checks the name, it must have two input
     *          parameters. 
     *              - newName. String with newName
     *              - SelectFiel. SelectFile object.
     *      parameters: Custom parameters send to Controller
     *      target: Controller to be called
     * }
     */
    initialize: function(td,options)
    {
        this.td = td;
        this.options = options;
        
        this._insertHtmlInput();
        
        this.inputname = this.td.down('input.changename');

        this.td.descendants().invoke('hide');
        
        this._showEditFields();

        this.inputname.focus();
        
        this.attachListeners();
    },
    
    /**
     * Attachlisteners to Input Field
     */
    attachListeners: function()
    {
        this.inputname.observe("blur",function(){
            this._resetCellContent();
        }.bind(this));
        this.inputname.observe("keydown",function(e){
            if( e.keyCode == Event.KEY_RETURN ){
                if ( this._renameFile() ) {
                    this.td.addClassName("loading");
                }
                this._resetCellContent();
            }
            else if( e.keyCode == Event.KEY_ESC ){
                this._resetCellContent();
            }
        }.bind(this));
    },
    
    /**
     * Restore the Cell to its original value.
     */
    _resetCellContent: function()
    {
        this.td.descendants().invoke('show');
        this.inputname.hide();
    },
    
    /**
     * Show up the fields related to name edition
     */
    _showEditFields: function()
    {
        this.inputname.show();
    },
    
    /**
     * Insert the input element to current Cell
     */
    _insertHtmlInput: function()
    {
        var name = this._getCurrentName();
        //Make the HTML to insert into the cell
        var inputTemplate = new Template('<input size="#{tam}" type="text" class="changename" '
        + 'value="#{valor}">');
        this.td.insert({top: inputTemplate.evaluate({
            valor: name,
            tam: name.length + 5
        })});
    },
    
    _getCurrentFile: function()
    {
        var sf = new SelectedFile(this.td.up("tr"));
        return sf;
    },
    
    _renameFile: function()
    {
        var newName = this._getNewName();
        var valName = this.options.checkName(newName,this._getCurrentFile());
        if ( !valName ) {
            return;
        }
        this._setCurrentName(valName);
        var __onSuccess = function(req) {
            if (req.responseText != "") {
                var msg = req.responseText.evalJSON();
                if (msg._message_type == "error") {
                    this.td.removeClassName("loading");
                    var errorMsg = msg._message;
                    if ( msg.errors ) {
                        msg.errors.each(function(err){
                            errorMsg += err.error;
                        });
                    }
					msg._message = errorMsg;
                }
                else {
                    this.td.removeClassName("loading");
                    this.td.down("a.filename").update(valName);
                }
				new MessageDD().show(msg);
            }
		}.bind(this);
        
        var options = {
			onFailure: Ajax.showError,
			onException: function(req, ex) {alert(_("Error al crear objeto AJAX: ") + ex.message);},
			onSuccess: __onSuccess,
            wait: 10000,
            parameters: Object.merge(this._getParameters(), this.options.parameters)
		};
        
        new Ajax.Request(this.options.target, options);
        return true;
    },
    
    /**
     * Establish the input value to new name
     * @param {name}
     */
    _setCurrentName: function( name )
    {
        this.td.down('input.changename').setValue(name);
    },
    
    /**
     * Obtain the origin name of current edited file
     */
    _getCurrentName: function()
    {
        var sf = new SelectedFile(this.td.up("tr"));
        var name = unescape(sf.FileName);
        return name;
    },
    
    /**
     * Fill parameters to be sent in change name request.
     */
    _getParameters: function()
    {
        var opt = {
            ssid: $F("__sessionId")
        };
        var tabname = this.options.tab.getTabName().valueOf();
        switch( tabname ) {
            // Rename from archive. Set correct parameters
            case "archive":
                opt.data= Object.toJSON({
                    scanid: this.options.tab.getScanPath(),
                    files: [{
                        src: escape(Base64.encode(this._getCurrentName())),
                        dst: escape(Base64.encode(this._getNewName()))
                    }]
                });
                break;
            // Rename from view. Set correct parameters
            case "view":
                opt.name = escape(Base64.encode(this._getNewName()));
                break;
        }
        return opt;
    },
    
    _getNewName: function()
    {
        return this.td.down('input.changename').getValue().strip();
    }
    
});

var DDXml = Class.create({
    serialize: function(doc){
        if ( Prototype.Browser.IE || typeof XMLSerializer == "undefined" ) {
            return doc.xml;// IE way
		}
		else if ( typeof XMLSerializer != "undefined" ) {
            return (new XMLSerializer()).serializeToString(doc); // Mozilla way
        }
		else {
            throw {element: null,
                message: "serialize() is not supported or can't serialize " + doc};
        }
    }
});
var GlobalDDXml = new DDXml();
