/**
 * general.js
 *  
 * This software is provided "AS IS," without a warranty of any kind.
**/

var URIHostname = location.hostname;
var _usercookies_  = '_usercookies_';
var _opacity_ = false;
var _protoculousG_ = _protoculous_ > 0 ? _protoculous_ : 0;

if(typeof frameable == 'undefined' && top.location != self.location){top.location=self.location;}

if (document.documentElement && typeof document.documentElement.style != 'undefined') {
  if (typeof document.documentElement.style.opacity != 'undefined' || typeof document.documentElement.style.MozOpacity  != 'undefined' || typeof document.documentElement.style.KhtmlOpacity  != 'undefined' || typeof document.documentElement.style.filter != 'undefined') {
  	_opacity_ = true;
  }
}

var detectCSS = function(objID, cb) {
		var img = document.getElementById(objID);
        if (!img) return;
        var callback = cb;
        var imgDisabled = false;
        var cssDisabled = false;
        
        if(typeof document.defaultView != "undefined" && typeof document.defaultView.getComputedStyle != "undefined") {
            cssDisabled = (document.defaultView.getComputedStyle(img,"").getPropertyValue("display") != 'none');
        } else if(typeof img.currentStyle != "undefined") {
            cssDisabled = (img.currentStyle.display != 'none');
        }

        if (img.readyState && img.readyState != 'undefined') {
            if (img.readyState == 'uninitialized') {
                imgDisabled=true;
            }
        } else if (img.complete && img.complete === true) {
            if (img.width === 0 && img.height === 0) {
                imgDisabled=true;
            }
        } else if (img.complete === false) {
            imgDisabled=true;
        }
        //alert(img.complete +'-'+ img.width +'-'+ img.height +'-'+ img.readyState);
        callback(imgDisabled, cssDisabled);
};

function FCKeditorReset() {
	var i, oEditor, oValue;
	var oFields = FCKeditorReset.arguments;
	
	for (i=0; i<oFields.length; i++) {
	// Get the editor instance that we want to interact with.
	    oEditor = FCKeditorAPI.GetInstance(oFields[i]) ;
	    oValue  = js_find_obj(oFields[i]) ;
        
        if (oEditor && oValue) {
	        // Set the editor contents (replace the actual one).
	        oEditor.SetHTML( oValue.value ) ;
	        oEditor.ResetIsDirty();
	    }
	}
}

