var jaTooltip = function(options) {
    this.options = MochiKit.Base.update({ cache: true }, options);

    this.element = MochiKit.DOM.$(this.options.element);
    if(!this.element) {
        throw "element not found: " + this.options.element;
    }

    this.element.jatooltip = this;
    jaTooltip.tooltips.push(this);

    var tts = MochiKit.DOM.$(jaTooltip.tts_id);
    if(!tts) {
        tts = MochiKit.DOM.DIV();
        tts.id = "__jatts";
        document.body.appendChild(tts);
    }

    if(this.options.tooltip) {
        this.tooltip = MochiKit.DOM.$(this.options.tooltip);
        if(!this.tooltip) {
            throw "tooltip not found: " + this.options.tooltip;
        }
        tts.appendChild(this.tooltip);
        this.tooltip.style.position = "absolute";
        MochiKit.DOM.hideElement(this.tooltip);
    }

    if(this.options.ttFunc) {
        this.options.ttFunc = MochiKit.Base.bind(this.options.ttFunc, this);
    }

    if(this.options.jsonFunc) {
        this.options.jsonFunc = MochiKit.Base.bind(this.options.jsonFunc, this);
    }

    if(this.options.urlFunc) {
        this.options.urlFunc = MochiKit.Base.bind(this.options.urlFunc, this);
    }

    if(this.options.ajaxFunc) {
        this.options.ajaxFunc = MochiKit.Base.bind(this.options.ajaxFunc, this);
    }

    this.onMouseMoveCon = MochiKit.Signal.connect(this.element, 'onmousemove', this, this.onMouseMove);
    this.onMouseOutCon = MochiKit.Signal.connect(this.element, 'onmouseout', this, this.onMouseOut);
    this.onMouseOverCon = MochiKit.Signal.connect(this.element, 'onmouseover', this, this.onMouseOver);

};

jaTooltip.prototype = {
    hide: function() {
        if(this.ajaxD) {
            this.ajaxD.cancel();
            this.ajaxD = null;
        }
        if(this.tooltip) {
            MochiKit.DOM.hideElement(this.tooltip);
            if(!this.options.cache) {
                var tts = MochiKit.DOM.$(jaTooltip.tts_id);
                tts.removeChild(this.tooltip);
                this.tooltip = null;
            }
        }
        if(this.onDocMouseMoveCon) {
            MochiKit.Signal.disconnect(this.onDocMouseMoveCon);
            this.onDocMouseMoveCon = null;
        }
    },

    update: function(c) {
        if(this.tooltip) {
            MochiKit.DOM.setElementPosition(this.tooltip, c);
        }
    },

    show: function(c) {
        if(this.tooltip) {
            if(c) {
                this.update(c);
            }
            MochiKit.DOM.showElement(this.tooltip);
        }
    },

    dynamicShow: function(c) {
        if(!this.options.cache || !this.tooltip) {
            var tts = MochiKit.DOM.$(jaTooltip.tts_id);
            if(this.tooltip) {
                tts.removeChild(this.tooltip);
            }
            this.tooltip = MochiKit.DOM.$(this.options.ttFunc(this.element));
            tts.appendChild(this.tooltip);
            this.tooltip.style.position = "absolute";
        }

        this.show(c);
    },

    ajaxShow: function(m) {
        if(!this.options.cache || !this.tooltip) {
            if(this.ajaxD) {
                this.ajaxD.cancel();
            }

            this.ajaxD = MochiKit.Async.doSimpleXMLHttpRequest(this.options.url || this.options.urlFunc(this.element));
            this.ajaxD.addCallback(MochiKit.Base.bind(function(req) {
                var div;
                if(this.options.jsonFunc) {
                    div = MochiKit.DOM.$(this.options.jsonFunc(MochiKit.Async.evalJSONRequest(req)));
                } else if(this.options.ajaxFunc) {
                    div = MochiKit.DOM.$(this.options.ajaxFunc(req.responseText));
                } else {
                    div = MochiKit.DOM.DIV();
                    div.innerHTML = req.responseText;
                    if(div.childNodes.length == 1) {
                        div = div.firstChild;
                    }
                }
                var tts = MochiKit.DOM.$(jaTooltip.tts_id);
                tts.appendChild(div);
                div.style.position = "absolute";

                if(this.tooltip) {
                    tts.removeChild(this.tooltip);
                }
                this.tooltip = div;
                this.ajaxD = null;

                var c = this.getTTCoords(m);

                this.show(c);
            }, this));
        } else {
            var c = this.getTTCoords(m);
            this.show(c);
        }
    },

    getTTCoords: function(m) {
        var c = m.page;
        c.x += 5;
        c.y += 5;

        if(this.tooltip) {
            var cl = m.client;

            var ttdim = MochiKit.DOM.elementDimensions(this.tooltip);
            var vdim = MochiKit.DOM.getViewportDimensions();

            if(cl.x+ttdim.w > vdim.w) {
                c.x = c.x-ttdim.w-10;
                cl.x = cl.x-ttdim.w-10;
            }

            if(cl.y+ttdim.h > vdim.h) {
                c.y = c.y-ttdim.h-10;
                cl.y = cl.y-ttdim.h-10;
            }

            if(cl.x < 0) {
                c.x -= cl.x+5;
            }
            if(cl.y < 0) {
                c.y -= cl.y+5;
            }
        }

        return c;
    },

    onMouseOver: function(e) {
        if(!this.onDocMouseMoveCon) {
            this.onDocMouseMoveCon = MochiKit.Signal.connect(document, 'onmousemove', this, this.onDocMouseMove);
        }
        var c = this.getTTCoords(e.mouse());

        if(this.options.url || this.options.urlFunc) {
            this.ajaxShow(e.mouse());
        } else if(this.options.ttFunc) {
            this.dynamicShow(c);
        } else {
            this.show(c);
        }
    },

    onMouseOut: function(e) {
        this.hide();
    },

    onMouseMove: function(e) {
        var c = this.getTTCoords(e.mouse());
        this.update(c);
    },

    onDocMouseMove: function(e) {
        var element = e.target();
        var foundThis = false;
        while(element != document && !foundThis) {
            if(element == this.element) {
                foundThis = true;
            }
            element = element.parentNode;
        }
        if(!foundThis) {
            this.hide();
        }
    }

};


jaTooltip.tts_id = "__jatts";

jaTooltip.tooltips = [];

jaTooltip.initTooltips = function(elem_class, obj) {
    var func;
    if(typeof(obj) == "string") {
        func = function(element) {
            var ttid = element.id + obj;
            new jaTooltip({ element: element, tooltip: ttid}); 
        };
    } else if(typeof(obj) == "object") {
        func = function(element) {
            new jaTooltip(MochiKit.Base.update({ element: element }, obj));
        };
    } else {
    }
    var elements = MochiKit.DOM.getElementsByTagAndClassName(null, elem_class);
    MochiKit.Iter.forEach(elements, func);
};

