// Merzia FX
// web2.0 javascript library
//   - utils
//   - ajax
//   - fading
//   - digg spy alike realtime events display
//   - balloon-style help boxes
//
// Copyright (C) 2007 Salvatore Sanfilippo (antirez at gmail dot com)
// Copyright (C) 2007 Merzia S.R.L.
// All Rights Reserved
//
// This library is released under the GPL version 2 license

/* =============================================================================
 * UTILS
 * ========================================================================== */

/* Just a less verbose way to getElementById() */
function $(id) {
    if (typeof(id) == 'string')
        return document.getElementById(id);
    return id;
}

/* Return the innerHTML of the element with ID 'id' */
function $html(id) {
    id=$(id);
    return id.getElementById(id).innerHTML;
}

/* Set the innerHTML of th element with ID 'id' */
function $sethtml(id,html) {
    id=$(id);
    id.innerHTML = html;
}

/* Append HTML to innerHTML of element with ID 'id' */
function $apphtml(id,html) {
    id=$(id);
    id.innerHTML += html;
}

/* Handy way to test if typeof(o) is 'undefined' */
function isdef(o) {
    return typeof(o) != 'undefined';
}

/* encodeURIComponent() working with IE5.0 */
function mfxEscape(s) {
    try {
        return encodeURIComponent(s);
    } catch(e) {
        var e = escape(s);
        e = e.replace(/@/g,"%40");
        e = e.replace(/\//g,"%2f");
        e = e.replace(/\+/g,"%2b");
        return e;
    }
}

/* decodeURIComponent() working with IE5.0 */
function mfxUnescape(s) {
    try {
        s = s.replace(/\+/g,"%20");
        return decodeURIComponent(s);
    } catch(e) {
        var s = unescape(s);
        s = s.replace(/\+/g," ");
        return s;
    }
}

/* mfxGetUrlParam("http://www.google.com?foo=bar","foo") => "bar" */
function mfxGetUrlParam(url,name) {
    var re="(&|\\?)"+name+"=([^&]*)";
    if (m = url.match(re)) return mfxUnescape(m[2]);
    return false;
}

/* Preform an action every N milliseconds */
function mfxEvery(milliseconds,handler) {
    if (handler() !== false)
        setTimeout(function() {
            mfxEvery(milliseconds,handler);
        },milliseconds);
}

function mfxGetElementsByClass(cname) {
    var el = document.getElementsByTagName('*');
    var res = [];
    for (var i = 0; i < el.length; i++) {
        var aux = ' '+el[i].className+' ';
        if (aux.indexOf(cname) != -1) {
            res[res.length] = el[i];
        }
    }
    return res;
}

function mfxSaveStyle(o,pname,defvalue) {
    o = $(o);
    if (!isdef(o.mfxSavedStyle)) o.mfxSavedStyle = {};
    var value = o.style[pname];
    if (!isdef(value)) value=defvalue;
    o.mfxSavedStyle[pname]=value;
}

function mfxRestoreStyle(o,pname) {
    o = $(o);
    if (!isdef(o.mfxSavedStyle) || !isdef(o.mfxSavedStyle[pname])) return;
    o.style[pname] = o.mfxSavedStyle[pname];
    delete o.mfxSavedStyle[pname];
}

function mfxMap(o,f) {
    var res = [];
    for(var i = 0; i < o.length; i++)
        res[res.length] = f(o[i]);
    return res;
}

/* =============================================================================
 * JSON
 * ========================================================================== */
function mfxJson(o) {
    if (typeof(o) == 'boolean') return String(o);
    if (typeof(o) == 'number') return String(o);
    if (typeof(o) == 'string') return mfxJsonString(o);
    if (typeof(o) == 'object') {
        if (o.constructor == Array) {
            return mfxJsonArray(o);
        } else {
            return mfxJsonObject(o);
        }
    }
    if (typeof(o) == 'undefined') return "undefined";
    return undefined;
}

/* The string to json conversion is taken from json.org */
function mfxJsonString(s) {
    if (typeof(s) != 'string') s = String(s);
    var m = {   '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f',
                '\r': '\\r', '"' : '\\"', '\\': '\\\\' };
    if (/["\\\x00-\x1f]/.test(s)) {
        return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
            var c = m[b];
            if (c) {
                return c;
            }
            c = b.charCodeAt();
            return '\\u00' +
                Math.floor(c / 16).toString(16) +
                (c % 16).toString(16);
        }) + '"';
    }
    return '"'+s+'"';
}

