/*
	File: leafm.js
 */

var leafm = {};

leafm.libraries = {};
leafm.plugins = {};

leafm.helpers = {
	array: {		
	},
	
	date: {
	},

	elements: {
	},

	form: {
		display_errors: function(el, errors) {			
			if($(el)) {
				var parent_el = $(el);
				parent_el.getElements('.error').destroy();				
				parent_el.getElements('.ajax_load').destroy();

				if($type(errors) == 'object') {
					errors = $H(errors);
				} else {
					errors = $A(errors);	
				}				

				errors.each(function(err) {
					var target = parent_el.getElement('[name="' + err.name + '"]');
					var error_el = new Element('span', {'class':'error'}).set('html', err.message);
					error_el.injectAfter(target);
				});
			}
		},
		
		select: {
			get_index_by_text: function(value, select_el) {
				var index = null;
				select_el.getElements('option').each(function(opt, i) {
					if(opt.get('text') == value)
						index = i;
				});
				
				return index;
			},
			
			get_index_by_value: function(value, select_el) {
				var index = null;
				select_el.getElements('option').each(function(opt, i) {
					if(opt.value == value)
						index = i;
				});
				
				return index;
			}
		},
		
		validate: {
			email: function(input) {
				if(input.match(/^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/i)) {
					return true;
				} else {
					return false;
				}				
			},

			emails: function(input) {
				if(!input.contains(',')) {
					if(leafm.helpers.form.validate.email(input.trim())) {
						return true;
					}
					
					return false;							
				} else {
					var emails = input.split(',');
					var valid = true;
					
					emails.each(function(email) {
						if(!leafm.helpers.form.validate.email(email.trim())) {
							valid = false;
						}
					});
										
					return valid;
				}
			},
			
			phone: function(input) {
				if(input.match(/[a-z]+/i)) { // If phone has letters, return false
					return false;
				} else {			
					input = input.replace(/[^0-9]+/g, '');
					
					if(input.length >= 10) { // Make sure phone is at least 10 numbers
						return true;
					} else {
						return false;
					}
				}				
			},
			
			strtotime: function(input) {
				var reg =
					'^now$|^tomorrow$|^yesterday$|^today$|' +
					'^(next|last) (year|week|month)$|' + 
					'^([ ]?[\+\-][0-9]+ (week|day|month|year|hour|minute)s?)+$|' +
					'^(jan|feb|mar|apr|may|jun|jul|aug|sept|oct|nov|dec|january|february|march|april|may|june|july|august|september|november|december) [0-3]?[0-9] ([0-9]{2}|[0-9]{4})[ ]*([0-9]{1,2}(\:[0-5][0-9])?.?(am|pm)?)?$|' +
					'^[01]?[0-9].[0-3]?[0-9]{1}.([0-9]{2}|[0-9]{4})( [0-9]{1,2}(\:[0-5][0-9])?.?(am|pm)?)?$';
				
				if(input.test(reg, 'i')) {
					return true;
				}
				
				return false;
			},
			 
			url: function(input) {
				var reg = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
		
				if(reg.test(input)) {
					return true;
				} else {
					return false;
				}				
			},
			
			zip: function(input) {
				if(input.match(/[a-z]+/i)) { // If zip has letters, return false
					return false;
				} else {			
					input = input.replace(/[^0-9]+/g, '');
					
					if(input.length >= 5) { // Make zip is at least 5 numbers
						return true;
					} else {
						return false;
					}
				}				
			}
		}		
	},
		
	encrypt: {
		base64_decode: function(data) {
		    var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
		    var o1, o2, o3, h1, h2, h3, h4, bits, i = ac = 0, dec = "", tmp_arr = [];
		 
		    data += '';
		 
		    do {  // unpack four hexets into three octets using index points in b64
		        h1 = b64.indexOf(data.charAt(i++));
		        h2 = b64.indexOf(data.charAt(i++));
		        h3 = b64.indexOf(data.charAt(i++));
		        h4 = b64.indexOf(data.charAt(i++));
		 
		        bits = h1<<18 | h2<<12 | h3<<6 | h4;
		 
		        o1 = bits>>16 & 0xff;
		        o2 = bits>>8 & 0xff;
		        o3 = bits & 0xff;
		 
		        if (h3 == 64) {
		            tmp_arr[ac++] = String.fromCharCode(o1);
		        } else if (h4 == 64) {
		            tmp_arr[ac++] = String.fromCharCode(o1, o2);
		        } else {
		            tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
		        }
		    } while (i < data.length);
		 
		    dec = tmp_arr.join('');
		    dec = leafm.helpers.encrypt.utf8_decode(dec);
		 
		    return dec;
		},

		base64_encode: function(data) {
		    var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
		    var o1, o2, o3, h1, h2, h3, h4, bits, i = ac = 0, enc="", tmp_arr = [];
		    data = leafm.helpers.encrypt.utf8_encode(data);
		    
		    do { // pack three octets into four hexets
		        o1 = data.charCodeAt(i++);
		        o2 = data.charCodeAt(i++);
		        o3 = data.charCodeAt(i++);
		 
		        bits = o1<<16 | o2<<8 | o3;
		 
		        h1 = bits>>18 & 0x3f;
		        h2 = bits>>12 & 0x3f;
		        h3 = bits>>6 & 0x3f;
		        h4 = bits & 0x3f;
		 
		        // use hexets to index into b64, and append result to encoded string
		        tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
		    } while (i < data.length);
		    
		    enc = tmp_arr.join('');
		    
		    switch( data.length % 3 ){
		        case 1:
		            enc = enc.slice(0, -2) + '==';
		        break;
		        case 2:
		            enc = enc.slice(0, -1) + '=';
		        break;
		    }
		 
		    return enc;
		},

		decode: function() {
			
		},
		
		encode: function() {
			
		},

		md5: function(str) {
		    var RotateLeft = function(lValue, iShiftBits) {
		        return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits));
		    };
		 
		    var AddUnsigned = function(lX,lY) {
		        var lX4,lY4,lX8,lY8,lResult;
		        lX8 = (lX & 0x80000000);
		        lY8 = (lY & 0x80000000);
		        lX4 = (lX & 0x40000000);
		        lY4 = (lY & 0x40000000);
		        lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF);
		        if (lX4 & lY4) {
		            return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
		        }
		        if (lX4 | lY4) {
		            if (lResult & 0x40000000) {
		                return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
		            } else {
		                return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
		            }
		        } else {
		            return (lResult ^ lX8 ^ lY8);
		        }
		    };
		 
		    var F = function(x,y,z) { return (x & y) | ((~x) & z); };
		    var G = function(x,y,z) { return (x & z) | (y & (~z)); };
		    var H = function(x,y,z) { return (x ^ y ^ z); };
		    var I = function(x,y,z) { return (y ^ (x | (~z))); };
		 
		    var FF = function(a,b,c,d,x,s,ac) {
		        a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
		        return AddUnsigned(RotateLeft(a, s), b);
		    };
		 
		    var GG = function(a,b,c,d,x,s,ac) {
		        a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
		        return AddUnsigned(RotateLeft(a, s), b);
		    };
		 
		    var HH = function(a,b,c,d,x,s,ac) {
		        a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
		        return AddUnsigned(RotateLeft(a, s), b);
		    };
		 
		    var II = function(a,b,c,d,x,s,ac) {
		        a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
		        return AddUnsigned(RotateLeft(a, s), b);
		    };
		 
		    var ConvertToWordArray = function(str) {
		        var lWordCount;
		        var lMessageLength = str.length;
		        var lNumberOfWords_temp1=lMessageLength + 8;
		        var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64;
		        var lNumberOfWords = (lNumberOfWords_temp2+1)*16;
		        var lWordArray=Array(lNumberOfWords-1);
		        var lBytePosition = 0;
		        var lByteCount = 0;
		        while ( lByteCount < lMessageLength ) {
		            lWordCount = (lByteCount-(lByteCount % 4))/4;
		            lBytePosition = (lByteCount % 4)*8;
		            lWordArray[lWordCount] = (lWordArray[lWordCount] | (str.charCodeAt(lByteCount)<<lBytePosition));
		            lByteCount++;
		        }
		        lWordCount = (lByteCount-(lByteCount % 4))/4;
		        lBytePosition = (lByteCount % 4)*8;
		        lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition);
		        lWordArray[lNumberOfWords-2] = lMessageLength<<3;
		        lWordArray[lNumberOfWords-1] = lMessageLength>>>29;
		        return lWordArray;
		    };
		 
		    var WordToHex = function(lValue) {
		        var WordToHexValue="",WordToHexValue_temp="",lByte,lCount;
		        for (lCount = 0;lCount<=3;lCount++) {
		            lByte = (lValue>>>(lCount*8)) & 255;
		            WordToHexValue_temp = "0" + lByte.toString(16);
		            WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2);
		        }
		        return WordToHexValue;
		    };
		 
		    var x=Array();
		    var k,AA,BB,CC,DD,a,b,c,d;
		    var S11=7, S12=12, S13=17, S14=22;
		    var S21=5, S22=9 , S23=14, S24=20;
		    var S31=4, S32=11, S33=16, S34=23;
		    var S41=6, S42=10, S43=15, S44=21;
		 
		    str = utf8_encode(str);
		    x = ConvertToWordArray(str);
		    a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
		    
		    xl = x.length;
		    for (k=0;k<xl;k+=16) {
		        AA=a; BB=b; CC=c; DD=d;
		        a=FF(a,b,c,d,x[k+0], S11,0xD76AA478);
		        d=FF(d,a,b,c,x[k+1], S12,0xE8C7B756);
		        c=FF(c,d,a,b,x[k+2], S13,0x242070DB);
		        b=FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE);
		        a=FF(a,b,c,d,x[k+4], S11,0xF57C0FAF);
		        d=FF(d,a,b,c,x[k+5], S12,0x4787C62A);
		        c=FF(c,d,a,b,x[k+6], S13,0xA8304613);
		        b=FF(b,c,d,a,x[k+7], S14,0xFD469501);
		        a=FF(a,b,c,d,x[k+8], S11,0x698098D8);
		        d=FF(d,a,b,c,x[k+9], S12,0x8B44F7AF);
		        c=FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1);
		        b=FF(b,c,d,a,x[k+11],S14,0x895CD7BE);
		        a=FF(a,b,c,d,x[k+12],S11,0x6B901122);
		        d=FF(d,a,b,c,x[k+13],S12,0xFD987193);
		        c=FF(c,d,a,b,x[k+14],S13,0xA679438E);
		        b=FF(b,c,d,a,x[k+15],S14,0x49B40821);
		        a=GG(a,b,c,d,x[k+1], S21,0xF61E2562);
		        d=GG(d,a,b,c,x[k+6], S22,0xC040B340);
		        c=GG(c,d,a,b,x[k+11],S23,0x265E5A51);
		        b=GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA);
		        a=GG(a,b,c,d,x[k+5], S21,0xD62F105D);
		        d=GG(d,a,b,c,x[k+10],S22,0x2441453);
		        c=GG(c,d,a,b,x[k+15],S23,0xD8A1E681);
		        b=GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8);
		        a=GG(a,b,c,d,x[k+9], S21,0x21E1CDE6);
		        d=GG(d,a,b,c,x[k+14],S22,0xC33707D6);
		        c=GG(c,d,a,b,x[k+3], S23,0xF4D50D87);
		        b=GG(b,c,d,a,x[k+8], S24,0x455A14ED);
		        a=GG(a,b,c,d,x[k+13],S21,0xA9E3E905);
		        d=GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8);
		        c=GG(c,d,a,b,x[k+7], S23,0x676F02D9);
		        b=GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);
		        a=HH(a,b,c,d,x[k+5], S31,0xFFFA3942);
		        d=HH(d,a,b,c,x[k+8], S32,0x8771F681);
		        c=HH(c,d,a,b,x[k+11],S33,0x6D9D6122);
		        b=HH(b,c,d,a,x[k+14],S34,0xFDE5380C);
		        a=HH(a,b,c,d,x[k+1], S31,0xA4BEEA44);
		        d=HH(d,a,b,c,x[k+4], S32,0x4BDECFA9);
		        c=HH(c,d,a,b,x[k+7], S33,0xF6BB4B60);
		        b=HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);
		        a=HH(a,b,c,d,x[k+13],S31,0x289B7EC6);
		        d=HH(d,a,b,c,x[k+0], S32,0xEAA127FA);
		        c=HH(c,d,a,b,x[k+3], S33,0xD4EF3085);
		        b=HH(b,c,d,a,x[k+6], S34,0x4881D05);
		        a=HH(a,b,c,d,x[k+9], S31,0xD9D4D039);
		        d=HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);
		        c=HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);
		        b=HH(b,c,d,a,x[k+2], S34,0xC4AC5665);
		        a=II(a,b,c,d,x[k+0], S41,0xF4292244);
		        d=II(d,a,b,c,x[k+7], S42,0x432AFF97);
		        c=II(c,d,a,b,x[k+14],S43,0xAB9423A7);
		        b=II(b,c,d,a,x[k+5], S44,0xFC93A039);
		        a=II(a,b,c,d,x[k+12],S41,0x655B59C3);
		        d=II(d,a,b,c,x[k+3], S42,0x8F0CCC92);
		        c=II(c,d,a,b,x[k+10],S43,0xFFEFF47D);
		        b=II(b,c,d,a,x[k+1], S44,0x85845DD1);
		        a=II(a,b,c,d,x[k+8], S41,0x6FA87E4F);
		        d=II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);
		        c=II(c,d,a,b,x[k+6], S43,0xA3014314);
		        b=II(b,c,d,a,x[k+13],S44,0x4E0811A1);
		        a=II(a,b,c,d,x[k+4], S41,0xF7537E82);
		        d=II(d,a,b,c,x[k+11],S42,0xBD3AF235);
		        c=II(c,d,a,b,x[k+2], S43,0x2AD7D2BB);
		        b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
		        a=AddUnsigned(a,AA);
		        b=AddUnsigned(b,BB);
		        c=AddUnsigned(c,CC);
		        d=AddUnsigned(d,DD);
		    }
		 
		    var temp = WordToHex(a)+WordToHex(b)+WordToHex(c)+WordToHex(d);
		 
		    return temp.toLowerCase();
		},

		utf8_decode: function(str_data) {
			var tmp_arr = [], i = ac = c1 = c2 = c3 = 0;
			
			str_data += '';
			
			while ( i < str_data.length ) {
				c1 = str_data.charCodeAt(i);
				if (c1 < 128) {
					tmp_arr[ac++] = String.fromCharCode(c1);
					i++;
				} else if ((c1 > 191) && (c1 < 224)) {
					c2 = str_data.charCodeAt(i+1);
					tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
					i += 2;
				} else {
					c2 = str_data.charCodeAt(i+1);
					c3 = str_data.charCodeAt(i+2);
					tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
					i += 3;
				}
			}
			
			return tmp_arr.join('');			
		},

		utf8_encode: function(string) {
		    string = (string+'').replace(/\r\n/g, "\n").replace(/\r/g, "\n");
		 
		    var utftext = "";
		    var start, end;
		    var stringl = 0;
		 
		    start = end = 0;
		    stringl = string.length;
		    for (var n = 0; n < stringl; n++) {
		        var c1 = string.charCodeAt(n);
		        var enc = null;
		 
		        if (c1 < 128) {
		            end++;
		        } else if((c1 > 127) && (c1 < 2048)) {
		            enc = String.fromCharCode((c1 >> 6) | 192) + String.fromCharCode((c1 & 63) | 128);
		        } else {
		            enc = String.fromCharCode((c1 >> 12) | 224) + String.fromCharCode(((c1 >> 6) & 63) | 128) + String.fromCharCode((c1 & 63) | 128);
		        }
		        if (enc != null) {
		            if (end > start) {
		                utftext += string.substring(start, end);
		            }
		            utftext += enc;
		            start = end = n+1;
		        }
		    }
		 
		    if (end > start) {
		        utftext += string.substring(start, string.length);
		    }
		 
		    return utftext;
		}
	},
	
	number: {
		decimal: function(value, places) {
			return value.toFixed(places);
		},
		
		// 2 decimal places with commans, no dollar sign
		dollar: function(value) {
		},
		
		to_float: function(value) {
			if(isNaN(value.toFloat())) {
				return 0.0;
			}
			
			return value.toFloat();
		},
		
		to_int: function(value) {
			if(isNaN(value.toInt())) {
				return 0;
			}
			
			return value.toInt();			
		}
	},
	
	page: {
		/*
			Class: leafm.helpers.page.ajax_list
				Class for making dynamic ajax lists
				
			Parameters:
				id
				options
				
			Changelog:
				- 2009 Jan 2 6:37pm - will - Modified the options parameter a
					bit. Now you can send native JS without using the $H() which
					is done automatically.
		 */				
		ajax_list: new Class({
			_el: '',
			_ajax: '',
			_curr_query: {
				driver: 'mysql',
				model: '',
				network: '',
				
				layout: '',
				url: '',
				search_terms: '',
				
				fields: '',
				conditions: '',
				order: '',
				limit: '',
				page: '',
				
				left_join: '',
				join: '',
				
				curr_page: '',
				curr_record: '',
				total_pages: '',
				total_records: ''
			},
			
			initialize: function(el, options) {
				var parent_el = $(el);
				var obj = this;
				
				obj._ajax = new Request();
				obj._curr_query = $H(obj._curr_query);
				obj.events = $H(obj.events);
				
				obj._el = parent_el;

				if(options && options.query) { // Initial query
					options.query = $H(options.query);
					options.query.each(function(value, key) {
						obj._curr_query.set(key, value);
					});
				}							

				if(options && options.events) { // Any events?
					options.events = $H(options.events);
					options.events.each(function(value, key) {
						obj.events.set(key, value);
					});
				}
				
				if(options && options.auto_refresh) {
					obj.refresh.periodical(5000, obj);
				}
				
				if(options && options.driver) {
					obj._curr_query.driver = options.driver;
				}
				
				// If data already exists
				if(parent_el.getElement('div.data')) {
					obj.update_query.bind(this)();
					
					obj.update();					
				// Otherwise load it thru ajax
				} else {
					obj.refresh('ajax_list');
				}								
			},
			
			events: {
				// Function that runs after a refresh
				after_refresh: function() {					
				},
				
				// Function runs before a refresh			
				before_refresh: function() {					
				}
			},
			
			goto_page: function(page_no) {
				
			},
			
			refresh: function(name, options) {
				var obj = this;
				var parent_el = $(obj._el);
				
				// bug 6821
				if (typeof name == 'object' && name.constructor.toString().indexOf("Array") != -1) {
					name = name[0];
				}
				
				switch(name) {
					case 'ajax_list':						
						var qry = obj.parse_query.bind(obj)();
						
						obj._ajax = new Request({url: '/leafm/ajax_list/'})
							.addEvent('complete', function(resp) {
								parent_el.set('html', resp);
								obj.update_query.bind(obj)();
								
								if(options && options.transition) {
									parent_el.getElements('li').tween('opacity', 0, 1);
								}
								
								obj.update.bind(obj, ['ajax_list'])();
								obj.events.get('after_refresh')();
							})						
							.send(qry);
						break;
					
					case 'viewer':
						var qry = obj.parse_query.bind(obj)();
						
						obj._ajax = new Request({url: '/leafm/ajax_list_viewer/'})
							.addEvent('complete', function(resp) {
								parent_el.getElement('.viewer').set('html', resp);
								obj.update_query.bind(obj)();

								if(options && options.transition) {								
									parent_el.getElements('li').tween('opacity', 0, 1);
								}
								
								obj.update.bind(obj, ['viewer'])();
								obj.events.get('after_refresh')();
							})
							.send(qry);
						break;
					
					case null:
					case undefined:
						obj.refresh('viewer', options);
						break;
				}				
			},
			
			update: function(name) {
				var obj = this;
				var parent_el = $(obj._el);
				
				// bug 6821
				if (typeof name == 'object' && name.constructor.toString().indexOf("Array") != -1) {
					name = name[0];
				}
				
				switch(name) {
					case 'ajax_list':
						obj.update.bind(obj, ['subnav'])();
						obj.update.bind(obj, ['viewer'])();
						obj.update.bind(obj, ['footer'])();						
						break;
						
					case 'viewer':
						if(parent_el.getElement('.page_list')) {
							var target_el = parent_el.getElement('.page_list');
							target_el.empty();
										
							if(obj._curr_query.get('page') != 1) {
								new Element('a', {'class': 'ctrl_page_prev', 'html': '&lt;'}).inject(target_el);
							}
								
							for(x=obj._curr_query.get('curr_page').toInt()-5; x<= obj._curr_query.get('curr_page').toInt()+5; x++) {
								if(x > 0 && x <= obj._curr_query.get('total_pages')) {
									var ctrl_goto_page = new Element('a', {'class': 'ctrl_goto_page_' + x, 'text': x});
									
									if(x == obj._curr_query.get('curr_page')) {
										ctrl_goto_page.addClass('selected');
									}
									
									ctrl_goto_page.inject(target_el);
								}
							}

							if(obj._curr_query.get('page') != obj._curr_query.get('total_pages')) {
								new Element('a', {'class': 'ctrl_page_next', 'html': '&gt;'}).inject(target_el);
							}
						}
						
						parent_el.getElements('.curr_page').each(function(el) {
							el.set('html', obj._curr_query.get('page'));
						});
						
						parent_el.getElements('.total_pages').each(function(el) {
							el.set('html', obj._curr_query.get('total_pages'));
						});
						
						parent_el.getElements('.ctrl_page_prev').each(function(ctrl) {
							ctrl.removeEvents();
							ctrl.addEvent('click', function() {
								if((parseInt(obj._curr_query.get('page')) - 1) > 0) {
									obj._curr_query.set('page', parseInt(obj._curr_query.get('page')) - 1);
									obj.refresh.bind(obj, ['viewer'])();
								}
							});
						});
						
						parent_el.getElements('.ctrl_page_next').each(function(ctrl) {
							ctrl.removeEvents();
							ctrl.addEvent('click', function() {
								if((parseInt(obj._curr_query.get('page')) + 1) <= obj._curr_query.get('total_pages')) {
									obj._curr_query.set('page', parseInt(obj._curr_query.get('page')) + 1);
									obj.refresh.bind(obj, ['viewer'])();
								}
							});
						});
						
						parent_el.getElements('.footer [class^=ctrl_goto_page_]').each(function(ctrl) {
							ctrl.removeEvents();
							ctrl.addEvent('click', function() {
								var to_page = ctrl.getProperty('class').match(/ctrl_goto_page_([0-9]+)/)[1];
								
								obj._curr_query.set('page', to_page);
								obj.refresh.bind(obj, ['viewer'])();
							});
						});
						break;
					
					case 'footer':
						break;
						
					case 'subnav':						
						var sub_el = parent_el.getElement('.subnav');

						if(sub_el.getElement('.ctrl_limit')) {
							sub_el.getElement('.ctrl_limit').removeEvents();
							sub_el.getElement('.ctrl_limit').addEvent('change', function() {
								obj._curr_query.set('limit', this.value);
								obj._curr_query.set('page', 1);
								obj.refresh.bind(obj, ['viewer'])();
							});
						}
						
						if(sub_el.getElement('.ctrl_order')) {
							sub_el.getElement('.ctrl_order').removeEvents();
							sub_el.getElement('.ctrl_order').addEvent('change', function() {
								obj._curr_query.set('order', this.value);
								obj._curr_query.set('page', 1);
								obj.refresh.bind(obj, ['viewer'])();
							});
						}
						
						if(sub_el.getElement('.ctrl_search')) {
							sub_el.getElement('input.ctrl_search');
							sub_el.getElement('input.ctrl_search').addEvent('keyup', function(e) {
								var e = new Event(e);
								
								if(e.code >=46 && e.code <=90 || e.code == 8) {
									obj._curr_query.set('page', 1);
									
									if(this.value == '') {
										obj._curr_query.set('search_terms', '');										
									} else {
										obj._curr_query.set('search_terms', this.value);
									}

									obj.refresh.bind(obj, ['viewer'])();
								}
							});
						}
						
						break;
				}
			},
			
			/*
				Function: parse_query
					Parse the MySQL query data before refresh
			 */
			parse_query: function() {
				var obj = this;	
				
				var temp_qry = $H();
				obj._curr_query.each(function(value, key) {
					if(value && value != '') {
						temp_qry.set('data[Query][' + key + ']', value);
					}
				});				
				var qry = 'data=' + escape(leafm.helpers.encrypt.base64_encode(temp_qry.toQueryString()));								
				
				return qry;				
			},
			
			/*
				Function: update_query
					Will get the query parameters from the html
					
					Requires this to point to the ajax_class instantiation
			 */
			update_query: function() {
				var obj = this;
				var parent_el = $(obj._el);

				var qry_els = parent_el.getElements('div.data.query *');
				qry_els.each(function(qry) {
					var classname = qry.get('class');
					
					var qry_property = classname.match(/data\[Query\]\[([a-z_]+)\]/i)[1];
					var qry_value = qry.get('html');

					if(qry_value.match(/^\{.*\}$/)) {
						obj._curr_query.set(qry_property, JSON.decode(qry_value));
					} else if(qry_value.match(/^\[.*\]$/)) {
						obj._curr_query.set(qry_property, eval(qry_value));
					} else {
						obj._curr_query.set(qry_property, qry_value);	
					}													
				});
			}
		}),
		
		/*
			Function: alert
				Browser dynamic alert messages that do not affect 
				javascript flow.
				
			Parameters:
				message - (string)
				options - (object) options.class, options.auto_close
		 */
		alert: function(message, options) {
			var new_el = leafm.helpers.page.load(
				null, 
				'<div class="content"><div class="body">' + message + '</div></div>',
				options
			);
			
			leafm.helpers.page.close.delay(5000, null, [new_el]);
		},
		
		close: function(el) {
			if($(el)) {
				$(el).destroy();
				leafm.helpers.page.hide_shroud();
			}
		},
		
		/*
			Function: center
				Will center an element. Make sure width is set and display is block.
		 */
		center: function(el) {
			if($(el)) {
				var parent_el = $(el);
				var size = parent_el.getSize();
				var win_size = window.getSize();				

				// If the element is larget than the viewport, make it position absolute
				if(size.y >= (win_size.y - 100) || size.x >= (win_size.x - 100)) {
					parent_el.setStyles({
						left: 10,
						top: 10,
						position: 'absolute'
					});
				} else {
					var new_x = ((win_size.x - size.x)/2).floor();
					var new_y = ((win_size.y - size.y)/2).floor();

					parent_el.setStyles({
						left: new_x,
						top: new_y,
						position: 'fixed'
					});
				}
			}
		},
		
		display: function(el) {
			if($(el)) {
				$(el).setStyle('display', 'block');
			}			
		},
		
		display_shroud: function() {
			if($('leafm_shroud')) {
				$('leafm_shroud').setStyle('display', 'none');
			}
		},
		
		hide_shroud: function() {
			if($('leafm_shroud')) {
				$('leafm_shroud').setStyle('display', 'block');
			}
		},
		
		hide: function(el) {
			if($(el)) {
				$(el).setStyle('display', 'none');
			}
		},
		
		load: function(el_id, html, options) {
			if(!$(el_id)) {
				options = $H(options);
				
				var new_el = new Element('div', {
					'class': 'window',
					'styles': {
						display: 'block',
						position: 'absolute'
					}
				}).set('html', html);
				
				// If el_id is set and is a string, not element, set the id
				if($type(el_id) == 'string') {
					new_el.setProperty('id', el_id);
				}
				
				// If extra options are set, set them
				if($type(options.get('class')) == 'string') {
					new_el.addClass(options.get('class'));					
				}
				
				// If draggable option is set
				if(options.get('draggable')) {
					new Drag(new_el, {
						handle: new_el.getElement('.header')
					});
				}
				
				new_el.injectAfter($('page'));
				
				leafm.helpers.page.display(new_el);
				leafm.helpers.page.center(new_el);
				
				new_el.getElements('.ctrl_close').each(function(el) {
					el.removeEvents();
					el.addEvent('click', function() {
						leafm.helpers.page.close(new_el);
					});
				});
				
				return new_el;
			}
		},
		
		tip: {},
		
		window: new Class({
			_el: '',
			
			initialize: function(id, html, options) {
				var obj = this;
				obj.events = $H(obj.events);
				var options = $H(options);
				
				if(!$(id)) {
					var new_el = new Element('div', {
						'class': 'window',
						'styles': {
							display: 'block',
							position: 'absolute'
						}
					}).set('html', html);
					
					// If el_id is set and is a string, not element, set the id
					if($type(id) == 'string') {
						new_el.setProperty('id', id);
					}
					
					// If extra options are set, set them
					if($type(options.get('class')) == 'string') {
						new_el.addClass(options.get('class'));					
					}
					
					// If draggable option is set
					if(options.get('draggable')) {
						new Drag(new_el, {
							handle: new_el.getElement('.header')
						});
					}					
					
					// If events option is set
					if(options.get('events')) {						
						var events = $H(options.get('events'));
						events.each(function(event, key) {
							obj.events.set(key, event);
						});
					}

					new_el.injectAfter($('page'));
					
					leafm.helpers.page.display(new_el);
					leafm.helpers.page.center(new_el);
					
					new_el.getElements('.ctrl_close').each(function(el) {
						obj.events.get('before_close')();

						el.removeEvents();
						el.addEvent('click', function() {
							leafm.helpers.page.close(new_el);
							
							obj.events.get('after_close')();
						});
					});
					
					
					obj._el = new_el;					
				}
			},
			
			events: {
				before_load: function() {					
				},
				
				after_close: function() {					
				},
				
				before_close: function() {					
				}
			},
			
			close: function() {				
			},
			
			minimize: function() {				
			}
		})
	},
	
	string: {
		alphasafe: function(str) {
			str = str.toLowerCase().replace(/[^a-z0-9]/i, '_');
						
			return str;
		},
		
		english: function(str) {			
		},
		
		pad: function(input, pad_length, pad_string, pad_type) {			
			var half = '', pad_to_go;
			
			var str_pad_repeater = function(s, len) {
				var collect = '', i;
			
			    while(collect.length < len) collect += s;
			    collect = collect.substr(0,len);
			
			    return collect;
			};
			
			input += '';
			
			if (pad_type != 'STR_PAD_LEFT' && pad_type != 'STR_PAD_RIGHT' && pad_type != 'STR_PAD_BOTH') { pad_type = 'STR_PAD_RIGHT'; }
			if ((pad_to_go = pad_length - input.length) > 0) {
			    if (pad_type == 'STR_PAD_LEFT') { input = str_pad_repeater(pad_string, pad_to_go) + input; }
			    else if (pad_type == 'STR_PAD_RIGHT') { input = input + str_pad_repeater(pad_string, pad_to_go); }
			    else if (pad_type == 'STR_PAD_BOTH') {
			        half = str_pad_repeater(pad_string, Math.ceil(pad_to_go/2));
			        input = half + input + half;
			        input = input.substr(0, pad_length);
			    }
			}
			
			return input;				
		}
	}
}
