/*
* g.raphael-radar 0.3 - Radar chart, based on Raphaƫl.js
* https://github.com/Valve/g.raphael-radar
* Copyright (c) 2012 Valentin Vasilyev (iamvalentin@gmail.com)
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
*/
(function () {
    function Radar(paper, cx, cy, r, values, opts) {
        var $r = Raphael; //for minification;
        if (!values || values.length == 0) throw 'Values array is required';
        opts = opts || {};
        var startAngle = 270,
      angle = 360 / values.length;
        var defaultOpts = {
            meshSize: 30,
            labels: [],
            labelFontSize: 14,
            valueFontSize: 14,
            drawLabels: true,
            drawValues: true,
            armFill: 'none',
            armStroke: 'rgba(255, 106, 0, .5)',
            armStrokeWidth: 1,
            drawArms: true,
            meshFill: 'none',
            meshStroke: 'rgba(120, 120, 120, .5)',
            meshStrokeWidth: 1,
            drawMesh: true,
            max: Math.max.apply(Math, values),
            pathFill: 'none',
            pathStroke: '#0026ff',
            pathStrokeWidth: 3,
            pathCircleOuterRadius: 4,
            pathCircleInnerRadius: 2,
            drawPathCircles: true,
            closePath: true
        };
        //replacing default opts with explicitly provided
        for (var prop in opts) {
            defaultOpts[prop] = opts[prop];
        }
        opts = defaultOpts;
        delete defaultOpts;

        var arm = function (cx, cy, r, angle) {
            var rad = $r.rad(angle);
            var x = cx + (r * Math.cos(rad));
            var y = cy + (r * Math.sin(rad));
            return ["M", cx, cy, "L", x, y, "Z"].join(",");
        }

        var meshLine = function (cx, cy, r, startAngle, angle) {
            var mesh = ["M"];
            var circle = startAngle + 360;
            while (startAngle < circle) {
                var x = cx + r * Math.cos($r.rad(startAngle));
                var y = cy + r * Math.sin($r.rad(startAngle));
                mesh.push(x);
                mesh.push(y);
                mesh.push("L");
                startAngle += angle;
            }
            mesh.push("Z");
            return mesh.join(",");
        }

        var label = function (cx, cy, r, angle) {
            var rad = $r.rad(angle);
            var x = cx + r * Math.cos(rad);
            var y = cy + r * Math.sin(rad);
            return {
                x: (Math.round(x) === cx) ? x : (x < cx ? x - 10 : x + 10),
                y: (Math.round(y) === cy) ? y : (y < cy ? y - 10 : y + 10),
                attr: {
                    "text-anchor": (Math.round(x) === cx) ? "middle" : (x < cx ? "end" : "start"),
                    "font-size": opts.labelFontSize
                }
            };
        }

        var labelvalue = function (cx, cy, r, angle, value, max) {
            var rad = $r.rad(angle);
            var x = cx + r / max * value * Math.cos(rad);
            var y = cy + r / max * value * Math.sin(rad);
            if (Math.round(x) === cx) {
                y += 10 * Math.sin(rad);
            }

            return {
                x: (Math.round(x) === cx) ? x+2 : (x < cx ? x - 10 : x + 10),
                y: (Math.round(y) === cy) ? y-2 : (y < cy ? y - 10 : y + 10),
                attr: {
                    "text-anchor": (Math.round(x) === cx) ? "middle" : (x < cx ? "end" : "start"),
                    "font-size": opts.valueFontSize
                }
            };
        }

        var path = function (cx, cy, r, startAngle, values, max) {
            var pathData = [];
            var i = 0, l = values.length;
            while (i < l) {
                var rad = $r.rad(startAngle + 360 / values.length * i);
                pathData.push(i == 0 ? "M" : "L");
                pathData.push(cx + r / max * values[i] * Math.cos(rad));
                pathData.push(cy + r / max * values[i] * Math.sin(rad));
                ++i;
            }
            
            if (opts.closePath) {
                pathData.push("Z");
            }

            paper.path(pathData.join(",")).attr({
                "stroke": opts.pathStroke,
                "fill": opts.pathFill,
                "stroke-width": opts.pathStrokeWidth,
                "stroke-linejoin": 'round'
            });
        }

        var circle = function (cx, cy, r, angle, value, max, title) {
            var rad = $r.rad(angle);
            var p = {
                x: cx + r / max * value * Math.cos(rad),
                y: cy + r / max * value * Math.sin(rad)
            };

            paper.circle(p.x, p.y, opts.pathCircleOuterRadius * 2).attr({ fill: opts.pathStroke, stroke: 'none', title: title + ": " + value });
            paper.circle(p.x, p.y, opts.pathCircleInnerRadius * 2).attr({ fill: "#fff", stroke: "none", title: title + ": " + value });
        }

        //arms
        if (opts.drawArms) {
            var i = 0, l = values.length;
            while (i < l) {
                paper.path(arm(cx, cy, r, startAngle + angle * i)).attr({
                    fill: opts.armFill,
                    stroke: opts.armStroke,
                    "stroke-width": opts.armStrokeWidth
                });
                ++i;
            }
        }
        //mesh
        if (opts.drawMesh) {
            var meshCount = Math.floor(r / opts.meshSize);
            var meshHeight = r / meshCount;
            var meshRadius = meshHeight;
            var meshes = [];
            while (meshCount--) {
                meshes.push(meshLine(cx, cy, meshRadius, startAngle, angle));
                meshRadius += meshHeight;
            }
            var i = 0, l = meshes.length;
            while (i < l) {
                paper.path(meshes[i]).attr({
                    fill: opts.meshFill,
                    stroke: opts.meshStroke,
                    "stroke-width": opts.meshStrokeWidth
                });
                ++i;
            }
        }
        // values
        if (opts.drawValues) {
            var i = values.length;
            while (i--) {                
                var textObject = labelvalue(cx, cy, r, startAngle + angle * i, values[i], opts.max);
                var fulltext = values[i];
                var text = paper.text(textObject.x, textObject.y, fulltext).attr(textObject.attr);           

            }
        }
        //labels
        if (opts.drawLabels) {
            var i = opts.labels.length;
            while (i--) {
                var textObject = label(cx, cy, r, startAngle + angle * i);

                var fulltext = opts.labels[i]; 
                var text = paper.text(textObject.x, textObject.y, fulltext).attr(textObject.attr);
                fulltext = fulltext.replace("-", "- ").replace("/", "/ ");

                var words = fulltext.split(" ");
                var wordsCount = words.length;

                var maxwidth = Math.min(textObject.x, paper.width - textObject.x);
                var maxheight = Math.min(textObject.y, paper.height - textObject.y);

                
                var fontSizeMin = 8;
                for (var fontSize = opts.labelFontSize; fontSize >= fontSizeMin; --fontSize) {
                    text.attr("font-size", fontSize);
                    var tempText = "";
                    for (var i1 = 0; i1 < wordsCount; ++i1) {
                        text.attr("text", tempText + " " + words[i1]);
                        if (text.getBBox().width > maxwidth) {
                            tempText += "\n" + words[i1];
                        } else {
                            tempText += " " + words[i1];
                        }
                    }
                    text.attr("text", tempText);
                    if (text.getBBox().width > maxwidth) {
                        tempText = tempText.replace("-", "-\n");
                        text.attr("text", tempText);
                    }
                    if (fontSize == fontSizeMin ||
                     (text.getBBox().height <= maxheight &&
                     (text.getBBox().width <= maxwidth || wordsCount > 1))) {
                        var titleCountLines = tempText.split("\n").length;
                        text.attr("text", tempText.substring(1));
                        break;
                    }
                }
            }
        }


        path(cx, cy, r, startAngle, values, opts.max);

        //circles on path
        if (opts.drawPathCircles) {
            var i = values.length;
            while (i--) {
                circle(cx, cy, r, startAngle + angle * i, values[i], opts.max, opts.labels[i]);

            }
        }
    };
    //inheritance
    var F = function () { };
    F.prototype = Raphael.g;
    Radar.prototype = new F();

    //public
    Raphael.fn.radar = function (cx, cy, r, values, opts) {
        return new Radar(this, cx, cy, r, values, opts);
    };
})();