/**
 * majax - mini AJAX functions
 *
 * Usage:
 * majax.get(url, function(text){document.getElementById('targetid').innerHTML = text;});
 * majax.login('myusername','mypassword');
 * majax.get(url, 'targetid');
 * majax.post( majax.formData('myform'), url, 'targetid');
 * <form action="url" onsubmit="return majax.submit(this,'targetid')">...</form>
 * The 'targetid' can either be the id of a document element or a function to execute.
 *
 * Copyright 2008, Mack Pexton <mack at acmebase.org>
 * License: http://www.opensource.org/licenses/mit-license.php
 */

if (!window.$) $ = function(e) { return (typeof e == 'string') ? document.getElementById(e) : e; }

var majax = {
	// Public
	get: function(url,handler) {
		var req = majax._request(handler);
		if (!req) return;
		req.open('GET', url, true);
                req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
		if (majax._auth) req.setRequestHeader('Authorization',majax._auth);
		if (window.XMLHttpRequest) { req.send(null) } else { req.send() }
	},
	post: function(data,url,handler) {
		var req = majax._request(handler);
		if (!req) return;
		var datastr = majax.toQuery(data);
		req.open('POST', url, true);
		req.setRequestHeader('Content-type','application/x-www-form-urlencoded; charset=UTF-8'); 
		req.setRequestHeader("Content-length", datastr.length);
		req.setRequestHeader("Connection", "close");
		req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
		if (majax._auth) req.setRequestHeader('Authorization',majax._auth);
		req.send(datastr);
	},
	submit: function(frm,handler) {
		majax.post(majax.formData(frm),frm.action,handler);
		return false;
	},

	login: function(user,password) {
		/* from http://coderseye.com/2007/how-to-do-http-basic-auth-in-ajax.html */
		majax._auth = 'Basic '+encodeBase64(user+':'+password);
	},

	evalJSON: function(text) {
		if (majax.isJSON(text)) {
			try { return eval('('+text+')'); } catch(e) { }
		}
		throw 'Bad JSON string: '+text;
	},
	isJSON: function(text) {
		return (/^\s*[\[{].*[}\]]\s*$/.test(text));
	},

	toQuery: function(data) {
		if (data == null) return '';
		var arr = [];
		for (var d in data) { arr.push(encodeURIComponent(d) + '=' + encodeURIComponent(data[d])); }
		return arr.join('&');
	},

	formData: function(frm) {
		var e, data = {}, formfields = this.formFields(frm);
		for (var i = 0,l= formfields.length; i<l; i++) {
			e = formfields[i];
			if (e.type && (e.type == 'radio' || e.type == 'checkbox')) {
				if (e.checked && e.name) data[e.name] = e.value;
			}
			else {
				if (e.name) data[e.name] = e.value;
			}
		}
		return data;
	},
	formFields: function(frm) {
		var e, arr, result = [];
		arr = frm.getElementsByTagName('INPUT');
		for (e in arr) { if (typeof arr[e] == 'object') result.push( (arr[e].type ? arr[e] : this._getCorrectRadioElementFromStupidIE(arr[e])) ); }
		arr = frm.getElementsByTagName('SELECT');
		for (e in arr) { if (typeof arr[e] == 'object') result.push(arr[e]); }
		arr = frm.getElementsByTagName('TEXTAREA');
		for (e in arr) { if (typeof arr[e] == 'object') result.push(arr[e]); }
		return result;
	},

	// Private 
	_auth: null,
	_currentRadioButtonIndex: {},
	_getCorrectRadioElementFromStupidIE: function(e) {
		// Accommodate IE who returns an array of all radio buttons 
		// for each radio input element found in document.
		// Return the radio element corresponding to it's place in document.
		if (e.length && e.length > 0) {
			var name = e[0].name;
			if (typeof this._currentRadioButtonIndex[name] == 'undefined') this._currentRadioButtonIndex[name] = 0;
			return e[ this._currentRadioButtonIndex[name]++ ];
		}
	},
	_request: function(handler) {
		var callback = function(s){
			if(handler){
				if(typeof handler == 'function'){ handler(s); } else{ $(handler).innerHTML = s; }
			}
		};
		var req = window.XMLHttpRequest ? new XMLHttpRequest
			: window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP')
			: null;
		if (req) {
			req.onreadystatechange = function() {
				if (req.readyState == 4) {
					if (req.status == 200 || req.status == 304) {
						callback(req.responseText);
					}
					else {
						throw 'majax error: '+req.statusText;
					}
				}
			}
		}
		return req;
	}
}

/* Base64 code from Tyler Akins -- http://rumkin.com */
function encodeBase64(input) {
	var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
	var output = "";
	var chr1, chr2, chr3;
	var enc1, enc2, enc3, enc4;
	var i = 0;
	do {
		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 + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);
	} while( i < input.length );
	return output;
}
function decodeBase64(input) {
	var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
	var output = "";
	var chr1, chr2, chr3;
	var enc1, enc2, enc3, enc4;
	var i = 0;
	input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
	do {
		enc1 = keyStr.indexOf(input.charAt(i++));
		enc2 = keyStr.indexOf(input.charAt(i++));
		enc3 = keyStr.indexOf(input.charAt(i++));
		enc4 = 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); }
	} while(i < input.length);
	return output;
}

