Ext.define('Ext.sparkline.VmlCanvas', {
    extend: 'Ext.sparkline.CanvasBase',
 
    constructor: function(ownerSparkLine) {
        var me = this;
 
        me.owner = ownerSparkLine;
        ownerSparkLine.element = {
            tag: 'span',
            reference: 'element',
            listeners: {
                mouseenter: 'onMouseEnter',
                mouseleave: 'onMouseLeave',
                mousemove: 'onMouseMove'
            },
            style: {
                display: 'inline-block',
                position: 'relative',
                overflow: 'hidden',
                margin: '0px',
                padding: '0px',
                verticalAlign: 'top',
                cursor: 'default'
            },
            children: [{
                tag: 'svml:group',
                reference: 'groupEl',
                coordorigin: '0 0',
                coordsize: '0 0',
                style: 'position:absolute;width:0;height:0;pointer-events:none'
            }]
        };
    },
 
    setWidth: function(width) {
        var me = this;
 
        me.callParent(arguments);
        me.owner.groupEl.dom.coordsize = me.width + ' ' + (me.height || 0);
        me.owner.groupEl.dom.style.width = width + 'px';
    },
 
    setHeight: function(height) {
        var me = this;
 
        me.callParent(arguments);
        me.owner.groupEl.dom.coordsize = (me.width || 0) + ' ' + me.height;
        me.owner.groupEl.dom.style.height = height + 'px';
    },
 
    onOwnerUpdate: function () {
        var me = this;
 
        me.group = me.owner.groupEl;
        me.el = me.owner.element;
        me.prerender = [];
    },
 
    _drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {
        var vpath = [],
            initial, stroke, fill, closed, plen, i;
 
        for (= 0, plen = path.length; i < plen; i++) {
            vpath[i] = (path[i][0]) + ',' + (path[i][1]);
        }
        initial = vpath.splice(0, 1);
        lineWidth = lineWidth == null ? 1 : lineWidth;
        stroke = lineColor == null ? ' stroked="false" ' : ' strokeWeight="' + lineWidth + 'px" strokeColor="' + lineColor + '';
        fill = fillColor == null ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
        closed = vpath[0] === vpath[vpath.length - 1] ? '' : '';
        return ['<svml:shape coordorigin="0 0" coordsize="', this.pixelWidth, ' ', this.pixelHeight,
                '" id="jqsshape', shapeid, '',
                stroke,
                fill,
            ' style="position:absolute;height:', this.pixelHeight, 'px;width:', this.pixelWidth, 'px" ',
            ' path="m ', initial, ' l ', vpath.join(''), ' ', closed, 'e"></svml:shape>'
        ].join('');
    },
 
    _drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {
        var circumference = radius * 2,
            stroke, fill;
 
        x -= radius;
        y -= radius;
        stroke = lineColor == null ? ' stroked="false" ' : ' strokeWeight="' + lineWidth + 'px" strokeColor="' + lineColor + '';
        fill = fillColor == null ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
        return ['<svml:oval id="jqsshape', shapeid, '',
            stroke,
            fill,
            ' style="position:absolute;top:', y, 'px; left:', x, 'px;width:', circumference, 'px;height:', circumference, 'px"></svml:oval>'
        ].join('');
    },
 
    _drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {
        var vpath,
            width = this.pixelWidth,
            height = this.pixelHeight,
            startx,
            starty,
            endx,
            endy,
            stroke = lineColor == null ? ' stroked="false" ' : ' strokeWeight="1px" strokeColor="' + lineColor + '',
            fill = fillColor == null ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
 
        // VML cannot handle start & end angle the same. 
        if (startAngle === endAngle) {
            return '';
        }
        if ((endAngle - startAngle) === (2 * Math.PI)) {
            startAngle = 0.0;  // VML seems to have a problem when drawing a full circle that doesn't start 0 
            endAngle = (2 * Math.PI);
        }
 
        startx = x + Math.round(Math.cos(startAngle) * radius);
        starty = y + Math.round(Math.sin(startAngle) * radius);
        endx = x + Math.round(Math.cos(endAngle) * radius);
        endy = y + Math.round(Math.sin(endAngle) * radius);
 
        if (startx === endx && starty === endy) {
            if ((endAngle - startAngle) < Math.PI) {
                // Prevent very small slices from being mistaken as a whole pie 
                return '';
            }
            // essentially going to be the entire circle, so ignore startAngle 
            startx = endx = x + radius;
            starty = endy = y;
        }
 
        if (startx === endx && starty === endy && (endAngle - startAngle) < Math.PI) {
            return '';
        }
 
        vpath = [- radius, y - radius, x + radius, y + radius, startx, starty, endx, endy];
        return ['<svml:shape coordorigin="0 0" coordsize="', width, ' ', height,
            '" id="jqsshape', shapeid, '',
            stroke,
            fill,
            ' style="position:absolute;height:', height, 'px;width:', width,
            'px" path="m ', x, ',', y, ' wa ', vpath.join(''), ' x e"></svml:shape>'
        ].join('');
    },
 
    _drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {
        return this._drawShape(shapeid, [[x, y], [x, y + height], [+ width, y + height], [+ width, y], [x, y]], lineColor, fillColor);
    },
 
    reset: function () {
        Ext.fly(this.group).empty();
    },
 
    appendShape: function (shape) {
        this.prerender.push(this['_draw' + shape.type].apply(this, shape.args));
        this.lastShapeId = shape.id;
        return shape.id;
    },
 
    replaceWithShape: function (shapeid, shape) {
        var existing = this.el.getById('jqsshape' + shapeid, true),
            vel = this['_draw' + shape.type].apply(this, shape.args);
 
        existing.outerHTML = vel;
    },
 
    replaceWithShapes: function (shapeids, shapes) {
        // replace the first shapeid with all the new shapes then toast the remaining old shapes 
        var existing = this.el.getById('jqsshape' + shapeids[0], true),
            replace = '',
            slen = shapes.length,
            i;
 
        for (= 0; i < slen; i++) {
            replace += this['_draw' + shapes[i].type].apply(this, shapes[i].args);
        }
        existing.outerHTML = replace;
        for (= 1; i < shapeids.length; i++) {
            this.el.getById('jqsshape' + shapeids[i]).destroy();
        }
    },
 
    insertAfterShape: function (shapeid, shape) {
        var existing = this.el.getById('jqsshape' + shapeid, true),
                vel = this['_draw' + shape.type].apply(this, shape.args);
        existing.insertAdjacentHTML('afterEnd', vel);
    },
 
    removeShapeId: function (shapeid) {
        var existing = this.el.getById('jqsshape' + shapeid, true);
        this.group.removeChild(existing);
    },
 
    getShapeAt: function (x, y) {
        var shapeid = this.el.id.substr(8);
        return shapeid;
    },
 
    render: function () {
        this.group.dom.innerHTML = this.prerender.join('');
    }
}, function() {
    Ext.onReady(function() {
        var doc = document;
    
        if (doc.namespaces && !doc.namespaces.svml) {
            doc.namespaces.add("svml", "urn:schemas-microsoft-com:vml", '#default#VML');
        }
    });
});