
/**
 * Registr pozadavku na tooltip
 */
var TooltipRegistry = new (function(){
    
    this.db = new Array();
    
    this.register = function(obj) {
        this.db.push(obj);
    };
    
    this.peek = function(i) {
        return this.db[i];
    };
    
    this.get = function() {
        return this.db.shift();
    }
    
    this.size = function() {
        return this.db.length;
    };
    
})();

/**
 * Objekt pozadavku na zobrazeni tooltipu
 */
var TooltipRequest = function(params){
    this.object = null;
    this.trigger = 'click';
    this.defuser = '';
    this.timeout = 0;

    this.type = 'info';
    this.size = '';
    this.title = '';
    this.html = '';
    this.content = null;
    
    this.messages = new Array(3);
    
    this.init = function(params) {
        var _self = this;
        // pokud je zadano URL, pak nactu objekt
        // pomoci AJAXu
        if (params.url) {
            $.ajax({
                url: params.url,
                data: params.data,
                dataType: 'json',
                async: false,
                success: function(data){
                    _self.init(data);
                }
            });
        // pokud je zadana callback funkce, pak se
        // zavola ta
        } else if (params.callback) {
            this.init(params.callback(params.data));
        // ulozi parametry requestu
        } else {
            this.object = params.object;
            this.trigger = params.trigger;
            this.defuser = params.defuser;
            this.timeout = params.timeout;

            this.type = params.type ? params.type : 'info';
            this.size = params.size ? params.size : '';
            this.title = params.title;
            this.html = params.html;
            this.content = params.content;
        
            this.messages[0] = params.success ? (isArray(params.success) ? params.success : new Array(params.success)) : null;
            this.messages[1] = params.warning ? (isArray(params.warning) ? params.warning : new Array(params.warning)) : null;
            this.messages[2] = params.failure ? (isArray(params.failure) ? params.failure : new Array(params.failure)) : null;
        }
    };
    
    this.isValid = function() {
        return (this.messages[0] && this.messages[0].length > 0) ||
            (this.messages[1] && this.messages[1].length > 0) ||
            (this.messages[2] && this.messages[2].length > 0) ||
            (this.html && this.html != '') ||
            (this.content)
    }
    
    this.getView = function() {
        
        var view = $('<div/>');
        view.html(this.html);
        
        for(var i=0;i<this.messages.length;i++) {
            if (this.messages[i] && isArray(this.messages[i]) && this.messages[i].length > 0) {
                view.append(listify(this.messages[i]));
            }
        }
        
        view.append(this.content);
        return view;
    };
    
    function listify(messages) {
        var list = $('<ul class="list"></ul>');
        
        for(var i=0;i<messages.length;i++) {
            list.append($('<li>'+messages[i]+'</li>'));
        }

        return list;
    }
    
    this.init(params);
};

/**
 * Objekt dialogu tooltipu
 */
