var HappingUserApi = Class
		.create({
			options : null,
			userCache : null,
			constants : {
				apiUserEndpointUrl : "/services/user",
				editUserAccountUrl : "/api/usuarios/edicion/editarMisDatos.action",
				editUserDataUrl : "/api/usuarios/edicion/misDatos.action",
				editUserContactUrl : "/api/usuarios/edicion/miContacto.action",
				editUserMailUrl : "/api/usuarios/edicion/miCorreo.action",
				editUserPwdUrl : "/api/usuarios/edicion/miContrasenia.action",
				editUserPermissionsUrl : "/api/usuarios/edicion/privacidad.action",

				deleteUserAccountUrl : "/api/usuarios/edicion/baja.action",
				loginUrl : "/contentLogin.action",
				logoutUrl : "/ckactions/logout",
				signupUrl : "/api/usuarios/registro/dispatchRegistro.action",
				resetPasswordUrl : "/usuarios/solicitarRecordarPassword.action",
				editUserPhoneUrl : "/api/usuarios/edicion/confirmarTelefono.action",

				secMyData : "mis-datos",
				secMyContact : "mi-contacto",
				secMyMail : "mi-correo",
				secMyPwd : "mi-password",
				secPermission : "mis-permisos"
			},
			initialize : function(options) {
				this.options = Object.extend({
					site : null,
					acegiHash : null,
					tipoRegistro : "P",
					xssProxyHostAndScript : securedHostHapping
							+ "/perl/js/json/uri="
				}, options || {});
				if (!this.userCache) {
					this.userCache = new Cache();
				}
			},
			signup : function(options) {
				if (this.options.site == null) {
					throw ("Parameter not defined: site");
				}
				window.location.href = "/ckactions/register";
				/*
				options = (options || {});
				options.tipoRegistro = (options && options.tipoRegistro) ? options.tipoRegistro
						: this.options.tipoRegistro;
				var signupType = options.tipoRegistro;
				if ([ "B", "P", "C" ].indexOf(signupType) == -1) {
					throw ("Bad parameter: signupType");
				}
				var signupTypeText = (signupType == "B") ? "b&aacute;sico"
						: (signupType == "P") ? "principal"
								: (signupType == "C") ? "completo" : "invalid";
				return LightHelper.abrirRedLightwindow("L",
						securedHostHapping + this.constants.signupUrl
								+ "?site=" + this.options.site + "&"
								+ $H(options).toQueryString(),
						"Registro en cocacola.es ", 836, 494);
				*/
			},
			editPermissions : function() {
				if (this.options.site == null) {
					throw ("Parameter not defined: site");
				}
				hideMiCuenta();

				var whereToGo = this.constants.editUserPermissionsUrl;
				return Logged.checkNavigation("P", false, "L",
						securedHostHapping + whereToGo + "?site="
								+ this.options.site, "Editar mis permisos", 836,
						484);

			},
			deleteAccount : function() {
				if (this.options.site == null) {
					throw ("Parameter not defined: site");
				}
				return Logged.checkNavigation("P", false, "L",
						securedHostHapping
								+ this.constants.deleteUserAccountUrl
								+ "?site=" + this.options.site,
						"Editar mis datos", 836, 494);
			},
			modifyAndActivateMobile : function(activate) {
				if (this.options.site == null) {
					throw ("Parameter not defined: site");
				}
				var activateStr = '', lwName = 'Modifica';
				if (activate) {
					activateStr = '&activar=1';
					lwName = 'Activa';
				}
				return Logged.checkNavigation("P", false, "L",
						securedHostHapping + this.constants.editUserPhoneUrl
								+ "?site=" + this.options.site + activateStr,
						lwName + " tu móvil", 836, 494);
			},
			resetPassword : function() {
				if (this.options.site == null) {
					throw ("Parameter not defined: site");
				}
				LightHelper.abrirRedLightwindow("L", securedHostHapping
						+ this.constants.resetPasswordUrl + "?site="
						+ this.options.site, "Restablecer contrase&ntilde;a",
						836, 494);
				return false;
			},
			openLogin : function(signupType) {
				if (this.options.site == null) {
					throw ("Parameter not defined: site");
				}
				window.location.href = "/ckactions/login";

				/*
				return LightHelper
						.abrirRedLightwindow(
								"L",
								securedHostHapping
										+ this.constants.loginUrl
										+ "?site="
										+ this.options.site
										+ "&registro="
										+ ((typeof (signupType) == "undefined") ? this.options.tipoRegistro
												: signupType.tipoRegistro),
								"Identif&iacute;cate", 676, 480);
				*/
			},
			logout : function() {
				this.userCache.clear();
				if (this.isLogged()) {
					if ($('mini_ajax_waiting_logout')) {
						$$('#mini_ajax_waiting_logout').each(Element.show);
					}
					/*
					 * if (this.hasDivHeader()) { parent.Logged.fromNav=false;
					 * servicioSeguridad.logout({callback: function(){try
					 * {postLogout();} catch(e) { alert(e); } } } ); } else {
					 */
					var opt = {
						method : "post",
						asynchronous : false,
						requestHeaders : this.options.headers,
						parameters : {},
						onFailure : function() {
							throw ("!Oops something wierd happened when logout. Try again later!");
						},
						onException : function(req, exception) {
							alert("The request had a fatal exception thrown.\n\n"
									+ Object.values(exception));
						},
						onSuccess : function(transport) {
							// var response = transport.responseText;
							// if (response!=null && response=='1') {
							parent.Logged.fromNav = false;
							myCookies.clear("__sscc");
							postLogout(); // callback, should be
							// overwrited on parent pageh
						}
					};

					if (typeof (this.options.xssProxyHostAndScript) != "undefined"
							|| this.options.xssProxyHostAndScript != "") {
						var url = securedHostHapping + this.constants.logoutUrl;
						new Ajax.Request(url, opt);
					} else {
						alert("proxy is undefined or blank!!");
					}
					/* } */
				} else {
					alert("user is not logged!");
					return false;
				}
			},
			hasDivHeader : function() {
				return ($("hd") != null);
			},
			isLogged : function(doCookieCheck) {
				var isReallyLogged = false;
				if (this.hasDivHeader()) {
					isReallyLogged = $('user') != undefined;
					if (typeof (doCookieCheck) != "undefined"
							&& (isReallyLogged && !this.getAcegiHash())) { // verify
						// if
						// has
						// security
						// cookie
						alert("Se produjo un error al realizar la consulta. \n"
								+ "Por favor, verifique que su navegador tiene habilitadas \n"
								+ "las cookies y reintente la operación.");
						this.logout(); // force logout
						isReallyLogged = false;
					}
				} else {
					isReallyLogged = (this.getUserByAcegiHash() != null);
				}
				return isReallyLogged;
			},
			getAcegiHash : function() {
				acegiCookie = myCookies.get("datr");
				/**
				 * From Tomcat 6.0.16 (remm): Cookie handling/parsing changes!
				 * The following behavior has been changed with regards to
				 * Tomcat's cookie handling a) Cookies containing control
				 * characters, except 0x09(HT), are rejected using an
				 * InvalidArgumentException b) If cookies are not quoted, they
				 * will be quoted if they contain tspecials(ver0),
				 * tspecials2(ver1) characters c) Escape character '\\' is
				 * allowed and respected as a escape character, will be
				 * unescaped during parsing
				 * 
				 * Remove extra double quotes if exists.
				 */
				if (acegiCookie) {
					acegiCookie = acegiCookie.escapeHTML().gsub(/"/, '');
				}
				return acegiCookie;
			},
			getUserByAcegiHash : function(options) {
				var user = null;
				var acegiCookie = this.getAcegiHash();
				return (acegiCookie!=null);
/*
 				// This is a workaround while we wait the cokeid js client 
  
 				if (acegiCookie
						&& myHappingUserApi.userCache.getItem(acegiCookie) != null) {
					return myHappingUserApi.userCache.getItem(acegiCookie);
				}
				if (acegiCookie) {
					this.options = Object.extend(this.options, options);
					this.options.acegiHash = acegiCookie;
					this.options.headers = new Hash({
						"X-Requested-With" : null,
						"X-Prototype-Version" : null,
						"Cache-Control" : "max-age=0"
					});
					if (this.options.requiredAuth) {
						var authPre = this.make_basic_auth('happingtest',
								'Z2VuY29jaGFw');
						this.options.headers.update({
							"Authorization" : authPre
						});
					}
					var opt = {
						method : "get",
						asynchronous : false,
						requestHeaders : this.options.headers,
						parameters : {
							"acegiHash" : this.options.acegiHash,
							"site" : this.options.site,
							"response" : "application/json"
						},
						onLoading : function(transport) {
							// cancelar otras peticiones ajax
							if (Ajax.activeRequestCount > 1) {
								transport.abort();
							}
						},
						onFailure : function() {
							throw ("!Oops something wierd happened in hash. Try again later!");
						},
						onException : function(req, exception) {
							alert("The request had a fatal exception thrown.\n\n"
									+ exception);
						},
						onSuccess : function(transport) {
							var json = null;
							try {
								json = transport.responseText.evalJSON();
								if (json != null
										&& json.queryResultType != null
										&& json.queryResultType.usuario
										&& json.queryResultType.usuario.nick != null) {
									user = json.queryResultType.usuario;
									myHappingUserApi.userCache.setItem(
											acegiCookie, user, {
												expirationSliding : 10
											});
									Logged.tipoRegistro = user.tipoRegistro;
								} else {
									var error = json.queryResultType.ERROR;
									alert("The request had an error:\n\n"
											+ Object.values(error));
								}
							} catch (e) {
								alert("Oops something wierd happened with the request.\n\n"
										+ e);
							}
						}
					};

					if (typeof (this.options.apiUserEndpointUrl) != "undefined"
							|| this.options.apiUserEndpointUrl != "") {
						var url = this.options.xssProxyHostAndScript
								+ apiHostAndContextRoot
								+ this.constants.apiUserEndpointUrl
								+ "/getUserByAcegiHash";
						new Ajax.Request(url, opt);
					} else {
						alert("url is undefined or blank!!");
					}
				}
				return user; */
			},
			make_basic_auth : function(user, pass) {
				var tok = user + ':' + Base64.decode(pass);
				var hash = Base64.encode(tok);
				return "Basic " + hash;
			},
			urlEncodeIfNecessary : function(s) { // Filter to avoid XSS
													// attacks
				var regex = /[\\\"<>\.;]/;
				var hasBadChars = regex.exec(s) != null;
				return hasBadChars ? encodeURIComponent(s) : s;
			}
		});
var myHappingUserApi = (myHappingUserApi || new HappingUserApi());

var happing = (happing || RUZEE.ShadedBorder.create({
	corner : 10,
	border : 0,
	shadow : 28
}));
var lwContainer = (lwContainer || RUZEE.ShadedBorder.create({
	corner : 8,
	border : 1,
	shadow : 16
}));

/**
 * 
 * Base64 encode / decode http://www.webtoolkit.info/
 * 
 */

var Base64 = {

	// private property
	_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

	// public method for encoding
	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;
	},

	// public method for decoding
	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;

	},

	// private method for UTF-8 encoding
	_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;
	},

	// private method for UTF-8 decoding
	_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;
	}

}

