/**
 * 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;
}();

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

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


/**
 * 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);
	});
};


/**
 * 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;
		var c = c1 = c2 = 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.\n"
				+ "No se pudo acceder a la url \"" + target + "\".";
			break;
		case 404:
			msg = "La url \"" + target + "\" no existe.\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);
};

/**
 * Shows a file preview in given container
 *
 * @param {Object}	params
 *
 */
var show_document = function(params)
{
	var mime = "application/octet-stream"; // default mime
	var no_plugin_msg = "No se ha encontrado ningún plugin para mostrar este documento.";
	var use_iframe = false;
	var target = '';

	if (params["localUrl"]) {
		target = params.localUrl;
	} else {
		target = __localUrl;
	}

	if (params.container.id == 'viewPreview'){
		target += "&a=fa&id=" + params.fileId + "&n=" + params.fileName
		+ ((params.page > 0) ? "#page=" + parseInt(params.page,10) : "")
		+ ((params["ds"] && params.ds != "") ? "&ds=" + escape(params.ds) : "")
		+ ((params["cversion"] && params.cversion > 0) ? "&cversion=" + params.cversion : "");
	}
	else {
		target += "&a=fs&rs=" + parseInt(params.scan_path,10) + "&f=" + escape(params.fileName);
	}

	params.container.update(""); // clean container

	// discover the file mime type
	var m = /\.(pdf|tif|gif|jpg|jpeg|png|odt|doc|docx|rtf|xls|txt|htm|html|mht)$/i.exec(params.fileName.toLowerCase());
	if (m != null && m.length > 1) {
		switch (m[1]) {
			case "pdf":
				mime = "application/pdf";
				no_plugin_msg = "No se ha encontrado ningún plugin para mostrar documentos PDF.";
				use_iframe = true;
				break;
			case "gif":
				mime = "image/gif";
				use_iframe = true;
				break;
			case "jpg":
			case "jpeg":
				mime = "image/jpeg";
				use_iframe = true;
				break;
			case "tif":
				mime = "image/tiff";
				break;
			case "png":
				mime = "image/png";
				use_iframe = true;
				break;
			case "odt":
					mime = "application/vnd.oasis.opendocument.text";
					no_plugin_msg = "No se ha encontrado ningún plugin para mostrar documentos OpenOffice.org.";
				break;
			case "doc":
			case "docx":
				mime = "application/msword";
				no_plugin_msg = "No se ha encontrado ningún plugin para mostrar documentos Microsoft Office.";
				use_iframe = Prototype.Browser.IE;
				break;
			case "rtf":mime = "application/rtf";
				break;
			case "xls":
				mime = "application/vnd.ms-excel";
				no_plugin_msg = "No se ha encontrado ningún plugin para mostrar documentos Microsoft Office.";
				use_iframe = Prototype.Browser.IE;
				break;
			case "txt":mime = "text/plain";
				break;
			case "htm":
			case "html":
				mime = "text/html";
				use_iframe = true;
				break;
			case "mht":mime = "message/rfc822";
				break;
		}
	}

	var obj;

	if (Prototype.Browser.IE && !use_iframe) {
		// IE doesn't support object tag with fallback content
		obj = new Element("object", {data: target, type: mime, width: "100%"})
			.insert(new Element("param", {name: "src", value: target}));
	}
	else {
		if (use_iframe) {
			// some mime types need an iframe to render properly
			obj = new Element("iframe", {src: target, width: "100%", frameborder: 0, type: mime});
		}
		else {
			obj = new Element("object", {data: target, type: mime, width: "100%"})
				.insert(new Element("param", {name: "src", value: target}))
				.insert(new Element("p").update(no_plugin_msg))
				.insert(new Element("br"))
				.insert(new Element("a", {href: target}).update("Descargar documento"));
		}
	}

	params.container.update(obj);
};


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

		// add listeners on menu items
		if ($("nav-menu") != null) {
			$("nav-menu").select("a.modal").each(function(item) {
				var target = item.href;
				item.observe("click", this.showMenu.bindAsEventListener(this, target));
			}.bind(this));
		}

		// add listeners on tabs
		$("main-tabs").select("li 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;
	},

	/**
	 * 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);
				break;

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

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

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

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

	/**
	 * 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.target.id);
			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("li a.current");
		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();
		}
	},

	/**
	 * 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();
				break;
			case "view":
				this.tabs.view = new View();
				this.tabs.view.setApplicationCallback(this);
				this.tabs.view.update();
				break;
			case "closes":
				this.tabs.closes = new ClosesTab();
				this.tabs.closes.setApplicationCallback(this);
                this.tabs.closes.repaint();
				break;
			case "help":
				this.tabs.help = new Help();
                this.tabs.help.setApplicationCallback(this);
				this.tabs.help.repaint();
				break;
		}
	}
};

/**
 * Abstract class with common method for tab objects.
 */
var BaseTab = Class.create();
BaseTab.prototype = {
	/**
	 * @construct
	 */
	initialize: function()
	{
		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: "loading"}).update("Cargando ...");
					cont.update(l);
				},
				onSuccess: function(req, json) {
					cont.replace(req.responseText);
				},
				asynchronous: false,
				requestHeader: {Accept: "text/html"}
			};

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

	/**
	 * 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;
		}
	},

	/**
	 * Checks if tab's content is loaded
	 *
	 * @return {Boolean}
	 */
	isLoaded: function()
	{
		var cont = this.getTabContainer();
		if (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 = $("header").down(".title h2.entityName").innerHTML.stripTags().strip();

        if (entityName == "") { // entity not selected, popup entity selector
			var app = this.getApplication();
			app.showMenu(Prototype.emptyFunction(), "/index.php/Entity");
            return false;
		}
        else{
            return true;
        }
    }
};

/**
 *
 */
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"}).update("<br/>Por favor, espere mientras se carga la página ...");
					cont.update(l);
				},
				onSuccess: function(req, json) {
					cont.replace(req.responseText);
				},
				asynchronous: true,
				requestHeader: {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), 5);
		}
	},

	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);
		}
		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();
		}

	}
});


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

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

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


/**
 * 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 - (2 + coord0.top + $("main-tabs").getHeight()) + 72;

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

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

		this.isEntitySelected();
	}
});