/*
Utility Function
*/
var Utility = function(){};
Object.extend(Utility,{
        LZ: function(x) {
            return(x<0||x>9?"":"0")+x;
        },
        isInt: function(x) {
            var digits="1234567890";
            for(var i=0; i < x.length; i++) {
                if (digits.indexOf(x.charAt(i))==-1) {
                    return false;
                }
            }
            return true;
        },
        getInt: function(str) {
			var digits="1234567890";
			var ret = '';
			var start = false;
			for(var i=0; i < str.length; i++) {
                if (digits.indexOf(str.charAt(i))==-1) {
                    if (start) break;
                } else {
					ret += str.charAt(i);
					if (!start) start = true;
				}
            }
            return ret;
        },
        captchaURL: null,
        captchaReload: function(element) {
            element = $(element);
            if (!element) return alert('There is no security image in this form!');
            if (Utility.captchaURL == null) captchaURL = element.src;
            
            element.style.visibility='hidden';
            element.src = captchaURL + '&zr=' + Utility.random();
        },
        winPopup: new Array(),
        winOpen: function(options) {
            var popUp = false;
            options.url = options.url || false;
            options.name = options.name || false;
            if (!options.url || !options.name) return alert('winOpen required "url" and "name" properties!');
            options.width = options.width || 600;
            options.height = options.height || 400;
            options.resizable = options.resizable || 'yes';
            options.scrollbar = options.scrollbar || 'yes';
            
            if (Utility.winPopup[options.name]) {
                popUp = Utility.winPopup[options.name];
            }
            
            if (!popUp || popUp.closed ) {
                popUp=window.open(options.url,options.name,"width="+options.width+",height="+options.height+",top=10,left=10,resizable="+options.resizable+",scrollbars="+options.scrollbar+",menubar=no,toolbar=no,status=no,location=no");
                Utility.winPopup[options.name] = popUp;
            } else {
                popUp.location=options.url;
            }
            if (popUp && popUp.focus) popUp.focus();
            
            return popUp;
        }, 
        winClose: function(name) {
            var quirksMode = (top == self), popUp=false;
            if (quirksMode) {
                top.location.href = location.hostname;
            } else {
                if (parent.focus) parent.focus();
                if (window.focus) window.focus();
            }
            if (Utility.winPopup[name]) {
                popUp = Utility.winPopup[name];
            }
            if (!popUp || popUp.closed ) {
                popUp=null;
            } else {
                if (popUp.close) popUp.close();
                Utility.winPopup[name] = popUp;
            }
            return popUp;
        },
        toolPrint: function(w) {
            if (!w) w=window;
            if (!w.print) alert('Browser does not this script. Try to print from menu or use ctr+p.');
            else w.print();
        },
        toolPrintPreview: function(onoff, objp) {
            var i, a, objp;
            if (objp) objp=$(objp);
            if (objp) objp.innerHTML = '<strong>Mode: Print Preview</strong> <a href="#" onclick="Utility.toolPrint(); return false;">print this page</a> | <a href="#" onclick="Utility.toolPrintCancel(\'style_preview\'); return false;">back to normal view</a>';
            
            for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
                if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title")) {
                     a.disabled = true;
                     if(a.getAttribute("title") == onoff) a.disabled = false;
                }
            }
        },
        toolPrintCancel: function(onoff) {
            var i, a, main;
            for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
                if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title")) {
                     a.disabled = false;
                     if(a.getAttribute("title") == onoff) a.disabled = true;
                }
            }
        },
        toolPDF: function() {
            var wl = window.location; var uri = wl.protocol + '//' + wl.host + wl.pathname;
            if (wl.search && wl.search != '') uri += wl.search + '&'; else uri += '?';
            uri += 'print=pdf'; uri += '&hash=' + wl.hash;
            return Utility.winOpen({url:uri, name:'print'});
        },
        toolWatch: function(obj) {
            var lust = $(obj); if (!lust) return;
            var list = lust.getElementsByTagName('li');
            if (list && list.length > 0 && list[list.length -1].name == '_nolist_') Element.remove(list[list.length -1]);
                
            if (UserCookie.isLogin()) {
                var url = _baseuri_ + 'xml/watchlist-add.xml';
                new Ajax.Request(url, {
                        method: 'post',
                        parameters: 'fID='+_fID+'&pID='+_pID+''
                });
            } else {
                var check = UserCookie.getIn('wl');
                if (check.indexOf(_pID+"") >= 0) {
                    return alert('Already in the list');
                }
                check = UserCookie.setIn('wl', _pID+"");
            }
            lust.innerHTML = '<li><a href="'+document.location+'">'+document.title+'</a></li>' + lust.innerHTML;
        },
        trim: function(str) {
            return str.replace(/^\s+|\s+$/g,"");
        },
        textCounter: function(field, maxlimit) {
            if (field.value && field.value.length > maxlimit) {
                field.value = field.value.substring(0, maxlimit);
                return('Only '+maxlimit+' character allowed!');
            } 
            return true;
        },
        random: function() {
            return new Date().getTime();
        },
        findOffset: function(obj, checkParent) {
            var curleft = curtop = curwidth = curheight = 0;
            if (obj.offsetParent) {
                curwidth = obj.offsetWidth
                curheight = obj.offsetHeight
                curleft = obj.offsetLeft
                curtop = obj.offsetTop
                if (checkParent) {
                    while (obj = obj.offsetParent) {
                        curleft += obj.offsetLeft
                        curtop += obj.offsetTop
                    }
                }
                return [curwidth,curheight,curleft,curtop];
            } else {
                return false;
            }
        }
});

function loginForm(formName, captcha) {
    if (typeof formValidator == 'undefined') return;
    var lF = new formValidator(formName);
    lF.addField("username", "Username field", "required||alnumhyphen");
    lF.addField("password", "Password field", "required");
    
    if (captcha===true) {
        lF.addField("fcaptcha", "Security field", "required");
        pageLogin();
    }
}

function rowOverEffect(object) {
  if (object.className == 'dataTableRow') object.className = 'dataTableRowOver';
}

function rowOutEffect(object) {
  if (object.className == 'dataTableRowOver') object.className = 'dataTableRow';
}


/*
 * COOKIES
 */
