// Balloon 0.1.1

var Balloon = new Class({

    options: $H({
        fxDuration: 350,
        fxTransition: 'quad:in',
        maxLength: false,
        selector: '.balloon'
    }),

    styles: $H({
        background: ['#fff', '#ddd'],
        cornerRadius: 5,        
        height: 20,
        padding: {
            x: 4,
            y: 2
        },
        size: 10,
        stroke: {
            color: '#ccc',
            size: 1
        },
        tip: {
            height: 5,
            width: 5
        },
        width: 250
    }),

    initialize: function(options)
    {
        this.extendOptions(options || {});

        this.elements = this.getElements();

        this.build();
        this.observe();
    },
    
    extendOptions: function(options)
    {
        this.styles.extend(options.styles || {});
        this.options.extend(options);
    },
    
    getElements: function()
    {
        return $$(this.options.selector);    
    },
    
    getTitle: function(el)
    {
        var t = el.get('title');
        el.removeAttribute('title');
        if(this.options.maxLength != false && t.length > this.options.maxLength)
        {
            t = t.substr(0, this.options.maxLength)+'...';
        }
        return t;
    },
    
    build: function()
    {
        this.elements.each(function(el){
            this.createBalloon(el); 
        }, this);    
    },
    
    show: function(el)
    {       
        var fx = el.retrieve('fx');
        var height = el.getParent().getElement('span').getHeight();

        fx.pause();
        fx.start({
            opacity: 1,
            top: (el.retrieve('top') - height)
        });
    },
    
    hide: function(el)
    {
        var fx = el.retrieve('fx');

        fx.pause();
        fx.start({
            opacity: 0,
            top: el.retrieve('top')
        });
    },
    
    observe: function()
    {
        var fx = [];

        this.elements.each(function(el, i){
            var canvas = el.getNext();
            var overlay = el.getNext('.balloon-overlay');

            var fx = new Fx.Morph(canvas, {
                duration: this.options.fxDuration,
                transition: this.options.fxTransition
            })

            overlay.store('fx', fx);
            overlay.store('top', overlay.getStyle('top').toInt());

            overlay.addEvents({
                'mouseover': function() {
                    this.show(overlay);
                }.bind(this),
                'mouseout': function() {
                    this.hide(overlay);
                }.bind(this)                
            });
        }, this);
    },

    createBalloon: function(el){

        var dim = el.getCoordinates();

        var styles = this.styles;

        var canvasHolder = new Element('span', {
            'class': 'speech-balloon',
            styles: {
                height: styles.height + styles.tip.height + (styles.stroke.size*2) + (styles.padding.y*2),
                left: (dim.left - (styles.width/2) + (dim.width/2)).round(),
                opacity: 0,
                padding: styles.padding.x+'px '+styles.y+'px',
                position: 'absolute',
                top: dim.top,
                width: styles.width + (styles.stroke.size*2),
                zIndex: 10
            }
        }).inject(el, 'after');

        var canvas = new Element('canvas', {
            height: styles.height + styles.tip.height + (styles.stroke.size*2) + (styles.padding.y*2),
            width: styles.width + (styles.stroke.size*2)
        }).inject(canvasHolder);

        canvasHolder.adopt(
            new Element('p', {
                'class': 'speech-balloon-content',
                html: this.getTitle(el),
                styles: {
                    height: styles.height,
                    left: styles.padding.x + styles.stroke.size,
                    top: styles.padding.y + styles.stroke.size,
                    width: styles.width - styles.padding.x - styles.stroke.size
                }
            })
        );

        // create overlay
        new Element('span', {
            'class': 'balloon-overlay',
            styles: {
                height: dim.height,
                left: dim.left,
                position: 'absolute',
                top: dim.top,
                width: dim.width,
                zIndex: 11
            }
        }).inject(canvasHolder, 'after');

        this.draw(canvas, styles);
    },

    draw: function(canvas, styles)
    {
        if(window.window.ActiveXObject)
        {
            G_vmlCanvasManager.initElement(canvas);
        }

        var objCanvas = canvas;
        
        if(objCanvas.getContext){
            var objContext = objCanvas.getContext('2d');

            objContext.beginPath();

            objContext.moveTo(styles.cornerRadius, 0);
            objContext.quadraticCurveTo(
                0, 0,
                0, styles.cornerRadius
            );
            
            objContext.lineTo(0, styles.height - styles.cornerRadius);
            objContext.quadraticCurveTo(
                0, styles.height + (styles.padding.y*2),
                styles.cornerRadius, styles.height + (styles.padding.y*2)
            );

            // TIP
            objContext.lineTo(
                ((styles.width/2) - styles.tip.width).round(),
                styles.height + (styles.padding.y*2)
            );           
            objContext.lineTo(
                (styles.width/2).round(),
                styles.height + styles.tip.height + (styles.padding.y*2)
            );
            objContext.lineTo(
                ((styles.width/2) + styles.tip.width).round(),
                styles.height + (styles.padding.y*2)
            );
            /*objContext.lineTo(
                styles.width - styles.cornerRadius,
                styles.height + (styles.padding.y*2)
            );*/
            // !TIP

            /*objContext.quadraticCurveTo(
                0, styles.height + (styles.padding.y*2),
                styles.width-styles.cornerRadius, styles.height + (styles.padding.y*2)
            );*/

            objContext.lineTo(styles.width-styles.cornerRadius, styles.height + (styles.padding.y*2));
            
            objContext.quadraticCurveTo(
                styles.width, styles.height + (styles.padding.y*2),
                styles.width, styles.height - styles.cornerRadius + (styles.padding.y*2)
            );
            objContext.lineTo(styles.width, styles.cornerRadius);
            objContext.quadraticCurveTo(
                styles.width, 0,
                styles.width-styles.cornerRadius, 0
            );

            objContext.closePath();

            // Background
            if(styles.background[1].match('#'))
            {
                var objGradient = objContext.createLinearGradient(
                    0 + styles.stroke.size,
                    0,
                    0,
                    styles.height + (styles.padding.y*2) + styles.tip.height
                );

                objGradient.addColorStop(0, styles.background[0]);
                objGradient.addColorStop(1, styles.background[1]);

                objContext.fillStyle = objGradient;    
            }
            else
            {
                objContext.fillStyle = this.styles.background;
            }
            objContext.fill();

            objContext.strokeStyle = styles.stroke.color;
            objContext.lineWidth = styles.stroke.size;
            objContext.stroke();
        }

    }   
    
});