/*
при клике(наведению мыши) по элементу,
во всплывающий под этим элементом слой, загружаются данные из бэкенда или выполняется функция
*/
var hint = Class.create();
hint.prototype = {
    initialize: function(params) {
        // Значения по умолчанию
        //
        this.hintElement = null;
        // кеширование результатов запроса, включено
        this.requestCaching = true;
        // путь к бэкенду, если не указать, то обращения к серверу не произойдет
        this.backendScript = false;
        // имя функции, которую необходимо выполнить при открытии подсказки
        // если не указать, обращения к функции не произойдет
        this.functionName = false;
        // по умолчанию закрывать окно, если кликнули вне его зоны
        this.outClickHide = true;

        Object.extend(this, params);

        this.hintElement = $(this.hintElement);
        if (!this.hintElement)
            return false;
        this.hintElement.style.position = 'absolute';
        this.loadingTpl = this.hintElement.innerHTML;
        Event.observe(document, 'mousedown', this.outsideClickHide.bindAsEventListener(this));
        Event.observe(document, 'keypress', this.escHide.bindAsEventListener(this), false);
        Event.observe(window, 'resize', this.changePosition.bindAsEventListener(this));
        Event.observe(window, 'scroll', this.changePosition.bindAsEventListener(this));
    },

    // показываем всплывающее окно
    showHint: function(caller, params) {
        this.caller =$(caller);
        // сначала закрыть всплывающее окно, возможно оно было открыто
        this.hideHint();
        // обратиться к бэкенду
        if (this.backendScript) {
            this.changePosition();
            this.hintElement.style.display = 'block';
            this.loadData(params);
            return;
        // в противном случае выполнить функцию
        } else if (this.functionName) {
            if (!params)
                params = '';
            this.functionName(params);

        }
        this.changePosition();
        this.hintElement.style.display = 'block';
    },

    // меняем расположение всплывающей подсказки
    changePosition: function() {
        if (!this.caller || !this.hintElement)
            return;
        var callerPos = Position.page(this.caller);
        // x и y координата вызывающего элемента относительно видимой области окна
        var cX = callerPos[0], cY = callerPos[1];
        // ширина и высота вызывающего элемента
        var cW = this.caller.getWidth(), cH = this.caller.getHeight();
        // координаты левого верхнего угла вызывающего элемента
        var callerTopLeft = {x:cX, y:cY};
        // координаты левого нижнего угла вызывающего элемента
        var callerBottomLeft = {x:cX, y:(cY + cH)};
        // ширина и высота окна
        var winSize = Position.getWindowSize();
        var winW = winSize.width, winH = winSize.height;
        // ширина и высота подсказки
        var dim = this.hintElement.getDimensions();
        var hintW = dim.width, hintH = dim.height;
        // сдвигать вправо/влево, если выходит за границы окна
        var offsetLeft = 0;
        if (cX < 0) {
            offsetLeft = Math.abs(cX);
            if (offsetLeft > cW)
                offsetLeft = cW;
        }
        if ((cX + hintW) > winW) {
            offsetLeft = winW - (cX + hintW)-2;
            if (cX > winW)
                offsetLeft = -hintW-2;
        }
        if ((callerTopLeft.y >= hintH) && !((callerBottomLeft.y + hintH) <= winH))
            // расположить выше вызывающего элемента
            Position.clone(this.caller, this.hintElement, {setWidth: false, setHeight: false, offsetTop: -hintH, offsetLeft: offsetLeft});
        else
            // расположить ниже
            Position.clone(this.caller, this.hintElement, {setWidth: false, setHeight: false, offsetTop: cH, offsetLeft: offsetLeft});
    },

    // загружаем данные во всплывающее окно
    //
    loadData: function(params) {
        var that = this;
        var r = new Ajax.Request(that.backendScript, {
            method: 'POST',
            parameters: {
                requestCaching: that.requestCaching,
                params: params
            },
            // в случае ошибки передачи
            onFailure: function(tr) {
                alert("Ошибка передачи данных");
            },
            // в случае успеха
            onSuccess: function(tr) {
                if (!that.hintElement.visible())
                    return;
                var text = tr.responseText;
                that.hintElement.hide();
                that.hintElement.innerHTML = text;
                that.changePosition();
                that.hintElement.style.display = 'block';

                // выполнить пользовательскую функцию, если она указана
                if (that.functionName != false) {
                    if (!params)
                        params = '';
                    that.functionName(params);
                }
                // выполнить все скрипты в тексте, который вернул бэкенд
                text.evalScripts();
           }
        });
    },

    // закрываем всплывающее окно, если кликнули за его пределами
    outsideClickHide: function(event) {
        if (!this.outClickHide || !this.hintElement.visible())
            return;
        // если сделали mousedown по скроллбарам
        var winSize = Position.getWindowSize();
        var winW = winSize.width, winH = winSize.height;
        if ((event.clientX > winW) || (event.clientY > winH))
            return;

        var target = Event.element(event);
        target = $(target);
        if ((target == this.caller) || (target.descendantOf(this.caller)))
            return;
        while (target) {
            if (target == this.hintElement)
                return;
            target = target.parentNode;
        }
        this.hideHint();
    },

    // закрыть всплывающее окно, при нажатии на ссылку(кнопку) "закрыть"
    hideHint: function(e) {
        this.hintElement.hide();
        if (this.backendScript)
            this.hintElement.innerHTML = this.loadingTpl;
    },

    // закрыть при нажатии клавиши ESC
    escHide: function(e) {
        if (e.keyCode && (e.keyCode == Event.KEY_ESC)) {
           this.hideHint();
        }
    }

};