/*
 * MIT LICENSE Copyright (c) 2007 Monsur Hossain (http://www.monsur.com)
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

// ****************************************************************************
// CachePriority ENUM
// An easier way to refer to the priority of a cache item
var CachePriority = {
	Low : 1,
	Normal : 2,
	High : 4
}

// ****************************************************************************
// Cache constructor
// Creates a new cache object
// INPUT: maxSize (optional) - indicates how many items the cache can hold.
// default is -1, which means no limit on the
// number of items.
function Cache(maxSize) {
	this.items = {};
	this.count = 0;
	if (maxSize == null)
		maxSize = -1;
	this.maxSize = maxSize;
	this.fillFactor = .75;
	this.purgeSize = Math.round(this.maxSize * this.fillFactor);

	this.stats = {}
	this.stats.hits = 0;
	this.stats.misses = 0;
}

// ****************************************************************************
// Cache.getItem
// retrieves an item from the cache, returns null if the item doesn't exist
// or it is expired.
// INPUT: key - the key to load from the cache
Cache.prototype.getItem = function(key) {

	// retrieve the item from the cache
	var item = this.items[key];

	if (item != null) {
		if (!this._isExpired(item)) {
			// if the item is not expired
			// update its last accessed date
			item.lastAccessed = new Date().getTime();
		} else {
			// if the item is expired, remove it from the cache
			this._removeItem(key);
			item = null;
		}
	}

	// return the item value (if it exists), or null
	var returnVal = null;
	if (item != null) {
		returnVal = item.value;
		this.stats.hits++;
	} else {
		this.stats.misses++;
	}
	return returnVal;
}

// ****************************************************************************
// Cache.setItem
// sets an item in the cache
// parameters: key - the key to refer to the object
// value - the object to cache
// options - an optional parameter described below
// the last parameter accepts an object which controls various caching options:
// expirationAbsolute: the datetime when the item should expire
// expirationSliding: an integer representing the seconds since
// the last cache access after which the item
// should expire
// priority: How important it is to leave this item in the cache.
// You can use the values CachePriority.Low, .Normal, or
// .High, or you can just use an integer. Note that
// placing a priority on an item does not guarantee
// it will remain in cache. It can still be purged if
// an expiration is hit, or if the cache is full.
// callback: A function that gets called when the item is purged
// from cache. The key and value of the removed item
// are passed as parameters to the callback function.
Cache.prototype.setItem = function(key, value, options) {

	function CacheItem(k, v, o) {
		if ((k == null) || (k == ''))
			throw new Error("key cannot be null or empty");
		this.key = k;
		this.value = v;
		if (o == null)
			o = {};
		if (o.expirationAbsolute != null)
			o.expirationAbsolute = o.expirationAbsolute.getTime();
		if (o.priority == null)
			o.priority = CachePriority.Normal;
		this.options = o;
		this.lastAccessed = new Date().getTime();
	}

	// add a new cache item to the cache
	if (this.items[key] != null)
		this._removeItem(key);
	this._addItem(new CacheItem(key, value, options));

	// if the cache is full, purge it
	if ((this.maxSize > 0) && (this.count > this.maxSize)) {
		this._purge();
	}
}

// ****************************************************************************
// Cache.clear
// Remove all items from the cache
Cache.prototype.clear = function() {

	// loop through each item in the cache and remove it
	for ( var key in this.items) {
		this._removeItem(key);
	}
}

// ****************************************************************************
// Cache._purge (PRIVATE FUNCTION)
// remove old elements from the cache
Cache.prototype._purge = function() {

	var tmparray = new Array();

	// loop through the cache, expire items that should be expired
	// otherwise, add the item to an array
	for ( var key in this.items) {
		var item = this.items[key];
		if (this._isExpired(item)) {
			this._removeItem(key);
		} else {
			tmparray.push(item);
		}
	}

	if (tmparray.length > this.purgeSize) {

		// sort this array based on cache priority and the last accessed date
		tmparray = tmparray.sort(function(a, b) {
			if (a.options.priority != b.options.priority) {
				return b.options.priority - a.options.priority;
			} else {
				return b.lastAccessed - a.lastAccessed;
			}
		});

		// remove items from the end of the array
		while (tmparray.length > this.purgeSize) {
			var ritem = tmparray.pop();
			this._removeItem(ritem.key);
		}
	}
}

// ****************************************************************************
// Cache._addItem (PRIVATE FUNCTION)
// add an item to the cache
Cache.prototype._addItem = function(item) {
	this.items[item.key] = item;
	this.count++;
}

// ****************************************************************************
// Cache._removeItem (PRIVATE FUNCTION)
// Remove an item from the cache, call the callback function (if necessary)
Cache.prototype._removeItem = function(key) {
	var item = this.items[key];
	delete this.items[key];
	this.count--;

	// if there is a callback function, call it at the end of execution
	if (item.options.callback != null) {
		var callback = function() {
			item.options.callback(item.key, item.value);
		}
		setTimeout(callback, 0);
	}
}

// ****************************************************************************
// Cache._isExpired (PRIVATE FUNCTION)
// Returns true if the item should be expired based on its expiration options
Cache.prototype._isExpired = function(item) {
	var now = new Date().getTime();
	var expired = false;
	if ((item.options.expirationAbsolute)
			&& (item.options.expirationAbsolute < now)) {
		// if the absolute expiration has passed, expire the item
		expired = true;
	}
	if ((expired == false) && (item.options.expirationSliding)) {
		// if the sliding expiration has passed, expire the item
		var lastAccess = item.lastAccessed
				+ (item.options.expirationSliding * 1000);
		if (lastAccess < now) {
			expired = true;
		}
	}
	return expired;
}

Cache.prototype.toHtmlString = function() {
	var returnStr = this.count + " item(s) in cache<br /><ul>";
	for ( var key in this.items) {
		var item = this.items[key];
		returnStr = returnStr + "<li>" + item.key.toString() + " = "
				+ item.value.toString() + "</li>";
	}
	returnStr = returnStr + "</ul>";
	return returnStr;
}