var Cookie = function() {};
Object.extend(Cookie, {
    set: function(name, value, expires, path, domain, secure) {
        if (expires && expires != 0) {
            var exdate=new Date();
            exdate.setDate(exdate.getDate()+expires);
        }
        document.cookie = name + "=" + escape(value) + ((expires) ? "; expires=" + exdate.toGMTString() : "; expires=0") + ((path) ? "; path=" + path : "/") + ((domain) ? "; domain=" + domain : "") + ((secure) ? "; secure" : "");
    },
    getValue: function(offset) {
        var endstr = document.cookie.indexOf (";", offset);
        if (endstr == -1) {
            endstr = document.cookie.length;
        }
        return unescape(document.cookie.substring(offset, endstr));
    },
    get: function(name) {
        var arg = name + "=";
        var alen = arg.length;
        var clen = document.cookie.length;
        var i = 0;
        while (i < clen) {
            var j = i + alen;
            if (document.cookie.substring(i, j) == arg) {
                return Cookie.getValue(j);
            }
            i = document.cookie.indexOf(" ", i) + 1;
            if (i == 0) break; 
        }
        return null;
    },
    remove: function(name,path,domain) {
        if (Cookie.get(name)) {
            document.cookie = name + "=" + ((path) ? "; path=" + path : "") + ((domain) ? "; domain=" + domain : "") + "; expires=Thu, 01-Jan-70 00:00:01 GMT";
        }
    }
});

var UserCookie = function(){};
var UserCookieChange = false;
Object.extend(UserCookie, {
    data: new Hash(),
    init: function() {
        UserCookie.getCookie();
        UserCookie.timezone();
        //Event.observe(window, 'unload', function() {UserCookie.setCookie();});
    },
    setCookie: function() {
        var str = (UserCookie.data).toQueryString();
        str = str.substring(0,244);
        Cookie.set(_usercookies_, str, 0, _basepath_);
    },
    getCookie: function() {
        var cook = (Cookie.get(_usercookies_));
        if (cook) cook = cook.toQueryParams();
        (UserCookie.data).update(cook);
    },
    set: function(key,val) {
        (UserCookie.data).set(key,val);
        UserCookie.setCookie();
    },
    get: function(key) {
        return (UserCookie.data).get(key); 
    },
    unset: function(key) {
        return UserCookie.data.unset(key);
    },
    setIn: function(key,val) {
        var ret = UserCookie.getIn(key);
        ret.push(val); ret.compact(); ret.uniq();
        UserCookie.set(key, ret.join('#'));
        return ret;
    },
    getIn: function(key) {
        var val = UserCookie.get(key);
        if (val && val.split) return val.split('#');
        return [];
    },
    isLogin: function() {
        var ret = (UserCookie.data).get('u');
        if (ret && (ret.length > 1)) {
            return true;
        } 
        return false;
    },
    timezone: function() {
        var isTZ =  UserCookie.get('TZ');
        if (!isTZ) {
            var dt = new Date();
            if (dt.getTimezoneOffset) {
                UserCookie.set('TZ',dt.getTimezoneOffset());
            } else {
                UserCookie.set('TZ',dt.getTime());
            }
        }
    }
});
UserCookie.init();

var XMLDoc = function(){};
Object.extend(XMLDoc, {
        trim: function(nodes) {
            if (document.all) return nodes;
            if (!document.removeChild) return nodes;
            if (!document.replaceChild) return nodes;
            //
            nodes = nodes || document;
            var cur = nodes.firstChild;
            while (cur && cur.nodeType) {
                if (cur.nodeType == document.TEXT_NODE && ! /\S/.test(cur.nodeValue)) {
                    nodes.removeChild(cur);
                } else if (cur.nodeType == document.ELEMENT_NODE) {
                    var childCur = XMLDoc.trim(cur);
                    nodes.replaceChild(childCur, cur);
                }
                cur = cur.nextSibling
            }
            return nodes;
        },
        getNodesByAttribute: function(nodes) {
            var retval = [];
            var oChild = nodes.firstChild;
            while (oChild && oChild.nodeType) {
                if (oChild.nodeType == document.ELEMENT_NODE) {
                    if (oChild.getAttribute(attrName) == attrValue) {
                        retval.push(oChild);
                    }
                }
                oChild = oChild.nextSibling;
            }
            return retval;
        }
});


