/**
 * Determina si un objeto es de tipo array
 */
function isArray(object)
{
    return object.constructor == Array;
}

/**
 * Crea el objeto xmlhttp
 */
function ajaxCreateObject()
{
    var xmlhttp;

    try {
        xmlhttp = new ActiveXObject('Msxml2.XMLHTTP');
    } catch(e) {
        try {
            xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
        } catch(f) {
            xmlhttp = null;
        }
    }

    if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
        xmlhttp = new XMLHttpRequest();
    }

    return xmlhttp;
}

/**
 * Chequea las opciones
 */
function ajaxCheckParams(opts)
{
	var errorMsg = '';

	if (typeof opts.method == 'undefined') {
		opts.method = 'GET'; // default value
	} else {
		opts.method = opts.method.toUpperCase();

		if (opts.method != 'GET' && opts.method != 'POST') {
			errorMsg = '* method must be GET or POST\n';
		}
	}

	if (typeof opts.url == 'undefined') {
		errorMsg += '* url cannot be empty\n';
	}

	if (typeof opts.responseType == 'undefined') {
		opts.responseType = 'XML'; // default value
	} else {
		opts.responseType = opts.responseType.toUpperCase();

		if (opts.responseType != 'TEXT' && opts.responseType != 'XML' && opts.responseType != 'JSON') {
			errorMsg = '* responseType must be TEXT, XML or JSON\n';
		}
	}

	if (typeof opts.async == 'undefined') {
		opts.async = true; // default value
	} else if (typeof opts.async != 'boolean') {
		errorMsg += '* async must be boolean\n';
	}

	if (typeof opts.handler != 'undefined' && typeof opts.handler != 'function') {
		errorMsg += '* handler must be a function\n';
	} else if (typeof opts.handler == 'undefined' && opts.async) {
	    opts.responseType = 'TEXT';
	}

	if (typeof opts.handlerVars != 'undefined' && !isArray(opts.handlerVars)) {
		errorMsg += '* handlerVars must be an array\n';
	}

	if (typeof opts.debug == 'undefined') {
		opts.debug = false; // default value
	} else if (typeof opts.debug != 'boolean') {
		opts.debug = true;
		errorMsg += '* debug must be boolean\n';
	}

	if (typeof opts.showLoading == 'undefined') {
		opts.showLoading = false; // default value
	} else if (typeof opts.showLoading != 'boolean') {
		errorMsg += '* showLoading must be boolean\n';
	}

	if (typeof opts.loadingBg == 'undefined') {
		opts.loadingBg = '#ffffff'; // default value
	} else {
	    var re_hexcolor = /^#[0-9a-fA-F]{6}$/;

	    if (!re_hexcolor.test(opts.loadingBg)) {
	        errorMsg += '* loadingBg must be the form #RRGGBB\n';
	    }
	}

	if (typeof opts.loadingOp == 'undefined') {
		opts.loadingOp = 0.4; // default value
	} else if (typeof opts.loadingOp != 'number' || opts.loadingOp < 0 || opts.loadingOp > 1) {
	    errorMsg += '* loadingOp must be a number between 0 and 1\n';
	}

	if (typeof opts.loadingImgW == 'undefined') {
		opts.loadingImgW = 100; // default value
	} else if (typeof opts.loadingImgW != 'number') {
	    errorMsg += '* loadingImgW must be a number\n';
	}

	if (typeof opts.loadingImgH == 'undefined') {
		opts.loadingImgH = 100; // default value
	} else if (typeof opts.loadingImgH != 'number') {
	    errorMsg += '* loadingImgH must be a number\n';
	}

	if (errorMsg && opts.debug) {
		alert('ERROR:\n\n' + errorMsg);
		return false;
	}

	return true;
}

/**
 * Obtiene la respuesta del objeto xmlhttp
 */
function ajaxGetResponse(opts, xmlhttp)
{
	if (opts.responseType == 'XML') {
		response = xmlhttp.responseXML;
	} else {
		response = xmlhttp.responseText;
	}

	if (opts.responseType == 'JSON') {
		response = eval(response);
	}

	return response;
}

/**
 * Pasa la respuesta al manejador
 */
function ajaxCallHandler(opts, response)
{
	if (typeof opts.handlerVars == 'object') { // manejador con argumentos adicionales
		handlerArgs = '';
		for (var i = 0; i < opts.handlerVars.length; i++) {
			handlerArgs += 'opts.handlerVars[' + i + '], ';
		}
		handlerArgs = handlerArgs.replace(/, $/, '');

		eval("opts.handler(response, " + handlerArgs + ")");
	} else {
		opts.handler(response);
	}
}

