function Bubble(options)
{
    // стандартные настройки
    this.options = {
         // использовать затемнение
        overlay: true,
        
        // место вставки бабла
        placeholder: document.body,

        // ширина бабла
        width: 'auto',
        
        // высота бабла
        height: 'auto',
        
        // имя бабла
        name: 'bubble',
        
        // префикс бабла
        name_prefix: 'bubble_',
        
        // дополнительные CSS-классы
        additional_class: '',

        // выводить кнопку закрытия
        close_button: true
    };
    this.document_height = getDocumentHeight() - 30;

    // переопределение настроек
    if (typeof options == 'object')
    {
        for (var key in options)
            this.options[key] = options[key];
    }

    // прорисовка затемнения
    if (this.options.overlay)
    {
        this.drawOverlay();
        this.overlay('hide')
    }

    // прорисовка бабла
    this.drawBubble();
    this.hide();
}

Bubble.prototype = 
{
	/**
	 * Прорисовывает затемнение
	 */
    drawOverlay: function() 
    {
        this.$overlay = add('div', {'class': 'overlay'}, document.body);
        this.$overlay.style.height = this.document_height + 'px';
    },

	/**
	 * Прорисовывает бабл и кнопку закрыть, если передана соответствующая опция
 	*/
    drawBubble: function() 
    {
        var that = this;

        // бабл
        this.$bubble = add('div', {
            'id': (this.options.name_prefix + this.options.name),
            'class': 'bubble' + this.options.additional_class,
            'text': '<div class="in"></div>'
        }, this.options.placeholder);

        this.$bubble.style.width = (typeof this.options.width == 'number') ? this.options.width + 'px' : this.options.width;
        this.$bubble.style.height = (typeof this.options.height == 'number') ? this.options.height + 'px' : this.options.height;


        // кнопка "Закрыть"
        if (this.options.close_button)
        {
            var $close_button = add('span', {
                'class': 'close_button',
                'title': 'Закрыть'
            }, this.$bubble);

            $close_button.onclick = function() {
                that.overlay('hide');
                that.hide();
            }
        }
    },

	/**
	 * Отображает/прячем затемнение
	 * @param {String} mode параметр отображения [show|hide] 
	 * @return {Object} текущий класс 
	 */
    overlay: function(mode)
    {
        if (mode == 'show')
            this.$overlay.style.display = 'block';
        else if (mode == 'hide')
            this.$overlay.style.display = 'none';
        return this;
    },

	/**
	 * Отображает бабл
	 * @return {Object} текущий класс
	 */
    show: function()
    {
        this.overlay('show');
        this.$bubble.style.display = 'block';
        return this;
    },

    /**
     * Прячет бабл
     * @return {Object} текущий класс
     */
    hide: function()
    {
        this.overlay('hide');
        this.$bubble.style.display = 'none';
        return this;
    },

    /**
     * Устанавливает текст внутри бабла
     * @param {String} text текст, который надо установить в бабле
     * @return {Object} текущий класс
     */
    text: function(text)
    {
        var divs = this.$bubble.getElementsByTagName('div');
        var src_div;

        for (var i = 0, len = divs.length; i < len; i++)
        {
            if (divs[i].className == 'in')
            {
                src_div = divs[i];
                break;
            }
        }

        src_div.innerHTML = text;
        this.position('center');
        return this;
    },

    /**
     * Устанавливает ширину бабла
     * @param {Number} width ширина бабла
     * @return {Object} текущий класс 
     */
    width: function(width) {
        this.$bubble.style.width = (typeof width == 'number') ? width + 'px' : width;
        return this;
    },

    /**
     * Устанавливает высоту бабла
     * @param {Number} height высота бабла
     * @return {Object} текущий класс
     */
    height: function(height) {
        this.$bubble.style.height = (typeof height == 'number') ? height + 'px' : height;
        return this;
    },

    /**
     * Устанавливает ширину и высоту бабла
     * @param {Number} width ширина бабла
     * @param {Number} height ширина бабла
     * @return {Object} текущий класс
     */
    size: function(width, height) {
        this.width(width);
        this.height(height);
        return this;
    },

    /**
     * Перемещает бабл в позицию с указанными координатами  
     * @param {Mixed} pos позиция бабла 
     * Если передан Object{left: 10, top: 10} бабл перестится в координаты x=10, y=10.
     * Если передан String, один из возможных значений 'top','center','bottom' то бабл перемещается
     *      в верхнюю, центральную и нижнюю позицию окна соответственно
     * @param {DOMElement} holder элемент, по размерам которого высчитывается расположение бабла, по
     *      умолчанию берётся из this.options.placeholder
     * @return {Object} текущий класс
     */
    position: function(pos, holder)
    {
        if (typeof pos == 'string')
        {
            // элемент, по габаритам которого высчитывается расположение бабла
            var holder = holder || this.options.placeholder;

            var top = (isIE6) ? document.documentElement.clientHeight : holder.clientHeight;
            var left = (isIE6) ? document.documentElement.clientWidth : holder.clientWidth;
            top = Math.round(top / 2) + get_scroll_top();
            left = Math.round(left / 2);

            var width = Math.round(this.$bubble.clientWidth / 2);
            var height = Math.round(this.$bubble.clientHeight / 2);

            switch (pos)
            {
                case 'top':
                    top = 0;
                    left = left - width;
                    break;

                case 'center':
                    top = top - height;
                    left = left - width;
                    break;

                case 'bottom':
                    top = holder.clientHeight - height;
                    left = left - width;
                    break;
            }

            this.$bubble.style.top = top + 'px';
            this.$bubble.style.left = left + 'px';
        }
        else if (typeof pos == 'object')
        {
            this.$bubble.style.left = pos.left + 'px';
            this.$bubble.style.top = pos.top + 'px';
        }
        return this;
    }

}

/**
 * Добавляет новый html-элемент (тег)
 * @param {String} ename Название добавляемого тега. Ex: 'option', 'em'
 * @param {Object} attrs Хэш с атрибутами добавляемого тега. Ex: {'id': 'new', 'width': '50%'}
 * @param {String} parent Родитель нового элемента. Ex: $('el'), document.body
 * @return {DOMElement}
 */
function add(ename, attrs, parent)
{
    var el = document.createElement(ename);
    if (typeof(attrs) == 'object')
    {
        for(var key in attrs)
        {
            if ('class' == key)
                el.className = attrs[key];
            else if ('text' == key)
                el.innerHTML = attrs[key];
            else
                el.setAttribute(key, attrs[key]);
        }
    }

    if (parent)
        parent.appendChild(el);

    return el;
}

function get_scroll_top()
{
    if(typeof pageYOffset != 'undefined')
    {
        //most browsers
        return pageYOffset;
    }
    else
    {
        var B = document.body; //IE 'quirks'
        var D = document.documentElement; //IE with doctype
        D = (D.clientHeight)? D : B;
        return D.scrollTop;
    }
}

