/*
 * jQuery.LiveTips
 * Plugin for jQuery 1.2.6+
 * Version: 0.2
 * Copyright (c) 2011 Eugene Chusov. All rights reserved.
 * Released under the GNU/GPL license: http:
 * More info at http://chusov.ru/livetips
 * Designed and developed by Eugene Chusov <eugene@chusov.ru>

 * ENG
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * RUS
 * Эта программа является свободным программным обеспечением. Вы можете
 * распространять и/или модифицировать её согласно условиям Стандартной
 * Общественной Лицензии GNU, опубликованной Фондом Свободного Программного
 * Обеспечения, версии 3 или, по Вашему желанию, любой более поздней версии.
 * Эта программа распространяется в надежде, что она будет полезной, но БЕЗ
 * ВСЯКИХ ГАРАНТИЙ, в том числе подразумеваемых гарантий ТОВАРНОГО СОСТОЯНИЯ ПРИ
 * ПРОДАЖЕ и ГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННОГО ПРИМЕНЕНИЯ. Смотрите Стандартную
 * Общественную Лицензию GNU для получения дополнительной информации.
 */

(function($){


	var pluginClass = function($tip){

		var self = this;

        var settings = {
            contentdiv: false,
            contentdivref: '.tip_container',
            opacity: 1,
            showdelay: 0,
            hidedelay: 300,
            showduration: 0,
            hideduration: 200,
            offsetx: 0,
            offsety: 0,
            canover: false,
            track: false,
            addclass: null,
            positionx: 'left',
            positiony: 'top'
        };


        self.init = function(options){
            $.extend(settings, options);
            abstractTip.init();
        }

        var docWidth = $(document).width();
        var docHeight = $(document).height();

        var abstractTip = {

            positions: [['top','left'], ['top','center'], ['top','rigth'],
                ['center','right'], ['bottom','right'], ['bottom','center'],
                ['bottom','left'], ['center','left']],

            timeout: null,
            text: null,
            $div: null,


            offset: null,

            tipWidth: null,
            tipHeight: null,

            divWidth: null,
            divHeight: null,

            init: function(){

                if( settings.contentdiv ){
                    var $tip_text = $tip.next(settings.contentdivref);
                    abstractTip.text = $tip_text.html();
                    $tip_text.remove();
                } else {
                    abstractTip.text = $tip.attr('title');
                    $tip.attr('title', '');
                }

                abstractTip.$div = $('<div class="livetips_overlay" style="position:absolute; display:none;"></div>');


                if( settings.addclass ){
                    abstractTip.$div.addClass(settings.addclass);
                }

                abstractTip.$div.appendTo('body');
                abstractTip.$div.html(abstractTip.text);

                abstractTip.$div.hover(abstractTip.divOver, abstractTip.divOut);


                if( settings.track ){
                    $tip.mousemove(abstractTip.track);
                }

                $tip.hover(abstractTip.tipOver, abstractTip.tipOut);
            },

            outFunction: function(){
                abstractTip.$div.stop().animate({opacity:0}, settings.hideduration, function(){
                    abstractTip.$div.hide();
                });
            },

            divOver: function(event){
                clearTimeout(abstractTip.timeout);
            },

            divOut: function(event){
                if( $(event.relatedTarget).parents('.tip').length == 0 ){
                    abstractTip.outFunction();
                }
            },


            tipOver: function(event){


                $('.livetips_overlay').stop().css('opacity', 0);

                abstractTip.offset = $tip.offset();

                abstractTip.divWidth = abstractTip.$div.outerWidth()

                abstractTip.tipWidth = $tip.outerWidth();
                abstractTip.tipWidth = abstractTip.tipWidth > 0
                    ? abstractTip.tipWidth
                    : $tip.children().width()

                abstractTip.tipHeight = $tip.outerHeight();
                abstractTip.divHeight = abstractTip.$div.outerHeight();

                var offset = abstractTip.divoffset();


                abstractTip.$div
                    .css('opacity', 0)
                    .css('left', offset.left  )
                    .css('top', offset.top )
                    .stop()
                    .show()

                if( settings.showdelay > 0 ){
                    abstractTip.$div.animate({margin: 0}, settings.showdelay, function(){
                        if( settings.showduration > 0 ){
                            abstractTip.$div.animate({opacity: settings.opacity}, settings.showduration);
                        } else {
                            abstractTip.$div.css({opacity: settings.opacity});
                        }
                    });
                } else {
                    if( settings.showduration > 0 ){
                        abstractTip.$div.animate({opacity: settings.opacity}, settings.showduration);
                    } else {
                        abstractTip.$div.css({opacity: settings.opacity});
                    }
                }
            },


            tipOut: function(event){
                if( settings.canover ){
                    abstractTip.timeout = setTimeout( function(){
                        abstractTip.outFunction();
                    }, settings.hidedelay );
                } else {
                    abstractTip.outFunction();
                }
            },


            checkOffset: function(offset){

                var xdiff = [0, abstractTip.divWidth, abstractTip.divWidth, 0];
                var ydiff = [0, 0, abstractTip.divHeight, abstractTip.divHeight];

                for( i in xdiff ){

                    if( offset.left + xdiff[i] < 0 || offset.left + xdiff[i] > docWidth ){
                        return false;
                    }

                    if( offset.top + ydiff[i] < 0 || offset.top  + ydiff[i] > docHeight ){
                        return false;
                    }
                }

                return true;
            },

            divoffset: function(){

                var offset = {};

                offset.left = abstractTip.divoffsetX();
                offset.top = abstractTip.divoffsetY();

                var result = abstractTip.checkOffset(offset);

                if( !result ){

                    for(i in abstractTip.positions){

                        offset.left = abstractTip.divoffsetX(abstractTip.positions[i][1]);
                        offset.top = abstractTip.divoffsetY(abstractTip.positions[i][0]);

                        if( abstractTip.checkOffset(offset) ){
                            return offset;
                        }
                    }
                }

                return offset;
            },


            divoffsetX: function(posX){

                posX = posX ? posX : settings.positionx;

                var x = [1/2, -1/2];
                x = posX == 'left' ? [0,-1] : x;
                x = posX == 'right' ? [1,0] : x;

                return abstractTip.offset.left + x[0]*abstractTip.tipWidth + x[1]*abstractTip.divWidth + settings.offsetx;
            },

            divoffsetY: function(posY){

                posY = posY ? posY : settings.positiony;

                var y = [1/2, -1/2];
                y = posY == 'top' ? [0,-1] : y;
                y = posY == 'bottom' ? [1,0] : y;

                return abstractTip.offset.top + y[0]*abstractTip.tipHeight  + y[1]*abstractTip.divHeight + settings.offsety;
            },


            track: function(event){

                clearTimeout(abstractTip.timeout);

                abstractTip.$div
                    .show()
                    .css('left', event.pageX + abstractTip.tipWidth + settings.offsetx  )
                    .css('top', event.pageY - abstractTip.divHeight + settings.offsety )
            }
        }

		return self;
	}


    $.fn.liveTips = function( method ){

        var args = arguments;


        return this.each(function(index){

            var $object = $(this);


			var plugin = $object.data('class');

			if( !plugin ){
				plugin = new pluginClass($object);
				$object.data('class', plugin);
			}


            if ( plugin[method] ) {
                plugin.__init || $.error( 'Run init method before: ' +  method );
                plugin[method](args[1]);
            } else if ( typeof method === 'object' || !method ) {
				plugin.__init = true;
                plugin.init(method);
            } else {
                $.error( 'Method ' +  method + ' does not exist on jQuery.funnyBox' );
            }
        });
    }

})(jQuery);
