/**
 *$Id: event.js 107 2009-01-22 09:38:37Z aanpilogov $
 *
 */
PuskFramework.evt = new function()
{
    var pf = PuskFramework;

    /*
     * Человекочитаемые названия клавиш
     */
    this.keys = {
        8:  'backspace',
        9:  'tab',
        13: 'enter',
        27: 'esc',
        37: 'left',
        38: 'up',
        39: 'right',
        40: 'down',
        46: 'delete',
        36: 'home',
        35: 'end',
        33: 'pageup',
        34: 'pagedown',
        45: 'insert'
    };

    /**
     * Получить событие кроссбраузерно
     *
     * @param {Object} evt событие или null
     * @return {Object}
     */
    this.e = function(evt) { return evt || window.event; };

    /**
     * Добавить обработчик события
     *
     * @param {Object} elem элемент
     * @param {Object} event тип события (без префикса on)
     * @param {Object} callback функция обработчик
     */
    this.add = function(elem, event, callback)
    {
        callback = pf._expandCallBack(callback);
        switch(event)
        {
            case 'mousewheel':
            {
                if (pf.browsCap.isMozilla) { event = 'DOMMouseScroll'; }
                break;
            }
            case 'dataavailable':
            {
                if (!pf.browsCap.isIE) { event = 'DOMContentLoaded'; }
                break;
            }
        }

        if(document.attachEvent)
        {
            elem.attachEvent('on'+event, callback);
        }
        else if(document.addEventListener)
        {
            elem.addEventListener(event, callback, true);
        }
    };

    /*
     * Алиас для совместимости
     */
    this.addListener = this.add;

    /**
     * Удалить обработчик события с элемента
     *
     * @param {Object} elem элемент
     * @param {Object} event событие (без префикса on)
     * @param {Object} callback обработчик
     */
    this.remove = function(elem, event, callback)
    {
        callback = pf._expandCallBack(callback);
        switch(event)
        {
            case 'mousewheel':
            {
                if (pf.browsCap.isMozilla) { event = 'DOMMouseScroll'; }
                break;
            }
            case 'dataavailable':
            {
                if (!pf.browsCap.isIE) { event = 'DOMContentLoaded'; }
                break;
            }

        }

        if(document.detachEvent)
        {
            elem.detachEvent('on'+event, callback);
        }
        else if(document.removeEventListener)
        {
            elem.removeEventListener(event, callback, true);
        }
    };

    /*
     * Алиасы для удобства и совместимости
     */
    this.removeListener = this.remove;
    this.del            = this.remove;

    /**
     * Остановить развитие события и его последствий ;)
     *
     * @param {Object} evt событие
     */
    this.stop = function(evt)
    {
        evt = pf.$event(evt);
        evt.stopPropagation();
        evt.preventDefault();
        return false;
    };

    /**
     * Получить человекопонятное название клавиши по событию
     *
     * @param {Object} evt событие
     * @return {String}
     */
    this.getKeyName = function(evt)
    {
        evt = this.e(evt);
        var code = evt.keyCode;
        return this.keys[code] || code;
    };

    /**
     * Получить абсолютные координаты мыши по событию в виде {x,y}
     *
     * @param {Object} evt событие
     * @return {Object}
     */
    this.getPosition = function(evt)
    {
        evt = this.e(evt);
        var x = 0, y = 0;

        if (evt.pageX || evt.pageY)
        {
            x = evt.pageX;
            y = evt.pageY;
        } else if (evt.clientX || evt.clientY) {
            x = evt.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft;
            y = evt.clientY + (document.documentElement.scrollTop  || document.body.scrollTop)  - document.documentElement.clientTop;
        }

        return {'x':x, 'y':y};
    };

    /**
     * Получить состояние колеса прокрутки мыши
     * положительное/отрицательное значения говорят о направлении
     *
     * @param {Object} evt событие
     * @return {Integer}
     */
    this.getWheel = function(evt)
    {
        evt = this.e(evt);

        var delta = 0;
        if (evt.wheelDelta)
        {
            delta = evt.wheelDelta/120;
        }
        else if (evt.detail)
        {
            delta = -evt.detail/3;
        }

        this.stop(evt);
        return delta || false;
    };

    /**
     * Проверяет, находится ли курсор мыши внутри заданного элемента
     *
     * @param {Object} elem элемент
     * @param {Object} evt событие
     * @return {Bool}
     */
    this.mouseIn = function(elem, evt)
    {
        var mPos = this.getPosition(evt);
        var ePos = pf.elem.getPosition(elem);
        var w = parseInt(elem.offsetWidth);
        var h = parseInt(elem.offsetHeight);
        return ((mPos.x > ePos.x) && (mPos.x <= ePos.x+w) && (mPos.y > ePos.y) && (mPos.y <= ePos.y+h));
    };

    /**
     * Проверка, действительно ли имеет место событие mouseover
     * некоторые браузеры ошибочно генерят события over и out
     *
     * @param {Object} element элемент
     * @param {Object} evt событие
     * @return {Bool}
     */
    this.checkMouseOver = function(element, evt)
    {
        evt = this.e(evt);
        if (element.contains)  return !element.contains(evt.fromElement);
        if (evt.relatedTarget) return !pf.elem.containsDOM(element, evt.relatedTarget);
    };

    /**
     * Проверка, действительно ли имеет место событие mouseout
     * некоторые браузеры ошибочно генерят события over и out
     *
     * @param {Object} element элемент
     * @param {Object} evt событие
     * @return {Bool}
     */
    this.checkMouseOut = function(element, evt)
    {
        evt = this.e(evt);
        if (element.contains)  return !element.contains(evt.toElement);
        try{ // FF + input.parentNode = eggog
        if (evt.relatedTarget) return !pf.elem.containsDOM(element, evt.relatedTarget);
        } catch(e) { return false; }
    };
};