var TooltipDialog = function(req) {
    
    this.dialog = $('<div id="dialog"></div>');

    this.container = $('<div id="dialog-content-'+req.type+'"></div>');
    this.overlay = $('<div id="dialog-overlay">');
    this.header = $('<div id="dialog-content-header"></div>');
    this.content = $('<div id="dialog-content-in"></div>');
    this.close = $('<a href="" class="close">zavřít</a>');
    this.footer = $('<div id="dialog-content-footer"></div>');
    
    if (req.size) {
        this.container.addClass(req.size);
    }
    
    this.getElement = function() {
        return this.dialog;
    }
    
    this.updatePosition = function() {
        var webHeight = 0;
        var pageHeight = $('#body').height();
        var container = this.container;
        var dialogWidth = this.container.width();
		var dialog = this.dialog;
    
        var documentHeight = $(document).height();
        if (documentHeight < pageHeight) {
            webHeight = pageHeight
        } else {
            webHeight = documentHeight
        }

        /* DEFAULT POSITION & SCROLLING */
        //container is smaller than viewing area
        if ($(window).height() > container.height()) {
            this.container
                .css('top', $(window).scrollTop() + ($(window).height() / 2) - (container.height() / 2))
                .css('left', ($(window).width()/2) - (dialogWidth/2))
                .css('display', 'block');
                
            $(window).scroll(function () { 
                container.css('top', $(window).scrollTop() + ($(window).height() / 2) - (container.height() / 2))
            });
        //for large containers
        } else {
            this.container
                .css('top', $(window).scrollTop())
                .css('left', ($(window).width()/2) - (dialogWidth/2))
                .css('display', 'block');
                
            $(window).scroll(function () {
                if ($(window).scrollTop() < parseInt(container.css('top').match(new RegExp('^([0-9]+)'))[1])) {
                    container.css('top',$(window).scrollTop());
                } else if ($(window).scrollTop() + $(window).height() > parseInt(container.css('top').match(new RegExp('^([0-9]+)'))[1]) + container.height()) {
                    container.css('top',$(window).scrollTop() + $(window).height() - container.height());
                }
            });
        }
        
        /* CLOSE TIMEOUT */
        if (req.timeout && req.timeout > 0) {
            setTimeout(function(){
                dialog.remove();
            },req.timeout*1000);
        }
		
        /* OVERLAY SETUP */
        this.overlay
            .css('height', webHeight)
            .css('display','block');
            
        this.dialog.css('visibility','visible');
            
        return this;
    }
    
    this.create = function() {
		var dialog = this.dialog;
        this.dialog.css('visibility','hidden');
                 
        /* PRI KLIKNUTI NA ZAVRIT */
        this.close.bind('click',function(){
            dialog.remove();
            return false;
        });
        
        /* PRI KLIKNUTI NA OVERLAY */
        this.overlay.bind('click',function(){
            dialog.remove();
            return false;
        });
        
        /* PRI STISKNUTI ESC */
        $(document).keypress(function(event) {
            if (event.keyCode == '27') {
                dialog.remove();
            }
        });

        // zkonstruuje hlavicku
        this.header.html(req.title);
        this.header.append(this.close);
        // zkonstruuje telo
        this.content.html(req.getView());
        // zkompletuje cely kontejner
        this.container.append(this.header);
        this.container.append(this.content);
        this.container.append(this.footer);
        // vymaze aktualni obsah
        // a vlozi novy
        this.dialog.empty();
        this.dialog.append(this.overlay);
        this.dialog.append(this.container);
        
        return this;
    }
    
    return this.create();
};

/**
 * Objekt okna tooltipu
 */