function mfxJsonArray(a) {
    var s = "[";
    for (var j = 0; j < a.length; j++) {
        s += mfxJson(a[j]);
        if (j != a.length-1) s += ",";
    }
    s += ']';
    return s;
}

function mfxJsonObject(o) {
    var s = "{";
    for (k in o) {
        s += k+":"+mfxJson(o[k])+",";
    }
    s += "}";
    s = s.replace(/,}$/,"}");
    return s;
}

/* =============================================================================
 * COOKIES
 * ========================================================================== */
function mfxSetCookie(name,value,expires,path,domain,secure)
{
    document.cookie= name + "=" + escape(value) +
        ((expires) ? "; expires=" + expires.toGMTString() : "") +
        ((path) ? "; path=" + path : "") +
        ((domain) ? "; domain=" + domain : "") +
        ((secure) ? "; secure" : "");
}

function mfxGetCookie(name)
{
    var dc = document.cookie;
    var prefix = name + "=";
    var begin = dc.indexOf("; " + prefix);
    if (begin == -1) {
        begin = dc.indexOf(prefix);
        if (begin != 0) return null;
    } else {
        begin += 2;
    }
    var end = document.cookie.indexOf(";", begin);
    if (end == -1) end = dc.length;
    return unescape(dc.substring(begin + prefix.length, end));
}

function mfxDelCookie(name,path,domain)
{
    if (mfxGetCookie(name)) {
        document.cookie = name + "=" + 
            ((path) ? "; path=" + path : "") +
            ((domain) ? "; domain=" + domain : "") +
            "; expires=Thu, 01-Jan-70 00:00:01 GMT";
    }
}

/* =============================================================================
 * FORMS
 * ========================================================================== */

function mfxGetInput(i) {
    i = $(i);
    if (isdef(i.type)) {
        if (i.type == 'text' || i.type == 'password') {
            return i.value;
        } else if (i.type == 'select-one') {
            return String(i.selectedIndex);
        } else if (i.type == 'checkbox') {
            if (i.checked == true) return "1";
            return "0";
        }
    }
}

function mfxSetInput(i,v) {
    i = $(i);
    if (isdef(i.type)) {
        if (i.type == 'text' || i.type == 'password') {
            i.value = v;
            if (typeof(i.onchange) == 'function') i.onchange();
        } else if (i.type == 'select-one') {
            i.selectedIndex = Number(v);
            if (typeof(i.onchange) == 'function') i.onchange();
        } else if (i.type == 'checkbox') {
            if ((Number(v) == true && i.checked == false) ||
                (Number(v) == false && i.checked == true))
            i.click();
        }
    }
}

function mfxSaveInputs(idlist) {
    var a = [];
    for (var i = 0; i < idlist.length; i++) {
        a[a.length] = idlist[i];
        a[a.length] = mfxGetInput(idlist[i]);
    }
    return a;
}

function mfxRestoreInputs(a) {
    for (var i = 0; i < a.length; i += 2)
        mfxSetInput(a[i],a[i+1]);
}

function mfxSaveInputsInString(idlist) {
    return mfxJson(mfxSaveInputs(idlist));
}

function mfxRestoreInputsFromString(s) {
    mfxRestoreInputs(eval(s));
}

function mfxSaveInputsInCookie(cookiename,idlist) {
    var s = mfxSaveInputsInString(idlist);
    mfxSetCookieDays(cookiename,s,1000);
}

function mfxSetCookieDays(name,val,days) {
    var now = new Date;
    var t = now.getTime();
    now.setTime(t+(3600*24*days*1000));
    mfxSetCookie(name,val,now,"/");
}

function mfxGetTime() {
    var now = new Date;
    return Math.floor(now.getTime()/1000);
}

function mfxRestoreInputsFromCookie(cookiename) {
    var c = mfxGetCookie(cookiename);
    if (c == null) return;
    mfxRestoreInputsFromString(c);
}

/* =============================================================================
 * BROWSER detection
 * ========================================================================== */

/* Browser detection is uncool, but sometimes to test
 * for features is impossible */
function mfxIsGecko() {
    if (mfxIsKonqueror()) return false;
    return navigator.userAgent.toLowerCase().indexOf("gecko") != -1;
}

function mfxIsExplorer() {
    if (isdef(window.opera)) return false;
    return navigator.userAgent.toLowerCase().indexOf("msie") != -1;
}

function mfxIsOpera() {
    return isdef(window.opera);
}

function mfxIsSafari() {
    return  isdef(navigator.vendor) &&
            navigator.vendor.toLowerCase().indexOf("apple") != -1;
}

