(function($){
    var tinge = {
        vars:{
            count: 0,
        pointers:{
        tl: 'M 0 10 L 0 0 L 10 10 Z',
        tm: 'M 0 10 L 5 0 L 10 10 Z',
        tr: 'M 0 10 L 10 0 L 10 10 Z',
        rt: 'M 0 0 L 10 0 L 0 10 Z',
        rm: 'M 0 0 L 10 5 L 0 10 Z',
        rb: 'M 0 0 L 10 10 L 0 10 Z',
        br: 'M 0 0 L 10 0 L 10 10 Z',
        bm: 'M 0 0 L 5 10 L 10 0 Z',
        bl: 'M 0 0 L 0 10 L 10 0 Z',
        lb: 'M 10 10 L 0 10 L 10 0 Z',
        lm: 'M 10 0 L 10 10 L 0 5 Z',
        lt: 'M 0 0 L 10 0 L 10 10 Z'
        }
        },
        config:{
            animation_speed: 500,
            pointer: 'tl',
            pointer_color: '#CCCCCC',
            pointer_size: 10,
            margin: 0,
            listener: 'hover',
            content: function(t,h){
                return h.attr('tinge');
            },
            show_delay: 500,
            hide_delay: 1000,
            refresh: false,
            disabled: false,
            solo: false,
            special_class: ''
        },
        html: '<div class="tinge" id=":tinge_id:"><div class="tinge_relative"><div class="tinge_pointer" id="pointer_:tinge_id:"></div><div class="tinge_content">:content:</div></div></div>',
        init: function(h, config){
            tinge.vars.count++;
            var c = $.extend(true, {}, tinge.config, config);
            c.id = 'tinge'+tinge.vars.count;
            h.addClass('tingeHandle'+tinge.vars.count).data('tingeActive_'+c.id, false);
            $('body').append(tinge.html.replace(/:tinge_id:/g, c.id).replace(/:content:/, c.content(t,h)));
        var t = $('#'+c.id);
            t.data('tingeActive', false).data('visible', false);
            if(c.special_class || false){
                t.addClass(c.special_class);
            }
            if(c.listener == 'show'){
                t.addClass('show_listener');
            }
        tinge.pointer(c);
        tinge.bind(t,h,c);
        },
    pointer: function(c){
        var paper = Raphael('pointer_'+c.id, c.pointer_size, c.pointer_size);
        var l = paper.path(tinge.vars.pointers[c.pointer]).attr('stroke', c.pointer_color).attr('stroke-width', 0).attr('fill', c.pointer_color);
    },
    bind: function(t,h,c){
        var startHideTimer = function(t,h,c){
        h.data('timeout_hide_'+c.id, setTimeout(function(t,h,c){return function(){tingeStatus(t,h,c,'hide');}}(t,h,c), c.hide_delay));
        }
        var startShowTimer = function(t,h,c){
        h.data('timeout_show_'+c.id, setTimeout(function(t,h,c){return function(){tingeStatus(t,h,c,'show');}}(t,h,c), c.show_delay));
        }
        var clearHideTimer = function(h,c){
        clearTimeout(h.data('timeout_hide_'+c.id));
        }
        var clearShowTimer = function(h,c){
        clearTimeout(h.data('timeout_show_'+c.id));
        }
            var showTinge = function(t,h,c){
                if(c.refresh == true){
                    t.find('.tinge_content').html(c.content(t,h));
                }
                if(c.solo == true){
                    var visible_tinges = $('.tinge.show_listener:visible');
                    t.data('visible_tinges', visible_tinges);
                    $('.tinge:visible').fadeOut(c.animation_speed);
                }
                var p = tinge.get_position(t,h,c);
                t.show().css('top', p.tinge_top).css('left', p.tinge_left).find('.tinge_pointer').css('top', p.pointer_top).css('left', p.pointer_left);
                t.animate({opacity: 0}, 0, function(){
                    t.animate({opacity: 1}, c.animation_speed);
                });
            }
            var hideTinge = function(t,h,c){
                t.fadeOut(c.animation_speed);
                if(c.solo == true){
                    var visible_tinges = t.data('visible_tinges');
                    if(visible_tinges || false){
                        visible_tinges.show().animate({opacity: 0}, 0, function(){
                            visible_tinges.animate({opacity: 1}, c.animation_speed);
                        });
                        t.data('visible_tinges', '');
                    }
                }
            }
            var tingeStatus = function(t,h,c,a){
                switch(a){
                    case 'show':
                        if(t.data('visible') == false){
                            t.data('visible', true);
                            showTinge(t,h,c);
                        }
                    break;
                    case 'hide':
                        if(t.data('visible') == true){
                            t.data('visible', false);
                            hideTinge(t,h,c);
                        }
                    break;
                }
            }
            switch(c.listener){
                case 'hover':
                    h.bind({
                        mouseenter: function(){
                            if(h.data('tingeActive_'+c.id) == false){
                                h.data('tingeActive_'+c.id, true);
                                clearHideTimer(h,c);
                startShowTimer(t,h,c);
                            }
                        },
                        mouseleave: function(){
                            if(h.data('tingeActive_'+c.id) == true){
                                h.data('tingeActive_'+c.id, false);
                                startHideTimer(t,h,c);
                                clearShowTimer(h,c);
                            }
                        }
                    });
            t.bind({
            mouseenter: function(){
                if(t.data('tingeActive') == false){
                t.data('tingeActive', true);
                                clearHideTimer(h,c);
                startShowTimer(t,h,c);
                }
            },
            mouseleave: function(){
                if(t.data('tingeActive') == true){
                t.data('tingeActive', false);
                startHideTimer(t,h,c);
                clearShowTimer(h,c);
                }
            }
            });
                break;
                case 'show':
                    showTinge(t,h,c);
                break;
                case 'focus':
                    h.bind({
                        focusin: function(){
                            if(h.data('tingeActive_'+c.id) != true){
                                h.data('tingeActive_'+c.id, true);
                                clearHideTimer(h,c);
                startShowTimer(t,h,c);
                            }
                        },
                        focusout: function(){
                            if(h.data('tingeActive_'+c.id) != false){
                                h.data('tingeActive_'+c.id, false);
                                startHideTimer(t,h,c);
                clearShowTimer(h,c);
                            }
                        }
                    });
                break;
        }
    },
    get_position: function(t,h,c){
        var hOffset = h.offset();
        var hWidth = h.outerWidth();
        var hHeight = h.outerHeight();
        var tWidth = t.outerWidth();
        var tHeight = t.outerHeight();
        var pWidth = c.pointer_size;
        var pHeight = c.pointer_size;
        var margin = c.margin;
        var tinge_top = 0;
        var tinge_left = 0;
        var pointer_top = 0;
        var pointer_left = 0;
        switch(c.pointer){
        default:
            alert('Position does not exist!');
        break;
        case 'tl':
            tinge_top = hOffset.top + hHeight + pHeight + margin;
            tinge_left = hOffset.left + hWidth + margin;
            pointer_top = pHeight * -1;
            pointer_left = 0;
        break;
        case 'tm':
            tinge_top = hOffset.top + hHeight + pHeight + margin;
            tinge_left = hOffset.left + hWidth / 2 - tWidth / 2;
            pointer_top = pHeight * -1;
            pointer_left = tWidth / 2 - pWidth / 2;
        break;
        case 'tr':
            tinge_top = hOffset.top + hHeight + pHeight + margin;
            tinge_left = hOffset.left - tWidth - margin;
            pointer_top = pHeight * -1;
            pointer_left = tWidth - pWidth;
        break;
        case 'rt':
            tinge_top = hOffset.top + hHeight + margin;
            tinge_left = hOffset.left - tWidth - pWidth - margin;
            pointer_top = 0;
            pointer_left = tWidth;
        break;
        case 'rm':
            tinge_top = hOffset.top + hHeight / 2 - tHeight / 2;
            tinge_left = hOffset.left - tWidth - pWidth - margin;
            pointer_top = tHeight / 2 - pHeight / 2;
            pointer_left = tWidth;
        break;
        case 'rb':
            tinge_top = hOffset.top - tHeight - margin;
            tinge_left = hOffset.left - tWidth - pWidth - margin;
            pointer_top = tHeight - pHeight;
            pointer_left = tWidth;
        break;
        case 'br':
            tinge_top = hOffset.top - tHeight - pHeight - margin;
            tinge_left = hOffset.left - tWidth - margin;
            pointer_top = tHeight;
            pointer_left = tWidth - pWidth;
        break;
        case 'bm':
            tinge_top = hOffset.top - tHeight - pHeight - margin;
            tinge_left = hOffset.left + hWidth / 2 - tWidth / 2;
            pointer_top = tHeight;
            pointer_left = tWidth / 2 - pWidth / 2;
        break;
        case 'bl':
            tinge_top = hOffset.top - tHeight - pHeight - margin;
            tinge_left = hOffset.left + hWidth + margin;
            pointer_top = tHeight;
            pointer_left = 0;
        break;
        case 'lb':
            tinge_top = hOffset.top - tHeight - margin;
            tinge_left = hOffset.left + hWidth + pWidth + margin;
            pointer_top = tHeight - pHeight;
            pointer_left = pWidth * -1;
        break;
        case 'lm':
            tinge_top = hOffset.top + hHeight / 2 - tHeight / 2;
            tinge_left = hOffset.left + hWidth + pWidth + margin;
            pointer_top = tHeight / 2 - pHeight / 2;
            pointer_left = pWidth * -1;
        break;
        case 'lt':
            tinge_top = hOffset.top + hHeight + margin;
            tinge_left = hOffset.left + hWidth + pWidth + margin;
            pointer_top = 0;
            pointer_left = pWidth * -1;
        break;
        }
        return {tinge_top: tinge_top, tinge_left: tinge_left, pointer_top: pointer_top, pointer_left: pointer_left};
    }
    };
    $.fn.tinge = function(config){
    var config = config || {};
        return this.each(function(){
            tinge.init($(this), config);
        });
    };
})(jQuery);