var TooltipWindow = function(req) {
    
    this.tooltip = $('<div id="tooltip"></div>');

    this.header = $('<div id="tooltip-header"></div>');
    this.content = $('<div id="tooltip-content"></div>');
    this.close = $('<a href="" class="close">zavřít</a>');
    this.footer = $('<div id="tooltip-footer"></div>');
    this.arrow = null;
    
    this.getElement = function() {
        return this.tooltip;
    };
    
    this.updatePosition = function() {
        var margin = 47;
        
        var objSize = { x: req.object.width(), y: req.object.height() };
        var objOffset = { x: req.object.offset().left, y: req.object.offset().top };
        var windowSize = { x: $(window).width(), y: $(window).height() };
        var scroll = { x: $(window).scrollLeft(), y: $(window).scrollTop() };
        var size = { x: this.tooltip.width(), y: this.tooltip.height() };
    
        function isFreeSpace(where) {
            switch (where) {
                case "top": return objOffset.y - size.y > 0 + scroll.y;
                case "bottom": return objOffset.y + objSize.y + size.y < windowSize.y + scroll.y;
                case "right": return objOffset.x + objSize.x + size.x/2 < windowSize.x + scroll.x;
                case "left": return objOffset.x - size.x/2 > 0 + scroll.x;
            }
        }
        
        if (isFreeSpace('top'))     this.tooltip.css('top',(objOffset.y-size.y)+'px');
        else                        this.tooltip.css('top',(objOffset.y+objSize.y+margin/2)+'px');
        
        var offsets = [
            Math.min(objOffset.x+objSize.x-margin,windowSize.x-size.x-1),
            Math.max(objOffset.x-size.x+margin,0)
        ];
        
        var shift = isFreeSpace('right') ? 0 : 1;
        this.tooltip.css('left',offsets[shift]+'px');
        
        var diffs = [
            (objOffset.x+objSize.x-margin) - (offsets[shift]),
            (offsets[shift]+size.x-margin-objOffset.x)
        ];
        
        var sides = [
            'left',
            'right'
        ];
        
        this.arrow = $('<div id="tooltip-arrow" class="tooltip-arrow-'+
            ((isFreeSpace('right') ? 'left' : 'right')+ '-'+(isFreeSpace('top') ? 'bottom' : 'top'))+
        '"></div>');
        this.tooltip.append(this.arrow);
        this.arrow.css(sides[shift],
            (parseInt(this.arrow.css(sides[shift]).match(new RegExp('^([0-9]+)'))[1])+diffs[shift])+'px');
        this.tooltip.css('visibility','visible');
        
        /* CLOSE TIMEOUT */
        if (req.timeout && req.timeout > 0) {
            setTimeout(function(){
                tooltip.remove();
            },req.timeout*1000);
        }

        return this;
    }
    
    this.create = function() {
        var tooltip = this.tooltip;
        this.tooltip.css('visibility','hidden');

        /* PRI KLIKNUTI NA ZAVRIT */
        this.close.bind('click',function(){
            tooltip.remove();
            return false;
        });
    
        /* PRI STISKNUTI ESC */
        $(document).keypress(function(event) {
            if (event.keyCode == '27') {
                tooltip.remove();
            }
        });
    
        /* VOLITELNE AKCE UZAVRENI */
        switch (req.defuser) {
            case "mouseout":
            case "mouseleave":
                req.object.bind(req.defuser,function(){
                    tooltip.remove();
                    return false;
                });
                break;
        }

        // zkonstruuje hlavicku
        this.header.html(req.title);
        this.header.append(this.close);
        // zkonstruuje telo
        this.content.html(req.getView());
        // zkompletuje cely kontejner
        this.tooltip.empty();
        this.tooltip.append(this.header);
        this.tooltip.append(this.content);
        this.tooltip.append(this.footer);
        
        return this;
    }

    return this.create();
};

/**
 * Samotny objekt tooltipu
 */
var Tooltip = function(request){
    
    this.init = function() {
        var obj;
        var trigger;
        var _self = this;
        
        while ((obj = TooltipRegistry.get())) {
            if (obj.object) {
                switch(obj.trigger) {
                    case 'click':
                    case 'mouseover':
                    case 'mouseenter':
                        trigger = obj.trigger;
                        break;
                    default:
                        trigger = 'click';
                        break;
                }
                
                obj.object.bind(trigger,function(){
                    _self.display(obj);
                });
            } else {
                this.display(obj);
            }
        }
        
        
    };
    
    /**
     * Rozhodne o zobrazeni spravneho typu tooltipu
     */
    this.display = function(req) {
        if (req.isValid()) {
            var obj = !req.object ?
                new TooltipDialog(req) :
                new TooltipWindow(req);
            
            if (!req.object)
                $('#dialog').remove();

            $('body').append(obj.getElement());
            obj.updatePosition();
        }
    };
    
    /* registrace predanych pozadavku */
    if (request) {
        if (!request[0]) {
            request = new Array(request);
        }
    
        for(var i=0;i<request.length;i++) {
            TooltipRegistry.register(request[i]);
        }
    }
    
    /**
     * Zobrazi okno s dialogem a naplni ho daty
     */
    this.init();

};