function mfxIsKonqueror() {
    return  isdef(navigator.vendor) &&
            navigator.vendor.indexOf("KDE") != -1;
}

/* =============================================================================
 * AJAX
 * ========================================================================== */

/* Browser compatibilty.
 * Tested with:
 *
 * Firefox 1.0 to 1.5
 * Konqueror 3.4.2
 * Internet Explorer 5.0
 * internet Explorer 6.0
 * internet Explorer 7.0
 *
 * It should work also in Opera and Safari without troubles. */

// Create the XML HTTP request object. We try to be
// more cross-browser as possible.
function mfxCreateXmlHttpReq(handler) {
  var xmlhttp = null;
  try {
    xmlhttp = new XMLHttpRequest();
  } catch(e) {
    try {
        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch(e) {
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
  }
  xmlhttp.onreadystatechange = handler;
  return xmlhttp;
}

// An handler that does nothing, used for AJAX requests that
// don't require a reply and are non-critical about error conditions.
function mfxDummyHandler() {
    return true;
}

// Shortcut for creating a GET request and get the reply
// This few lines of code can make Ajax stuff much more trivial
// to write, and... to avoid patterns in programs is sane!
function mfxGet(url,handler) {
    var a = new Array("placeholder");
    for (var j=2; j<arguments.length; j++) {
        a[a.length] = arguments[j];
    }
    var ajax_req = mfxCreateXmlHttpReq(mfxDummyHandler);
    var myhandler = function() {
        var content = mfxAjaxOk(ajax_req);
        if (content !== false) {
            a[0] = content;
            try {
                return handler.apply(this, a);
            } catch(e) {
                return mfxApply(handler, a);
            }
        }
    }
    ajax_req.onreadystatechange = myhandler;
    ajax_req.open("GET",url);
    ajax_req.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8');
    ajax_req.send(null);
}

// IE 5.0 does not support the apply() method of the function object,
// we resort to this eval-based solution that sucks because it is not
// capable of preserving 'this' and is ugly as hell, but it works for us.
function mfxApply(funcname,args) {
    var e = "funcname(";
    for (var i = 0; i < args.length; i++) {
        e += "args["+i+"]";
        if (i+1 != args.length) {
            e += ",";
        }
    }
    e += ");"
    return eval(e);
}

// Add a random parameter to the get request to avoid
// IE caching madness.
function mfxGetRand(url,handler) {
    url += (url.indexOf("?") == -1) ? "?" : "&";
    url += "rand="+escape(Math.random());
    arguments[0] = url;
    try {
        return mfxGet.apply(this,arguments);
    } catch(e) {
        return mfxApply(mfxGet,arguments);
    }
}

function mfxAjaxOk(req) {
    if (req.readyState == 4 && req.status == 200) {
        return req.responseText;
    } else {
        return false;
    }
}

/* =============================================================================
 * POSITIONING
 * ========================================================================== */

function mfxGetElementSize(ele) {
    ele=$(ele);
    var o = {};
    if (isdef(ele.offsetHeight)) {
        /* IE ... */
        o.width = ele.offsetWidth;
        o.height = ele.offsetHeight;
    } else {
        /* W3C way, supported by Gecko */
        try {
            o.width = document.defaultView.getComputedStyle(ele,"").getPropertyValue("width");
            o.height = document.defaultView.getComputedStyle(ele,"").getPropertyValue("height");
        } catch(e) {
            o = false;
        }
    }
    return o;
}

/* INPUT -- e: the event object */
function mfxGetMousePos(e) {
    if (!e) e = window.event;
    var pos = {};
    if (isdef(e.pageX)) {
        pos.x = e.pageX;
        pos.y = e.pageY;
    } else {
        pos.x = e.clientX;
        pos.y = e.clientY;
    	pos.x += document.body.scrollLeft+document.documentElement.scrollLeft;
	pos.y += document.body.scrollTop+document.documentElement.scrollTop;
    }
    return pos;
}

function mfxMoveTo(e,x,y) {
    e=$(e);
    if (e.style.position != 'absolute')
        e.style.position = 'absolute';
    e.style.left = x+'px';
    e.style.top = y+'px';
}

function mfxDelete(e) {
    e=$(e);
    e.parentNode.removeChild(e);
}

function mfxFindPosition(e) {
    e = $(e);
    var curleft = curtop = 0;
    if (e.offsetParent) {
        curleft = e.offsetLeft
        curtop = e.offsetTop
        while (e = e.offsetParent) {
            curleft += e.offsetLeft
            curtop += e.offsetTop
        }
    }
    return {x: curleft, y: curtop};
}

/* =============================================================================
 * DRAG & DROP
 * ========================================================================== */
function mfxDragEnable(e) {
    e = $(e);
    e.mfxcandrag = true;
    e.onmousedown = mfxDragOrResizeStart;
}

function mfxDragDisable(e) {
    e = $(e);
    e.mfxcandrag = undefined;
    if (!isdef(e.mfxcanresize)) {
        /* We can disable the onmousedown event handler
           only if it is not used by the resize code */
        e.onmousedown = null;
    }
}

/* The onmousedown event is shared between drag&drop and resize features */
function mfxDragOrResizeStart(e) {
    var o = this;
    if (isdef(o.mfxcanresize)) {
        if (mfxResizeStart(e,o)) return false;
    }
    if (isdef(o.mfxcandrag)) {
        mfxDragStart(e,o);
    }
    return false;
}

function mfxDragStart(e,o) {
    /* Check if the object already has top/left, otherwise
     * try to find it and set it */
    var opos = {};
    opos.x = parseInt(o.style.left);
    opos.y = parseInt(o.style.top);
    if (isNaN(opos.x) || isNaN(opos.y)) {
        var realpos = mfxFindPosition(o);
        o.style.position = 'absolute';
        o.style.left = realpos.x+'px';
        o.style.top = realpos.y+'px';
    }
    /* Initialization stuff, the real work is done in mfxDragMove() */
    var pos = mfxGetMousePos(e);
    o.dragLastX = pos.x;
    o.dragLastY = pos.y;
    document.onmousemove = function(e) {
        mfxDragMove(e,o);
    };
    document.onmouseup = function(e) {
        mfxDragStop(e,o);
    }
    if (typeof(o.ondragstart) == 'function')
        o.ondragstart(e,o);
    mfxSaveStyle(o,'zIndex','0');
    o.style.zIndex = '1000';
}

function mfxDragMove(e,o) {
    var mpos = mfxGetMousePos(e);
    var opos = {};
    opos.x = parseInt(o.style.left);
    opos.y = parseInt(o.style.top);
    var dx = mpos.x-o.dragLastX;
    var dy = mpos.y-o.dragLastY;
    o.dragLastX = mpos.x;
    o.dragLastY = mpos.y;
    o.style.top = (opos.y+dy)+'px';
    o.style.left = (opos.x+dx)+'px';
    if (typeof(o.ondrag) == 'function')
        o.ondrag(o);
    return false;
}

function mfxDragStop(e,o) {
    document.onmousemove = null;
    document.onmouseup = null;
    if (typeof(o.ondragstop) == 'function')
        o.ondragstop(e,o);
    mfxRestoreStyle(o,'zIndex');
}

/* =============================================================================
 * RESIZE
 * ========================================================================== */
function mfxResizeEnable(e) {
    e = $(e);
    e.mfxcanresize = true;
    e.onmousedown = mfxDragOrResizeStart;
}

function mfxResizeDisable(e) {
    e = $(e);
    e.mfxcanresize = undefined;
    if (!isdef(e.mfxcandrag)) {
        /* We can disable the onmousedown event handler
           only if it is not used by the drag&drop code */
        e.onmousedown = null;
    }
}

function mfxResizeStart(e,o) {
    var mpos = mfxGetMousePos(e);
    var opos = mfxFindPosition(o);
    var osize = mfxGetElementSize(o);
    var corner = {x: opos.x+osize.width, y: opos.y+osize.height};
    var delta = 8;
    /* Check if the object is clicked in the right-bottom angle,
       otherwise return false. */
    if (mpos.x >= corner.x-delta && mpos.x <= corner.x &&
        mpos.y >= corner.y-delta && mpos.y <= corner.y) {
        /* Ok, setup the resize operation */
        o.resizeLastX = mpos.x;
        o.resizeLastY = mpos.y;
        o.resizeWidth = osize.width;
        o.resizeHeight = osize.height;
        document.onmousemove = function(e) {
            mfxResizeMove(e,o);
        };
        document.onmouseup = function(e) {
            mfxResizeStop(e,o);
        }
        if (typeof(o.onresizestart) == 'function')
            o.onresizestart(e,o);
        mfxSaveStyle(o,'zIndex','0');
        o.style.zIndex = '1000';
        return true;
    } else {
        return false;
    }
}

function mfxResizeMove(e,o) {
    var mpos = mfxGetMousePos(e);
    var dx = mpos.x-o.resizeLastX;
    var dy = mpos.y-o.resizeLastY;
    o.resizeLastX = mpos.x;
    o.resizeLastY = mpos.y;
    o.resizeWidth += dx;
    o.resizeHeight += dy;
    o.style.width = (o.resizeWidth)+'px';
    o.style.height = (o.resizeHeight)+'px';
    if (typeof(o.onresize) == 'function')
        o.onresize(o);
    return false;
}

function mfxResizeStop(e,o) {
    document.onmousemove = null;
    document.onmouseup = null;
    if (typeof(o.onresizestop) == 'function')
        o.onresizestop(e,o);
    mfxRestoreStyle(o,'zIndex');
}

/* =============================================================================
 * CLICKTIPS - balloon-style helps on click or hover
 * ========================================================================== */
function registerClicktip(e,_text) {
    e.clicktipActive = false;
    e.onclick = function (event) {
        if (!event) var event = window.event;
        return handleClicktip(event,_text,e);
    };
}

function registerClicktipId(id,text) {
    var e = document.getElementById(id);
    if (e) {
        registerClicktip(e,text);
    } else {
        alert("Clicktip error: no such element ID '"+id+"'");
    }
}

/* Set a clicktip to all the elements of a given type/class */
function registerClicktipBulk(type,classname,text) {
    if (isdef(document.getElementsByTagName)) {
        var e = document.getElementsByTagName(type);
        var i;
        for (i = 0; i < e.length; i++) {
            if (!classname || e[i].className == classname) {
                registerClicktip(e[i], text);
            }
        }
    }
}

function registerOvertip(e,_text,showdelay,hidedelay) {
    e.clicktipActive = false;
    e.clicktipTimeout = false;
    e.onmouseover = function (event) {
        if (!event) var event = window.event;
        return handleOvertipOver(e,event,_text,showdelay,hidedelay);
    };
    e.onmouseout = function (event) {
        if (!event) var event = window.event;
        return handleOvertipOut(e,event,_text,showdelay,hidedelay);
    };
}

function registerOvertipId(id,text,showdelay,hidedelay) {
    var e = document.getElementById(id);
    if (e) {
        registerOvertip(e,text,showdelay,hidedelay);
    } else {
        alert("Clicktip error: no such element ID '"+id+"'");
    }
}

/* Set an overtip to all the elements of a given type/class */
function registerOvertipBulk(type,classname,text,showdelay,hidedelay) {
    if (isdef(document.getElementsByTagName)) {
        var e = document.getElementsByTagName(type);
        var i;
        for (i = 0; i < e.length; i++) {
            if (!classname || e[i].className == classname) {
                registerOvertip(e[i],text,showdelay,hidedelay);
            }
        }
    }
}

function delTip(div) {
    try {
        try { clearTimeout(div.clicktipTarget.clicktipTimeout); } catch(e) {};
        try { div.clicktipTarget.clicktipTimeout = false; } catch(e) {};
        try { div.clicktipTarget.clicktipActive = false; } catch(e) {};
        document.body.removeChild(div);
        delete(div);
    } catch(e) {};
}

function delTipOnClick() {
    delTip(this);
}

function createTipDiv(x,y,text,target) {
    /* Show a DIV with the right message */
    var div = document.createElement('div');
    div.className = 'clicktip';
    div.style.visibility = 'hidden';
    div.style.position = 'absolute';
    div.style.left = x+"px";
    div.style.top = y+"px";
    /* We set the DIV content usign innerHTML,
       If you are a purist append a text node instead ;) */
    div.innerHTML = text;

    /* When the clicktip gets clicked we hide it */
    div.clicktipTarget = target;
    div.onclick = delTipOnClick;
    document.body.appendChild(div);

    /* Try to fix the 'top' in order to display the div just over the pointer */
    var divsize = mfxGetElementSize(div);
    div.clicktipXDelta = 0;
    div.clicktipYDelta = 0;
    if (divsize) {
        /* Check if there is space on top to display the clicktip */
        if (divsize.height < y) {
            div.clicktipYDelta = -(divsize.height+2);
            div.clicktipXDelta = 2;
        } else {
            div.clicktipXDelta = 2;
            /* No space on top, display the tip on the bottom, i.e.
               just don't alter the current position. */
        }
    }
    if (div.clicktipXDelta || div.clicktipYDelta) {
        div.style.top = (y+div.clicktipYDelta)+"px";
        div.style.left = (x+div.clicktipXDelta)+"px";
    }
    div.style.visibility = 'visible';
    return div;
}

function handleClicktip(e,text,target) {
    /* A clicktip is already on screen for this object? Return */
    if (target.clicktipActive) return false;
    target.clicktipActive = true;

    /* The target object have a tipclick attribute? Use it as text */
    if (target.getAttribute('clicktip')) text=target.getAttribute('clicktip');
    if (!text) return; /* No text attribute nor one specified on registration */

    /* Get the mouse position */
    var mouse = mfxGetMousePos(e);

    /* Create/show the tip div */
    var div = createTipDiv(mouse.x,mouse.y,text,target);

    /* Compute how long the clicktip should be shown */
    var milliseconds = 2000; /* base time */
    var textlen = text.length;

    /* Add one second for every 50 characters */
    while(textlen > 30) {
        milliseconds += 1000;
        textlen -= 30;
    }

    /* Register a timer to remove the DIV after few seconds */
    setTimeout(function() {
        try {
            target.clicktipActive = false;
            document.body.removeChild(div);
            delete(div);
        } catch(e) {};
    }, milliseconds);
    return false;
}

function handleOvertipOver(target,e,text,showdelay,hidedelay)
{
    var mouse = mfxGetMousePos(e);

    target.clicktipX = mouse.x;
    target.clicktipY = mouse.y;

    /* An overtip is already scheduled or shown for this object? Return */
    if (target.clicktipTimeout !== false || target.clicktipActive) return false;

    /* Otherwise start the timer that will display the TIP */
    target.clicktipTimeout = setTimeout(function() {
        showAfterDelay(target,text,showdelay,hidedelay);
    }, showdelay);
}

function handleOvertipOut(target,e,text,showdelay,hidedelay)
{
    /* Clicktip scheduled but not yet shown, delete the timer */
    if (target.clicktipTimeout !== false && !target.clicktipActive) {
        try {
            clearTimeout(target.clicktipTimeout);
        } catch(e) {};
        target.clicktipTimeout = false;
        return;
    }

    /* Tip shown, register a timer to remove it */
    if (target.clicktipActive) {
        target.clicktipTimeout = setTimeout(function() {
            hideAfterDelay(target);
        }, hidedelay);
    }
}

function showAfterDelay(target,text,showdelay,hidedelay)
{
    var div = createTipDiv(target.clicktipX,target.clicktipY,text,target);
    target.clicktipActive = true;
    target.clicktipDiv = div;
    if (showdelay == 0) {
        target.onmousemove = function(event) {
            if (!event) var event = window.event;
            var mouse = mfxGetMousePos(event);
            tipFollowMouse(mouse,this);
        };
    }
}

function hideAfterDelay(target)
{
    delTip(target.clicktipDiv);
}

function tipFollowMouse(mouse,target) {
    var div = target.clicktipDiv;
    div.style.top = mouse.y + div.clicktipYDelta;
    div.style.left = mouse.x + div.clicktipXDelta;
}

/* =============================================================================
 * EFFECTS
 * ========================================================================== */

// Set object opacity in a cross-browser fashion
function mfxSetOpacity(o,val) {
    if (val == 1) val= mfxIsGecko() ? '' : 0.9999;
    o.style.opacity = val;
    try {
        o.style.filter = 'alpha(opacity='+Math.floor(val*100)+')';
    } catch(e) {};
}

// Fade the object 'o' from sval opacity to tval opacity
// i.e. mfxFade(o,0,1) will fade in
//      mfxFade(o,1,0) will fade out
function mfxFade(o,sval,tval,steps,delay) {
    o.style.zoom = '1'; // IE requires this to be set to 1 to set opacity
    if (isdef(o.fade)) {
        try {clearTimeout(o.fade.timeout);} catch(e) {}
        current = o.fade.current;
    } else {
        mfxSetOpacity(o,sval);
        current = sval;
    }
    o.fade = {};
    o.fade.steps = isdef(steps) ? steps : 20;
    o.fade.delay = isdef(delay) ? delay : 50;
    o.fade.sval = sval;
    o.fade.tval = tval;
    o.fade.incr = (tval-sval)/o.fade.steps;
    o.fade.current = current;
    mfxFadeTimeout(o);
}

function mfxFadeTimeout(o) {
    o.fade.current += o.fade.incr;
    if(o.fade.current < 0) o.fade.current = 0;
    else if(o.fade.current > 1) o.fade.current = 1;
    mfxSetOpacity(o,o.fade.current);
    if ((o.fade.incr > 0 && o.fade.current < o.fade.tval) ||
        (o.fade.incr < 0 && o.fade.current > o.fade.tval)) {
        o.fade.timeout = 
            setTimeout(function() {mfxFadeTimeout(o);}, o.fade.delay);
    } else {
        if (isdef(o.onfadedone)) o.onfadedone(o);
        o.fade = undefined;
    }
}

function mfxSpydivPush(div,classname,html) {
    var fade = isdef(div.spyNoFade) ? 0 : 1;
    var ele = document.createElement('div');
    var maxlen = isdef(div.spyMaxLen) ? div.spyMaxLen : 10;
    ele.className = classname;
    ele.innerHTML = html;
    if (fade) mfxSetOpacity(ele,0);
    if (!isdef(div.spyLastEle)) {
        div.appendChild(ele);
        div.spyLen = 1;
    } else {
        div.insertBefore(ele,div.spyLastEle);
        div.spyLen++;
    }
    div.spyLastEle = ele;
    if (fade) mfxFade(ele,0,1);
    while (div.spyLen > maxlen) {
        var nodes = div.childNodes;
        var last, i=0;
        while(1) {
            i++;
            last = nodes[nodes.length-i];
            if (!isdef(last.spyRemoved)) break;
        }
        if (fade) {
            last.onfadedone = function(e) {
                div.removeChild(e);
            }
            last.spyRemoved = true;
            mfxFade(last,1,0,5,50);
        } else {
            div.removeChild(last);
        }
        div.spyLen--;
    }
    return ele;
}

function mfxSpydivClear(div,toleave) {
    toleave = isdef(toleave) ? toleave : 0;
    while (div.spyLen > toleave) {
        var nodes = div.childNodes;
        var last, i=0;
        while(1) {
            i++;
            if (i > nodes.length) return;
            last = nodes[nodes.length-i];
            if (!isdef(last.spyRemoved)) break;
        }
        if (div.spyLastEle == last) div.spyLastEle = undefined;
        div.removeChild(last);
        div.spyLen--;
    }
}

function mfxToggle(o) {
    o = $(o);
    if(!isdef(o.style.visibility) ||
       o.style.visibility=='' ||
       o.style.visibility=='visible') {
        mfxHide(o);
    } else {
        mfxShow(o);
    }
}

function mfxShow(o) {
    o = $(o);
    o.style.visibility = 'visible';
    o.style.display = 'block';
}

function mfxHide(o) {
    o = $(o);
    o.style.visibility = 'hidden';
    o.style.display = 'none';
}

function mfxHighlightForm(e) {
    e = $(e);
    e.style.background='#ffeeee';
    if (typeof(e.onclick) == 'undeifned') {
        e.onclick = function(event) {
            e.style.background='white';
        }
    }
}
/* Copyright(C) 2005-2007 Salvatore Sanfilippo <antirez@gmail.com>
 * All Rights Reserved. */

function validate(string, regexp, err, fieldName) {
    if (string.match(regexp) == null) {
        alert(err);
        warnField(fieldName);
        return false;
    }
    return true;
}
function validateEmpty(string,err,filedName) {
    return validate(string, "^.*[^ ]+.*$", err, filedName);
}
function isValidEmail(a)
{
    var at = a.indexOf("@");
    var name = a.substring(0, at);
    var isp = a.substring(at + 1, a.length);
    var dot = a.lastIndexOf(".");
    if (at == -1 || at == 0 || name == "" || isp == "" || dot == -1 ||
dot== (a.length - 1))
    {
        return false;
    }
    return true;
}
function warnField(fieldName)
{
    eval("document.f."+fieldName+".style.border='1px red solid'");
    eval("document.f."+fieldName+".focus();");
}
function clearFields(fields, hidelist) {
    for (i = 0; i < fields.length; i++) {
        eval("document.f."+fields[i]+".style.border='1px solid #aaa'");
    }
    if (hidelist != null) {
        for (i = 0; i < hidelist.length; i++) {
            mfxHide(hidelist[i]);
        }
    }
}
function areyousure(message) {
    return confirm(message + ": are you sure?");
}
function submitForm() {
	document.f.submit();
}
function registrationCheckUsername() {
    mfxGetRand("ajaxcheckusername.rhtml?username="+document.f.username.value,
    function(c) {
        if (c.indexOf("OK") != -1) {
            submitForm();
        } else {
            warnField('username');
            regErrUsername();
            enableButton();
        }
    });
}
function regErrUsername() {
    var text="L'username scelta e' gia esistente, provane un'altra.";
    regErr(text,"username");
}
function regErr(text,field){
   mfxShow('regerrdiv');
   $('regerrdiv').innerHTML=text;
   warnField(field);
}
function checkRegistrationForm() {
    disableButton();
    clearFields(new Array("username","password","repassword"), new Array("regerrdiv"));
    if (!validate(document.f.username.value, "^[A-z0-9]{3,10}$", "L'username non puo' essere meno di 3 o piu' di 10 caratteri e non puo' contenere caratteri speciali.","username")){
        enableButton();
        return false;
    }
    if (!validate(document.f.password.value, "^.{5,}$", "Password troppo corta, usa una password composta da 5 o piu' caratteri.","password")){
        enableButton();
        return false;
    }
    if (document.f.password.value != document.f.repassword.value) {
        alert("Le due password digitate devono essere identiche.");
        warnField("password");
        warnField("repassword");
        enableButton();
        return false;
    }
    registrationCheckUsername();
    return false;
}
function disableButton(){
    $("registerButton").disabled=true;
    $("registerButton").value="Prego attendere...";
	
}
function enableButton(){
    $("registerButton").disabled=false;
    $("registerButton").value="Crea il mio account!";
}
function openphoto(url,title) {
    openCenteredWindow(url,'600','800',title,'toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no');
}

function openCenteredWindow(url, height, width, name, parms) {
   var left = Math.floor( (screen.width - width) / 2);
   var top = Math.floor( (screen.height - height) / 2);
   var winParms = "top=" + top + ",left=" + left + ",height=" + height + ",width=" + width;
   if (parms) { winParms += "," + parms; }
   var win = window.open(url, name, winParms);
   if (parseInt(navigator.appVersion) >= 4) { win.window.focus(); }
   return win;
}

function ajaxvotefilm(result){

            if(document.getElementById('fieldfilmrating').value=='-2'){
                 HTML='La tua valutazione &egrave; stata registrata';
            }
            else if (document.getElementById('fieldfilmrating').value=='-1'){
                 HTML='Il film &egrave; stato aggiunto nella tua <a href="/filmlist/'+result+'?viewtype=wishlist">wishlist</a>';
            }
            else if (document.getElementById('fieldfilmrating').value=='0'){
                 HTML='Il film &egrave; stato rimosso dai tuoi film';
                 
            }
            else{
                 HTML='Il film &egrave; stato aggiunto a: <a href="/filmlist/'+result+'">i tuoi film</a>';           
            }
            if($('fieldfilmrating').options[0].value=='-' && document.getElementById('fieldfilmrating').value!='0')
                    $('fieldfilmrating').options[0].value='0';
            $('show').style.visibility='visible';
            $('votemsg').innerHTML=HTML;
        }

function updatecommentvote(result){
            //alert(result);
            var result_split = result.split(',');
            var id = result_split[0];
            var vote = result_split[1];
            var total = result_split[2];
            var user = result_split[3];
            var color = result_split[4];
            var arrowid,arrowcolor,newvote;
            switch(vote){
                case '1': newvote=0;arrowid='aup';arrowcolor='green-up';break;
                case '-1': newvote=0;arrowid='aud';arrowcolor='red-down';break;
                case '0': arrowid='aup';arrowcolor='gray-up';break;
            }
           $('aup'+id).src= '/images/arrowgray-up.gif'
           $('aud'+id).src= '/images/arrowgray-down.gif'
           $('aup'+id).onclick = function(){mfxGetRand('/ajaxvotecomment.rhtml?user_id='+user+'&comment_id='+id+'&vote=1',updatecommentvote)}
           $('aud'+id).onclick = function(){mfxGetRand('/ajaxvotecomment.rhtml?user_id='+user+'&comment_id='+id+'&vote=-1',updatecommentvote)}
           //alert(arrowid+id)
           $(arrowid+id).src = '/images/arrow'+arrowcolor+'.gif'
           $(arrowid+id).onclick = function(){mfxGetRand('/ajaxvotecomment.rhtml?user_id='+user+'&comment_id='+id+'&vote='+newvote,updatecommentvote)}
           if(vote=='0'){
                $('aud'+id).src = '/images/arrowgray-down.gif';
                $('aup'+id).onclick = function(){mfxGetRand('/ajaxvotecomment.rhtml?user_id='+user+'&comment_id='+id+'&vote=1',updatecommentvote)}
                $('aud'+id).onclick = function(){mfxGetRand('/ajaxvotecomment.rhtml?user_id='+user+'&comment_id='+id+'&vote=-1',updatecommentvote)}
           }     
           $('pts'+id).innerHTML='<b>'+total+' punti'+'</b>';
           $('pts'+id).style.color=color;
}
