﻿Raphael.fn.drawWheel = function(cx, cy, r, w, values, opts) {
    opts = opts || {};

    var 
        paper = this,
        rad = Math.PI / 180,
        sectors = [],
        series = this.set(),
        chart = this.set(),
        len = values.length,
        angle = 0,
        total = 0;

    var sector = function(cx, cy, r, w, sa, ea) {
        var 
            r1 = r, r2 = r + w,
            x1 = cx + r1 * Math.sin(sa * rad), y1 = cy - r1 * Math.cos(sa * rad),
            x2 = cx + r2 * Math.sin(sa * rad), y2 = cy - r2 * Math.cos(sa * rad),
            x3 = cx + r2 * Math.sin(ea * rad), y3 = cy - r2 * Math.cos(ea * rad),
            x4 = cx + r1 * Math.sin(ea * rad), y4 = cy - r1 * Math.cos(ea * rad),
            xm = cx + r1 / 2 * Math.sin(-(sa + (ea - sa) / 2) * rad),
            ym = cy + r1 / 2 * Math.cos(-(sa + (ea - sa) / 2) * rad),
            res = [
                'M', x1, y1,
                'L', x2, y2,
                'A', r2, r2, 0, +(ea - sa > 180), 1, x3, y3,
                'L', x4, y4,
                'A', r1, r1, 0, +(ea - sa > 180), 0, x1, y1
            ];

        res.middle = { x: xm, y: ym };
        return res;
    };

    var labelise = function(label, val, total) {
        if (label) {
            return (label + '').replace(/(##+(?:\.#+)?)|(%%+(?:\.%+)?)/g, function(all, value, percent) {
                if (value) return (+val).toFixed(value.replace(/^#+\.?/g, '').length);
                if (percent) return (val * 100 / total).toFixed(percent.replace(/^%+\.?/g, '').length) + '%';
            });
        } else {
            return (+val).toFixed(0);
        }
    };

    var legend = function(labels) {
        var 
            top = cy + r + w + 15,
            x = 10, y = top,
            mw = 0, bb;

        labels = labels || [];
        chart.labels = paper.set();

        for (var i = 0; i < len; i++) {
            labels[i] = labelise(labels[i], values[i], total);

            bb = paper.text(x + 15, y, labels[i] || values[i]).attr({ font: '10px Arial, sans-serif', fill: 'none' }).getBBox(); ;
            mw = Math.max(mw, (bb.width + 25));
            if (y + bb.height > paper.paperHeight) {
                x += mw;
                mw = 0;
                y = top;
            }

            chart.labels.push(paper.set());
            chart.labels[i].push(paper.circle(x + 4, y, 4).attr({ 'fill': series[i].attr('fill'), 'stroke': 'none' }));
            chart.labels[i].push(paper.text(x + 15, y, labels[i] || values[i]).attr({ font: '10px Arial, sans-serif', fill: opts.legendcolor || '#000', 'text-anchor': 'start' }));
            y += bb.height * 1.2;
        }
        chart.push(chart.labels);
    };

    for (var i = 0; i < len; i++) {
        total += values[i];
    }
    for (var i = 0; i < len; i++) {
        var 
            mangle = angle - 360 * values[i] / total / 2,
            path = sector(cx, cy, r, w, angle, angle += 360 * values[i] / total),
            p = this.path(path).attr({
                'fill': opts.colors && opts.colors[i] || 'hsb(' + i / 10 + ', 1, .95)',
                'stroke': opts.stroke || 'none',
                'stroke-width': (opts.strokewidth == null ? 1 : opts.strokewidth)
            });

        p.value = values[i];
        p.middle = path.middle;
        p.mangle = mangle;
        sectors.push(p);
        series.push(p);
    }

    chart.hover = function(fin, fout) {
        fout = fout || function() { };
        var that = this;
        for (var i = 0; i < len; i++) {
            (function(sector, j) {
                var o = {
                    sector: sector,
                    cx: cx,
                    cy: cy,
                    mx: sector.middle.x,
                    my: sector.middle.y,
                    mangle: sector.mangle,
                    r: r,
                    value: values[j],
                    total: total,
                    label: that.labels && that.labels[j]
                };
                sector.mouseover(function() {
                    fin.call(o);
                }).mouseout(function() {
                    fout.call(o);
                });
            })(series[i], i);
        }
        return this;
    };

    chart.each = function(f) {
        var that = this;
        for (var i = 0; i < len; i++) {
            (function(sector, j) {
                var o = {
                    sector: sector,
                    cx: cx,
                    cy: cy,
                    x: sector.middle.x,
                    y: sector.middle.y,
                    mangle: sector.mangle,
                    r: r,
                    value: values[j],
                    total: total,
                    label: that.labels && that.labels[j]
                };
                f.call(o);
            })(series[i], i);
        }
        return this;
    };

    chart.click = function(f) {
        var that = this;
        for (var i = 0; i < len; i++) {
            (function(sector, j) {
                var o = {
                    sector: sector,
                    cx: cx,
                    cy: cy,
                    mx: sector.middle.x,
                    my: sector.middle.y,
                    mangle: sector.mangle,
                    r: r,
                    value: values[j],
                    total: total,
                    label: that.labels && that.labels[j]
                };
                sector.click(function() { f.call(o); });
            })(series[i], i);
        }
        return this;
    };

    if (opts.legend) {
        legend(opts.legend, opts.legendmark);
    }

    chart.push(series);
    chart.series = series;
    return chart;
};

function displayFlavors() {
    jQuery('div.flavor').each(function() {
        var 
            $flavor = jQuery(this),
            values = [],
            labels = [],
            colors = [];

        $flavor.find('dt').each(function() {
            var $dt = jQuery(this);
            var colorInput = $dt.find('input');
            colors.push((colorInput.length > 0) ? colorInput.val() : null);

            labels.push($.trim($dt.text()));
            values.push(parseInt($dt.next('dd').text(), 10));
        });
        if (!values.length) return;

        var $dl = $flavor.find('dl');
        var ctnr = $dl.before('<div/>').prev()[0];

        var w = 150, h = 130;
        var cx = w / 2, cy = h / 2 - 20;
        var r = 20;

        var p = Raphael(ctnr, w, h);
        p.paperWidth = w;
        p.paperHeight = h;

        /*
        p.rect(0, 0, w-1, h-1).attr({stroke: '#00f', 'stroke-opacity': 0.5});
        p.path(['M', 0, cy, 'L', w, cy].join(',')).attr({stroke: '#0f0', 'stroke-opacity': 0.3});
        p.path(['M', cx, 0, 'L', cx, h].join(',')).attr({stroke: '#0f0', 'stroke-opacity': 0.3});
        */

        var wheel = p.drawWheel(cx, cy, 20, 20, values, { colors: colors, legend: labels });
        $dl.remove();

        wheel.hover(function() {
            this.sector.stop();
            this.sector.animate({ scale: [1.1, 1.1, this.cx, this.cy] }, 500, 'elastic');
            if (this.label) {
                this.label.stop();
                this.label[0].scale(1.5);
                this.label.attr({ 'font-weight': 800 });
            }
        }, function() {
            this.sector.animate({ scale: [1, 1, this.cx, this.cy] }, 500, 'bounce');
            if (this.label) {
                this.label[0].animate({ scale: 1 }, 500, 'bounce');
                this.label.attr({ 'font-weight': 400 });
            }
        });
    });
};