Date.prototype.getDayOfYear = function() {
    var firstyear = new Date(this.getFullYear(),0,1);
    return Math.ceil((this - firstyear) / 86400000);
}
Date.prototype.getWeekOfYear = function() {
    var firstyear = new Date(this.getFullYear(),0,1);
    return Math.ceil((((this - firstyear) / 86400000) + firstyear.getDay())/7);
}
Date.prototype.getWeekOfMonth = function() {
    return Math.ceil((this.getDate() + (6 - this.getDay())) /7);
}
var DateFormat = Class.create({
        defaultLang: 'en',
        defaultFormat: '%m/%d/%Y',
        property: {
            lang: 'en',
            utc: false,
            format: '%m/%d/%Y',
            months: [],
            monthsAbbr: [],
            days: [],
            daysAbbr: []
        },
        initialize: function(property) {
            property = $H(property);
            var lang = property.get('lang');
            if (!lang) {
                lang = this.defaultLang
            } else if (DateLang.indexOf(lang) < 0) {
                DateLang.Populate(property);
            }
            this.oDate = null;
            this.hDate = null;
            this.property.lang = lang;
            this.property.utc = property.get('utc') || false;
            this.property.format = property.get('format') || DateLang[lang][1];
            this.defaultFormat = property.get('format') || DateLang[lang][1];
            this.property.months = property.get('months') || DateLang[lang][2];
            this.property.monthsAbbr = property.get('monthsAbbr') || DateLang[lang][3];
            this.property.days = property.get('days') || DateLang[lang][4];
            this.property.daysAbbr = property.get('daysAbbr') || DateLang[lang][5];
        },
        valid: function(val, format) {
            return
        },
        compare: function(options1,options2) {
            return;
        },
        toFormat: function(format) {
            if (!this.oDate) this.setDate();
            format = format ? format : this.property.format;   
            var rep = '', place = '', that=this;
            var str = format;
            format.scan(/%[a-zA-Z%]/, function(match){
                    rep = that.formatCallback(match[0]);
                    place = new RegExp(match[0]);
                    str = str.replace(place, rep);
            });
            return str;
        },
        getDate: function(options, format) {
            this.setDate(options);
            return this.toFormat(format);
        },
        setUTC: function(utc) {
            return this.property.utc = ((utc===false || utc==0) ? false : true);
        },
        setDate: function(options, retval) {
            if (!options && this.hDate) return;
            var op = $H(options);
            if (op.get('hour')) op.set('hours', op.get('hour'));
            if (op.get('minute')) op.set('minutes', op.get('minute'));
            if (op.get('second')) op.set('seconds', op.get('second'));
            
            var oD = new Date();
            var oT = false;
            if (op.get('format')) {
                this.property.format = op.get('format');
            }
            if (op.get('time') && op.get('time') > 0) {
                oD.setTime(op.get('time'));
                oT = true;
            } else {
                op.set('time', oD.getTime());
            }
            if (op.get('year') && op.get('year') > 0) {
                oD.setFullYear(op.get('year'));
            } else {
                op.set('year', oD.getFullYear());
            }
            if (op.get('month') && op.get('month') > 0) {
                oD.setMonth(this.unTZ(op.get('month')) -1);
            }
            op.set('month', oD.getMonth());
            
            if (op.get('date') && op.get('date') > 0) {
                oD.setDate(op.get('date'));
            } else {
                op.set('date', oD.getDate());
            }
            if (op.get('hours') && op.get('hours') > 0) {
                oD.setHours(this.unTZ(op.get('hours')));
            } else {
                op.set('hours', oD.getHours());
            }
            if (op.get('minutes') && op.get('minutes') > 0) {
                oD.setMinutes(this.unTZ(op.get('minutes')));
            } else {
                op.set('minutes', oD.getMinutes());
            }
            if (op.get('seconds') && op.get('seconds') > 0) {
                oD.setSeconds(this.unTZ(op.get('seconds')));
            } else {
                op.set('seconds', oD.getSeconds());
            }
            if (op.get('milliseconds') && op.get('milliseconds') > 0) {
                oD.setMilliseconds(this.unTZ(op.get('milliseconds')));
            } else {
                op.set('milliseconds', oD.getMilliseconds());
            }
            op.set('dayofweek', oD.getDay());
            this.oDate = oD;
            this.hDate = op;

            if (retval=='hash') return op;
            else if (retval=='object') return oD;
            else return;
        },
        toLocaleDateString: function(options) {
            this.setDate(options);
            //default javascript Date.toLocaleDateString
            return this.oDate.toLocaleDateString();
        },
        toString: function(options) {
            this.setDate(options);
            //default javascript Date.toString
            return this.oDate.toString();
        },
        toJSON: function(options) {
            this.setDate(options);
            //required prototype 1.6.0.2 or higher
            return this.oDate.toJSON();
        },
        toObject: function(options) {
            this.setDate(options);
            return this.oDate;
        },
        toDate: function(val,format) {
            return
        },
        formatCallback: function(x) {
            var oD = this.oDate;
            var tP = this.property;
            var utc = tP.utc && tP.utc===true ? true : false;
            if (!oD) return x;
            
            switch(x) {
                case '%a' :
                    return (utc ? tP.daysAbbr[oD.getUTCDay()] : tP.daysAbbr[oD.getDay()]);
                case '%A' :
                    return (utc ? tP.days[oD.getUTCDay()] : tP.days[oD.getDay()]);
                case '%b' : case '%h' :
                    return (utc ? tP.monthsAbbr[oD.getUTCMonth()] : tP.monthsAbbr[oD.getMonth()]);
                case '%B' :
                    return (utc ? tP.months[oD.getUTCMonth()] : tP.months[oD.getMonth()]);
                case '%d' :
                    return this.TZ(utc ? oD.getUTCDate() : oD.getDate());
                case '%e' :
                    return (utc ? oD.getUTCDate() : oD.getDate());
                case '%F' :
                    return oD.getWeekOfMonth();
                case '%H' :
                    return this.TZ(utc ? oD.getUTCHours() : oD.getHours());
                case '%I' : case '%p' :
                    var h = (utc ? oD.getUTCHours() : oD.getHours());
                    if (x=='%p') return (h >= 12 ? 'PM' : 'AM');
                    var hMod = this.TZ(h % 12);
                    if (hMod == '00') hMod = 12;
                    return hMod;
                case '%j' :
                    return oD.getDayOfYear();
                case '%m' :
                    return this.TZ(utc ? oD.getUTCMonth() + 1 : oD.getMonth() + 1);
                case '%M' :
                    return this.TZ(utc ? oD.getUTCMinutes() : oD.getMinutes());
                case '%n' :
                    return '<br />';
                case '%S' :
                    return this.TZ(utc ? oD.getUTCSeconds() : oD.getSeconds());
                case '%u' : case '%w' :
                    var d = (utc ? oD.getUTCDay() : oD.getDay());
                    if (x=='%u' && d==0) d=7;
                    return d;
                case '%U' : case '%W' : case '%V' :
                    if (x=='%U') return oD.getWeekOfYear() - 1;
                    return oD.getWeekOfYear();
                case '%y' : case '%Y' : case '%G' : case '%C' : case '%g' :
                    var y = (utc ? oD.getUTCFullYear() : oD.getFullYear()) + "";
                    if (x==='%y' || x==='%g') return y.substr(2,2);
                    if (x=='%C') return this.TZ(Math.ceil(y/100) + "");
                    return y;
                case '%Z' :
                    var s = (oD.toString()).split(':');
                    var s = (oD.toString().split(':'));
                    if (s[2]) {
                        s = s[2].split(' ');
                        s = s[1] ? s[1] : false; 
                    } else {
                        s = false;
                    }
                    return (s ? s : 'TZ:' + oD.getTimezoneOffset());
                case '%z' :
                    return oD.getTimezoneOffset();
                case '%%' :
                    return '&#37;';
                default :
                    return x;
            }
        },
        populate: function(property) {
            return DateLang.Populate(property.get('lang'), 
                (property.get('format') || DateLang[this.defaultLang][1]), 
                (property.get('months') || DateLang[this.defaultLang][2]), 
                (property.get('monthsAbbr') || DateLang[this.defaultLang][3]), 
                (property.get('days') || DateLang[this.defaultLang][4]), 
                (property.get('daysAbbr') || DateLang[this.defaultLang][5]));
        },
        TZ: function(x) {
            return(x<0||x>9?"":"0")+x;
        },
        unTZ: function(x) {
            return parseInt(x);
        }
});

