/**
 * This class is used for building and positioning a PopTip
 */
var PopTip = {
    hours      : ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve'],
    width      : 0,
    element    : '',
    poptip     : '',
    arrow      : '',
    x          : 0,
    y          : 0,
    x2         : 0,
    y2         : 0,
    pt_w       : 0,
    pt_h       : 0,
    offset_out : 50,
    offset_in  : 30,
    offset_c   : 10,
    
    /**
     * Sets some vars needed for positioning
     * 
     * @param element
     * 
     * @return void
     */
    setVars: function (element) {
        this.element    = element;
        this.arrow      = this.poptip.querySelector ('.poptip_arrow');
        this.x          = element.offsetLeft;
        this.y          = element.offsetTop;
        this.x2         = this.x + element.clientWidth;
        this.y2         = this.y + element.clientHeight;
        this.pt_w       = this.poptip.clientWidth;
        this.pt_h       = this.poptip.clientHeight;
    },
    
    /**
     * The 'caller' method, use this one to create a PopTip
     * 
     * @param title_text string
     * @param content_text string
     * @param position int
     * @param element Element
     * @param width int If no width is given, it resizes accordingly to its content
     * 
     * @return void
     */
    createPopTip: function (title_text, content_text, position, element, width) {
        this.closeAllPopTips ();
        
        if (width !== undefined) {
            this.width = width;
        }
        
        var parent = element.parentNode,
            poptip = this.buildPopTip (title_text, content_text, position);
            
        this.poptip = poptip;
            
        parent.insertBefore (this.poptip, parent.firstChild);
        
        this.setVars (element);
        this.setPosition (position);
        
        setTimeout (function () {PopTip.setEventListener ()}, 10);
    },
    
    /**
     * The builder function
     * 
     * @param title_text string
     * @param content_text string
     * @param position int
     * 
     * @return Element
     */
    buildPopTip: function (title_text, content_text, position) {
        var container = document.createElement ('div'),
            poptip    = document.createElement ('div'),
            head      = document.createElement ('div'),
            title     = document.createElement ('h3'),
            close     = document.createElement ('div'),
            content   = document.createElement ('div'),
            arrow     = document.createElement ('div');
            
        container.className = 'poptip_container';
        poptip.className    = 'poptip';
        head.className      = 'poptip_head';
        close.className     = 'poptip_close';
        content.className   = 'poptip_content';
        arrow.className     = 'poptip_arrow ' + this.hours[position - 1] + 'oclock';
        
        title.innerHTML = title_text;
        head.appendChild (title);
        
        close.setAttribute ('onclick', 'PopTip.closePopTip (this)');
        head.appendChild (close);
        
        poptip.appendChild (head);
        
        content.innerHTML = content_text;
        poptip.appendChild (content);
        
        if (this.width > 0) {
            poptip.style.width = this.width + 'px';
        }
        
        container.appendChild (poptip);
        container.appendChild (arrow);
        
        return container;
    },
    
    /**
     * Removes a PopTip from the DOM
     * 
     * @param element Element
     * 
     * @return void
     */
    closePopTip: function (element) {
        if (this.isDescendantPopTip (element) === false) {
            return;
        }
        
        var container = this.findPopTipContainer (element),
            parent = container.parentNode;
            
        parent.removeChild (container);
    },
    
    /**
     * Finds all the PopTips and removes them
     * 
     * @return void
     */
    closeAllPopTips: function () {
        this.removeEventListener ();
        
        var poptips = document.querySelectorAll ('.poptip_container .poptip_close');
        for (i = 0, j = poptips.length; i < j; i++) {
            this.closePopTip (poptips[i]);
        }
    },
    
    /**
     * Sets the event listener needed for closing PopTips if you click beside them
     * 
     * @return void
     */
    setEventListener: function () {
        var html = document.getElementsByTagName ('html')[0];
        
        if (html.addEventListener) {
            html.addEventListener ('click', PopTip.eventHandler, false);
        } else if (html.attachEvent) {
            html.attachEvent ('onclick', PopTip.eventHandler)
        }
    },
    
    /**
     * Removes the event listener
     * 
     * @return void
     */
    removeEventListener: function () {
        var html = document.getElementsByTagName ('html')[0];
        
        if (html.removeEventListener) {
            html.removeEventListener ('click', PopTip.eventHandler, false);
        } else if (html.detachEvent) {
            html.detachEvent ('onclick', PopTip.eventHandler)
        }
    },
    
    /**
     * The function used for the the event listener
     * 
     * @return void
     */
    eventHandler: function () {
        var target = arguments[0].target || arguments[0].srcElement || arguments[0].originalTarget;
        
        if (PopTip.isDescendantPopTip (target) === false){
            PopTip.closeAllPopTips ();
        }
    },
    
    /**
     * Check if target or it's parents is a poptip_container
     * 
     * @param target Element
     * 
     * @return mixed void|Node
     */
    findPopTipContainer: function (target) {
        if (target.className == "poptip_container") {
            return;
        }

        var node = target.parentNode;
        while (node != null) {
            if (node.className == "poptip_container") {
                return node;
            }
            node = node.parentNode;
        }
    },
    
    /**
     * Check if target or it's parents is a poptip
     * 
     * @param target Element
     * 
     * @return boolean
     */
    isDescendantPopTip: function (target) {
        if (target.className == "poptip") {
            return true;
        }

        var node = target.parentNode;
        while (node != null) {
            if (node.className == "poptip") {
                return true;
            }
            node = node.parentNode;
        }
        return false;
    },

    /**
     * Sets the position using clock notation
     * 
     * @param position int Use 1 through 12 to determine the position like the
     *        small hand of a clock
     *        
     * @return voi
     */
    setPosition: function (position) {
        switch (position) {
            case 1:
                this.oneoclock ();
                break;
            case 2:
                this.twooclock ();
                break;
            case 3:
                this.threeoclock ();
                break;
            case 4:
                this.fouroclock ();
                break;
            case 5:
                this.fiveoclock ();
                break;
            case 6:
                this.sixoclock ();
                break;
            case 7:
                this.sevenoclock ();
                break;
            case 8:
                this.eightoclock ();
                break;
            case 9:
                this.nineoclock ();
                break;
            case 10:
                this.tenoclock ();
                break;
            case 11:
                this.elevenoclock ();
                break;
            case 12:
                this.twelveoclock ();
                break;
        }
    },

    // 1 o'clock
    oneoclock: function () {
        this.poptip.style.top = this.y2 + 'px';
        this.poptip.style.left = this.x - (this.pt_w - this.offset_out) + 'px';
    },

    // 2 o'clock
    twooclock: function () {
        this.poptip.style.top = this.y - this.offset_in + 'px';
        this.poptip.style.left = this.x - this.pt_w + 'px';
    },

    // 3 o'clock
    threeoclock: function () {
        this.poptip.style.top = this.y - (this.pt_h / 2) + this.offset_c + 'px';
        this.poptip.style.left = this.x - this.pt_w + 'px';
        this.arrow.style.top = (this.pt_h / 2) - (this.offset_c) + 'px';
    },

    // 4 o'clock
    fouroclock: function () {
        this.poptip.style.top = this.y - (this.pt_h) + this.offset_out + 'px';
        this.poptip.style.left = this.x - this.pt_w + 'px';
    },

    // 5 o'clock
    fiveoclock: function () {
        this.poptip.style.top = this.y - (this.pt_h) + 'px';
        this.poptip.style.left = this.x - this.pt_w + this.offset_out + 'px';
    },

    // 6 o'clock
    sixoclock: function () {
        this.poptip.style.top = this.y - (this.pt_h) + 'px';
        this.poptip.style.left = this.x - (this.pt_w / 2) + this.offset_c + 'px';
        this.arrow.style.left = (this.pt_w / 2) - (this.offset_c) + 'px';
    },

    // 7 o'clock
    sevenoclock: function () {
        this.poptip.style.top = this.y - (this.pt_h) + 'px';
        this.poptip.style.left = this.x - this.offset_in + 'px';
    },

    // 8 o'clock
    eightoclock: function () {
        this.poptip.style.top = this.y - (this.pt_h) + this.offset_out + 'px';
        this.poptip.style.left = this.x2 + 'px';
    },

    // 9 o'clock
    nineoclock: function () {
        this.poptip.style.top = this.y - (this.pt_h / 2) + this.offset_c + 'px';
        this.poptip.style.left = this.x2 + 'px';
        this.arrow.style.top = (this.pt_h / 2) - (this.offset_c) + 'px';
    },

    // 10 o'clock
    tenoclock: function () {
        this.poptip.style.top = this.y - this.offset_in + 'px';
        this.poptip.style.left = this.x2 + 'px';
    },

    // 11 o'clock
    elevenoclock: function () {
        this.poptip.style.top = this.y2 + 'px';
        this.poptip.style.left = this.x - this.pt_w + this.offset_out + 'px';
    },

    // 12 o'clock
    twelveoclock: function () {
        this.poptip.style.top = this.y2 + 'px';
        this.poptip.style.left = this.x - (this.pt_w / 2) + this.offset_c + 'px';
        this.arrow.style.left = (this.pt_w / 2) - (this.offset_c) + 'px';
    }
}