Raphael.fn.g.piechart = function (e, d, o, b, l) {
    l = l || {};
    var k = this,
        m = [],
        g = this.set(),
        n = this.set(),
        j = this.set(),
        u = [],
        w = b.length,
        x = 0,
        A = 0,
        z = 0,
        c = 9,
        y = true;
    n.covers = g;
    if (w == 1) {
        j.push(this.circle(e, d, o).attr({
            fill: this.g.colors[0],
            stroke: l.stroke || "#fff",
            "stroke-width": l.strokewidth == null ? 1 : l.strokewidth
        }));
        g.push(this.circle(e, d, o).attr(this.g.shim));
        A = b[0];
        b[0] = {
            value: b[0],
            order: 0,
            valueOf: function () {
                return this.value;
            }
        };
        j[0].middle = {
            x: e,
            y: d
        };
        j[0].mangle = 180;
    } else {
        function t(F, E, i, H, D, M) {
            var J = Math.PI / 180,
                B = F + i * Math.cos(-H * J),
                p = F + i * Math.cos(-D * J),
                G = F + i / 2 * Math.cos(-(H + (D - H) / 2) * J),
                L = E + i * Math.sin(-H * J),
                K = E + i * Math.sin(-D * J),
                C = E + i / 2 * Math.sin(-(H + (D - H) / 2) * J),
                I = ["M", F, E, "L", B, L, "A", i, i, 0, +(Math.abs(D - H) > 180), 1, p, K, "z"];
            I.middle = {
                x: G,
                y: C
            };
            return I;
        }
        for (var v = 0; v < w; v++) {
            A += b[v];
            b[v] = {
                value: b[v],
                order: v,
                valueOf: function () {
                    return this.value;
                }
            };
        }
        b.sort(function (p, i) {
            return i.value - p.value;
        });
        for (v = 0; v < w; v++) {
            if (y && b[v] * 360 / A <= 1.5) {
                c = v;
                y = false;
            }
            if (v > c) {
                y = false;
                b[c].value += b[v];
                b[c].others = true;
                z = b[c].value;
            }
        }
        w = Math.min(c + 1, b.length);
        z && b.splice(w) && (b[c].others = true);
        for (v = 0; v < w; v++) {
            var f = x - 360 * b[v] / A / 2;
            if (!v) {
                x = 90 - f;
                f = x - 360 * b[v] / A / 2;
            }
            if (l.init) {
                var h = t(e, d, 1, x, x - 360 * b[v] / A).join(",");
            }
            var s = t(e, d, o, x, x -= 360 * b[v] / A);
            var q = this.path(l.init ? h : s).attr({
                fill: l.colors && l.colors[v] || this.g.colors[v] || "#666",
                stroke: l.stroke || "#fff",
                "stroke-width": (l.strokewidth == null ? 1 : l.strokewidth),
                "stroke-linejoin": "round"
            });
            q.value = b[v];
            q.middle = s.middle;
            q.mangle = f;
            m.push(q);
            j.push(q);
            l.init && q.animate({
                path: s.join(",")
            }, (+l.init - 1) || 1000, ">");
        }
        for (v = 0; v < w; v++) {
            q = k.path(m[v].attr("path")).attr(this.g.shim);
            l.href && l.href[v] && q.attr({
                href: l.href[v]
            });
            q.attr = function () {};
            g.push(q);
            j.push(q);
        }
    }
    n.hover = function (C, r) {
        r = r ||
        function () {};
        var B = this;
        for (var p = 0; p < w; p++) {
            (function (D, E, i) {
                var F = {
                    sector: D,
                    cover: E,
                    cx: e,
                    cy: d,
                    mx: D.middle.x,
                    my: D.middle.y,
                    mangle: D.mangle,
                    r: o,
                    value: b[i],
                    total: A,
                    label: B.labels && B.labels[i]
                };
                E.mouseover(function () {
                    C.call(F);
                }).mouseout(function () {
                    r.call(F);
                });
            })(j[p], g[p], p);
        }
        return this;
    };
    n.each = function (B) {
        var r = this;
        for (var p = 0; p < w; p++) {
            (function (C, D, i) {
                var E = {
                    sector: C,
                    cover: D,
                    cx: e,
                    cy: d,
                    x: C.middle.x,
                    y: C.middle.y,
                    mangle: C.mangle,
                    r: o,
                    value: b[i],
                    total: A,
                    label: r.labels && r.labels[i]
                };
                B.call(E);
            })(j[p], g[p], p);
        }
        return this;
    };
    n.click = function (B) {
        var r = this;
        for (var p = 0; p < w; p++) {
            (function (C, D, i) {
                var E = {
                    sector: C,
                    cover: D,
                    cx: e,
                    cy: d,
                    mx: C.middle.x,
                    my: C.middle.y,
                    mangle: C.mangle,
                    r: o,
                    value: b[i],
                    total: A,
                    label: r.labels && r.labels[i]
                };
                D.click(function () {
                    B.call(E);
                });
            })(j[p], g[p], p);
        }
        return this;
    };
    n.inject = function (i) {
        i.insertBefore(g[0]);
    };
    var a = function (G, B, r, p) {
        var K = e + o + o / 5,
            J = d,
            F = J + 10;
        G = G || [];
        p = (p && p.toLowerCase && p.toLowerCase()) || "east";
        r = k.g.markers[r && r.toLowerCase()] || "disc";
        n.labels = k.set();
        for (var E = 0; E < w; E++) {
            var L = j[E].attr("fill"),
                C = b[E].order,
                D;
            b[E].others && (G[C] = B || "Others");
            G[C] = k.g.labelise(G[C], b[E], A);
            n.labels.push(k.set());
            n.labels[E].push(k.g[r](K + 5, F, 5).attr({
                fill: L,
                stroke: "none"
            }));
            n.labels[E].push(D = k.text(K + 20, F, G[C] || b[C]).attr(k.g.txtattr).attr({
                fill: l.legendcolor || "#000",
                "text-anchor": "start"
            }));
            g[E].label = n.labels[E];
            F += D.getBBox().height * 1.2;
        }
        var H = n.labels.getBBox(),
            I = {
                east: [0, -H.height / 2],
                west: [-H.width - 2 * o - 40, -H.height / 2],
                north: [-o - H.width / 2, -o - H.height - 10],
                south: [-o - H.width / 2, o + 10]
            }[p];
        n.labels.translate.apply(n.labels, I);
        n.push(n.labels);
    };
    if (l.legend) {
        a(l.legend, l.legendothers, l.legendmark, l.legendpos);
    }
    n.push(j, g);
    n.series = j;
    n.covers = g;
    return n;
};