var DateLang = new Array();
DateLang.Populate = function(lang, defaultFormat, arrayMonths, arrayMonthsAbbr, arrayDays, arrayDaysAbbr) {
    DateLang[lang] = DateLang.Populate.arguments;
};

DateLang.Populate('en', 
    '%m/%d/%Y',
    ['January','February','March','April','May','June','July','August','September','October','November','December'],
    ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
    ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
    ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']);
DateLang.Populate('id', 
    '%d/%m/%Y',
    ['Januari','Februari','Maret','April','Mei','Juni','Juli','Agustus','September','Oktober','November','Desember'],
    ['Jan','Feb','Mar','Apr','Mei','Jun','Jul','Agu','Sep','Okt','Nov','Des'],
    ['Minggu','Senin','Selasa','Rabu','Kamis','Jumat','Sabtu'],
    ['Ming','Sen','Sel','Rab','Kam','Jum','Sab']);

_general_ = _protoculousG_;

function getObjElement(obj) {
    return $(obj);
}

/** 
 * author: Antonio Ramirez http://webeaters.blogspot.com
**/

var AutoComplete = Class.create();

AutoComplete.prototype = {
    Version: '1.3.0', 
    REQUIRED_PROTOTYPE: '1.6.0',
    initialize: function (id, param) {
        this.fld = $(id);
        if (!this.fld) 
            throw("AutoComplete requires a field id to initialize");
        this.sInp 	= "";
        this.nInpC 	= 0;
        this.aSug 	= [];
        this.iHigh 	= 0;
        this.options = param ? param : {};
        var k, def = {valueSep:null, minchars:1,meth:"get",varname:"input",className:"autocomplete",timeout:3000,delay:500,offsety:-5,shownoresults: true,noresults: "No results were found.",maxheight: 250,cache: true,maxentries: 25,onAjaxError:null,setWidth: false,minWidth: 100,maxWidth: 200,useNotifier: true};
        for (k in def) {
            if (typeof(this.options[k]) != typeof(def[k]))
                this.options[k] = def[k];
        }
        if (this.options.useNotifier) {
            this.fld.addClassName('ac_field');
        }
        var p = this;
        this.fld.onkeypress 	= function(ev){ return p.onKeyPress(ev); };
        this.fld.onkeyup      = function(ev){ return p.onKeyUp(ev); };
        this.fld.onblur			  = function(ev){ p.resetTimeout(); return true; };
        this.fld.setAttribute("AutoComplete","off");
        },
        convertVersionString: function (versionString) {
            var r = versionString.split('.');
            return parseInt(r[0])*100000 + parseInt(r[1])*1000 + parseInt(r[2]);
        },
        PROTOTYPE_CHECK: function() {
            if((typeof Prototype=='undefined') || (typeof Element == 'undefined'))
                throw("AutoComplete requires the Prototype JavaScript framework >= " + this.REQUIRED_PROTOTYPE);
        },
        onKeyPress: function (e) {
            if (!e) e = window.event;
            var key	= e.keyCode || e.wich;
            switch(key) {
            case Event.KEY_RETURN:
                this.setHighlightedValue();
                Event.stop(e);
                break;
            case Event.KEY_TAB:
                this.setHighlightedValue();
                //Event.stop(e);
                break;
            case Event.KEY_ESC:
                this.clearSuggestions();
                break;
            }
            return true;
        },
        onKeyUp: function (e) {
            if (!e) e = window.event;
            var key = e.keyCode || e.wich;
            if (key == Event.KEY_UP || key == Event.KEY_DOWN) {
                this.changeHighlight(key);
                Event.stop(e);
            } else this.getSuggestions(this.fld.value);
            return true;
        },
        getSuggestions: function(val) {
            if(val==this.sInp) return false;
            if($(this.acID)) $(this.acID).remove();
            this.sInp = val;
            if (val.length < this.options.minchars) {
                this.aSug 	= [];
                this.nInpC	= val.length;
                return false;
            }
            var ol	= this.nInpC;
            this.nInpC	= val.length ? val.length : 0;
            var l = this.aSug.length;
            if( this.options.cache && ( this.nInpC > ol ) && l && ( l < this.options.maxentries ) ) {
                var arr = new Array();
                for (var i=0;i<l;i++) {
                    if (this.aSug[i].value.toLowerCase().indexOf(val.toLowerCase()) != -1) {
                        arr.push(this.aSug[i]);
                    }
                }
                this.aSug = arr;
                this.createList(this.aSug);
            } else {
                var p = this;
                clearTimeout(this.ajID);
                this.ajID = setTimeout( function () {p.doAjaxRequest(p.sInp)}, this.options.delay);
            }
            document.helper = this;
            return false;
        },
        getLastInput : function(str) {
            var ret = str;
            if (undefined != this.options.valueSep) {
                var idx = ret.lastIndexOf(this.options.valueSep);
                ret = idx == -1 ? ret : ret.substring(idx + 1, ret.length);
            }
            return ret;
        },
        doAjaxRequest: function (input) {
            if (input != this.fld.value)
                return false;
            this.sInp = this.getLastInput(this.sInp);
            if (typeof this.options.script == 'function')
                var url = this.options.script(encodeURIComponent(this.sInp));
            else
                var url = this.options.script+this.options.varname+'='+encodeURIComponent(this.sInp);
            
            if(!url) return false;
            var p = this;
            var m = this.options.meth;  // get or post?
            if( this.options.useNotifier ) {
                this.fld.removeClassName('ac_field');
                this.fld.addClassName('ac_field_busy');
            };
            var options = {
                method: m,
                onSuccess: function (req) {
                    if( p.options.useNotifier ) {
                        p.fld.removeClassName('ac_field_busy');
                        p.fld.addClassName('ac_field');
                    };
                    p.setSuggestions(req,input);
                },
                onFailure: (typeof p.options.onAjaxError == 'function')? function (status) {
                    if (p.options.useNotifier) {
                        p.fld.removeClassName('ac_field_busy');
                        p.fld.addClassName('ac_field');
                    }
                    p.options.onAjaxError(status)
                } :
                function (status) {
                    if (p.options.useNotifier) {
                        p.fld.removeClassName('ac_field_busy');
                        p.fld.addClassName('ac_field');
                    }
                    alert("AJAX error: "+status);
                }
            }
            // make new ajax request
            new Ajax.Request(url, options);
        },
        setSuggestions: function (req, input) {
            if (input != this.fld.value)
                return false;
            this.aSug = [];
            if(this.options.json) {
                var jsondata = eval('(' + req.responseText + ')');
                this.aSug = jsondata.results;
            } else {
                var results = req.responseXML.getElementsByTagName('results')[0].childNodes;
                for(var i=0;i<results.length;i++) {
                    if(results[i].hasChildNodes())
                        this.aSug.push(  { 'id':results[i].getAttribute('id'), 'value':results[i].childNodes[0].nodeValue, 'info':results[i].getAttribute('info') }  );
                }
            }
            this.acID = 'ac_'+this.fld.id;
            this.createList(this.aSug);
        },
        createDOMElement: function ( type, attr, cont, html ) {
            var ne = document.createElement( type );
            if (!ne)
                return 0;
            
            for (var a in attr)
                ne[a] = attr[a];
            var t = typeof(cont);
            if (t == "string" && !html)
                ne.appendChild( document.createTextNode(cont) );
            else if (t == "string" && html)
                ne.innerHTML = cont;
            else if (t == "object")
                ne.appendChild( cont );
            return ne;
        },
        createList:	function(arr) {
            if($(this.acID)) $(this.acID).remove();
            this.killTimeout();
            if (arr.length == 0 && !this.options.shownoresults) return false;
            var div	= this.createDOMElement('div', {id:this.acID, className:this.options.className});
            var hcorner = this.createDOMElement('div', {className: 'ac_corner'});
            var hbar	= this.createDOMElement('div', {className: 'ac_bar'});
            var header	= this.createDOMElement('div', {className: 'ac_header'});
            header.appendChild(hcorner);
            header.appendChild(hbar);
            div.appendChild(header);
            var ul	= this.createDOMElement('ul', {id:'ac_ul'});
            var p 	= this; // pointer that we will need later on
            // no results?
            if (arr.length == 0 && this.options.shownoresults) {
                var li = this.createDOMElement('li', {className: 'ac_warning'}, this.options.noresults );
                ul.appendChild(li);
            } else {
                // loop through arr of suggestions creating an LI element for each of them
                for (var i=0,l = arr.length; i<l; i++) {
                    var val 	= arr[i].value;
                    var st 		= val.toLowerCase().indexOf(this.sInp.toLowerCase()); // HERE WE CHECK AGAINST THE SPLITTED VALUE IF ANY***
                    var output 	= val.substring(0,st) + '<em>' + val.substring(st,st+this.sInp.length) + '</em>' + val.substring(st+this.sInp.length);
                    var span	= this.createDOMElement('span',{},output,true); // type of, properties, output, isHTML?
                    if(arr[i].info != '') {
                        var br	= this.createDOMElement('br',{});
                        span.appendChild(br);
                        var small = this.createDOMElement('small',{}, arr[i].info);
                        span.appendChild(small);
                    }
                    var a 	= this.createDOMElement('a',{href:'#'});
                    var tl	= this.createDOMElement('span',{className:'tl'},'&nbsp;',true);
                    var tr	= this.createDOMElement('span',{className:'tr'},'&nbsp;',true);
                    a.appendChild(tl); a.appendChild(tr); a.appendChild(span);
                    a.name = i+1;
                    a.onclick = function () {p.setHighlightedValue();return false;};
                    a.onmouseover = function () {p.setHighlight(this.name);};
                    var li = this.createDOMElement('li', {}, a);
                    ul.appendChild(li);
                }
            }
            div.appendChild(ul); // add the newly created list to the div element
            var fcorner = this.createDOMElement('div', {className: 'ac_corner'});
            var fbar	= this.createDOMElement('div', {className: 'ac_bar'});
            var footer	= this.createDOMElement('div', {className: 'ac_footer'});
            footer.appendChild(fcorner);
            footer.appendChild(fbar);
            div.appendChild(footer);
            
            var pos         = this.fld.cumulativeOffset();
            div.style.left 	= pos[0] + "px";
            div.style.top 	= pos[1] + this.fld.offsetHeight + "px";
            var w =  (this.options.setWidth && this.fld.offsetWidth < this.options.minWidth) ? this.options.minWidth : (this.options.setWidth && this.fld.offsetWidth > this.options.maxWidth) ? this.options.maxWidth : this.fld.offsetWidth;
            div.style.width 	= w + "px";
            
            div.onmouseover 	= function(){ p.killTimeout() };
            div.onmouseout 		= function(){ p.resetTimeout() };
            document.getElementsByTagName("body")[0].appendChild(div);
            
            this.iHigh = 1;
            this.setHighlight(1);
            this.toID	= setTimeout(function () {p.clearSuggestions()}, this.options.timeout);
        },
        changeHighlight:	function(key) {
            var list = $("ac_ul");
            if (!list) return false;
            var n;
            n = (key == Event.KEY_DOWN || key == Event.KEY_TAB)? this.iHigh + 1 : this.iHigh - 1; // false assumed to be Event.KEY_UP
            n = (n > list.childNodes.length)? list.childNodes.length : ((n < 1)? 1 : n);
            this.setHighlight(n);
        },
        setHighlight:		function(n) {
            var list = $('ac_ul');
            if (!list) return false;
            if (this.iHigh > 0) this.clearHighlight();
            this.iHigh = Number(n);
            list.childNodes[this.iHigh-1].className = 'ac_highlight';
            this.killTimeout();
        },
        clearHighlight:	function() {
            var list = $('ac_ul');
            if(!list) return false;
            if(this.iHigh > 0) {
                list.childNodes[this.iHigh-1].className = '';
                this.iHigh = 0;
            }
        },
        setHighlightedValue:	function() {
            if (this.iHigh) {
                if (!this.aSug[this.iHigh - 1]) return;
                if (undefined != this.options.valueSep) {
                    var str = this.getLastInput(this.fld.value);
                    var idx = this.fld.value.lastIndexOf(str);
                    str = this.aSug[ this.iHigh -1 ].value + this.options.valueSep;
                    this.sInp = this.fld.value = idx == -1 ? str : this.fld.value.substring(0, idx) + str;
                } else {
                    var str = this.getLastInput(this.fld.value);
                    var idx = this.fld.value.lastIndexOf(str);
                    str = this.aSug[ this.iHigh -1 ].value;
                    this.sInp = this.fld.value = idx == -1 ? str : this.fld.value.substring(0, idx) + str;
                }
                this.fld.focus();
                if(this.fld.selectionStart)
                    this.fld.setSelectionRange(this.sInp.length, this.sInp.length);
                
                this.clearSuggestions();
                if (typeof this.options.callback == 'function')
                    this.options.callback(this.aSug[this.iHigh-1]);
            }
        },
        killTimeout:	function() {
            clearTimeout(this.toID);
        },
        resetTimeout:	function() {
            this.killTimeout();
            var p = this;
            this.toID = setTimeout(function () {p.clearSuggestions();}, p.options.timeout);
        },
        clearSuggestions:	function () {
            if ($(this.acID)) {
                this.fadeOut(300,function () {$(this.acID).remove();} );
            }
        },
        fadeOut:	function (milliseconds, callback) {
            this._fadeFrom 	= 1;
            this._fadeTo	= 0;
            this._afterUpdateInternal = callback;
            
            this._fadeDuration	= milliseconds;
            this._fadeInterval = 50;
            this._fadeTime = 0;
            var p = this;
            this._fadeIntervalID = setInterval(function() {p._changeOpacity()}, this._fadeInterval);
        },
        _changeOpacity: function() {
            if (!$(this.acID)) {
                this._fadeIntervalID=clearInterval(this._fadeIntervalID);
                return;
            }
            this._fadeTime += this._fadeInterval;
            
            var ieop = Math.round( (this._fadeFrom + ((this._fadeTo - this._fadeFrom) * (this._fadeTime/this._fadeDuration))) * 100)
            var op = ieop / 100;
            var el = $(this.acID);
            if (el.filters) {
                try {el.filters.item("DXImageTransform.Microsoft.Alpha").opacity = ieop;} catch (e) {el.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity='+ieop+')';}
            } else	{
                el.style.opacity = op;
            }
            if (this._fadeTime >= this._fadeDuration) {
                clearInterval( this._fadeIntervalID );
                if (typeof this._afterUpdateInternal == 'function')
                    this._afterUpdateInternal();
            }
        }
}