/**
 * Muestra imagen de loading
 */
function ajaxCreateLoading(opts)
{
 	if (opts.showLoading) {
 		var blockerDiv = document.createElement('div');

 		blockerDiv.id               = 'ajaxBlockerDiv';
 		blockerDiv.style.position   = 'fixed';
 		blockerDiv.style.zIndex     = '3000';
 		blockerDiv.style.width      = '100%';
 		blockerDiv.style.height     = '100%';
 		blockerDiv.style.top        = '0px';
 		blockerDiv.style.left       = '0px';
 		blockerDiv.style.background = opts.loadingBg;
 		blockerDiv.style.opacity    = opts.loadingOp;
 		blockerDiv.style.filter     = 'alpha(opacity=' + opts.loadingOp * 100 + ')';

 		document.body.appendChild(blockerDiv);

 		var loadingImg = document.createElement('img');

 		if (typeof opts.loadingImg == 'undefined') {
 			// Obtenemos la URL del script ajax.js
 			var scripts = document.getElementsByTagName('script');

 			for (var i = 0; i < scripts.length; i++) {
 				if (scripts[i].src.search(/\/ajax.js$/) != -1) {
 					baseURL = scripts[i].src.replace('ajax.js', '');
 				}
 			}

 			loadingImg.src = baseURL + 'img/ajax-loader.gif';
 		} else {
 			loadingImg.src = opts.loadingImg;
 		}

 		loadingImg.border           = '0';
 		loadingImg.style.position   = 'absolute';
 		loadingImg.style.top        = '50%';
 		loadingImg.style.left       = '50%';
 		loadingImg.style.marginTop  = '-' + opts.loadingImgH / 2 + 'px';
 		loadingImg.style.marginLeft = '-' + opts.loadingImgW / 2 + 'px';

 		blockerDiv.appendChild(loadingImg)

 		document.body.appendChild(blockerDiv);
 	}
}

/**
 * Elimina la imagen de loading
 */
function ajaxDestroyLoading(opts)
{
	if (opts.showLoading) {
		document.body.removeChild(document.getElementById('ajaxBlockerDiv'));
	}
}

/**
 * Muestra la excepcion si está activado el debug
 */
function ajaxShowException(opts, e)
{
	if (opts.debug) {
		alert(e);
	}
}

/**
 * Función pricipal
 */
function ajaxSendRequest(opts)
{
	if (!ajaxCheckParams(opts)) {
		return false;
	}

    var xmlhttp, uri, vars, data, response, requestArgs, handlerArgs;

    xmlhttp = ajaxCreateObject();

    if (typeof opts.queryVars == 'object') {
        vars = '?';
        for (var varName in opts.queryVars) {
            vars += varName + '=' + opts.queryVars[varName] + '&';
        }
        vars = vars.replace(/&$/, '');
    } else {
        vars = '';
    }

    if (opts.method == 'GET') {
        uri  = opts.url + vars;
        data = null;
    } else {
        uri  = opts.url;
        data = vars.replace(/^\?/, '');
    }

    try {
        xmlhttp.open(opts.method, uri, opts.async);

        if (opts.responseType == 'XML') {
            xmlhttp.overrideMimeType('text/xml');
        }

        if (opts.method == 'POST') {
            xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        }

        if (opts.async == false) {  // Síncrono
       		ajaxCreateLoading(opts);
        	xmlhttp.send(data);

			response = ajaxGetResponse(opts, xmlhttp);

        	if (typeof opts.handler == 'function') {
				ajaxCallHandler(opts, response);
				ajaxDestroyLoading(opts);
        	} else {
        		ajaxDestroyLoading(opts);

        		return response;
        	}
        } else { // Asíncrono
            xmlhttp.onreadystatechange = function() {
            	try {
            		if (xmlhttp.readyState == 4) {
            			try {
            				if (xmlhttp.status == 200) {
            					if (typeof opts.handler == 'function') {
            						ajaxCallHandler(opts, ajaxGetResponse(opts, xmlhttp));
            					}

            					ajaxDestroyLoading(opts);
            				}
            			} catch(e) {}
            		}
            	} catch(e) {
            		ajaxShowException(opts, e);
            	}
            }

            ajaxCreateLoading(opts);
            xmlhttp.send(data);
        }
    } catch(e) {
		ajaxShowException(opts, e);
    }
}
