(function (root, initialize){

var Bionya = initialize();
if(typeof define !== "undefined" && define.amd)define(Bionya);
root.Bionya = Bionya;

}(this, function(){

//modules here

/**

* @license almond 0.2.9 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved.
* Available via the MIT or new BSD license.
* see: http://github.com/jrburke/almond for details
*/

//Going sloppy to avoid ‘use strict’ string cost, but strict practices should //be followed. /*jslint sloppy: true */ /*global setTimeout: false */

var requirejs, require, define; (function (undef) {

var main, req, makeMap, handlers,
    defined = {},
    waiting = {},
    config = {},
    defining = {},
    hasOwn = Object.prototype.hasOwnProperty,
    aps = [].slice,
    jsSuffixRegExp = /\.js$/;

function hasProp(obj, prop) {
    return hasOwn.call(obj, prop);
}

/**
 * Given a relative module name, like ./something, normalize it to
 * a real name that can be mapped to a path.
 * @param {String} name the relative name
 * @param {String} baseName a real name that the name arg is relative
 * to.
 * @returns {String} normalized name
 */
function normalize(name, baseName) {
    var nameParts, nameSegment, mapValue, foundMap, lastIndex,
        foundI, foundStarMap, starI, i, j, part,
        baseParts = baseName && baseName.split("/"),
        map = config.map,
        starMap = (map && map['*']) || {};

    //Adjust any relative paths.
    if (name && name.charAt(0) === ".") {
        //If have a base name, try to normalize against it,
        //otherwise, assume it is a top-level require that will
        //be relative to baseUrl in the end.
        if (baseName) {
            //Convert baseName to array, and lop off the last part,
            //so that . matches that "directory" and not name of the baseName's
            //module. For instance, baseName of "one/two/three", maps to
            //"one/two/three.js", but we want the directory, "one/two" for
            //this normalization.
            baseParts = baseParts.slice(0, baseParts.length - 1);
            name = name.split('/');
            lastIndex = name.length - 1;

            // Node .js allowance:
            if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
                name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
            }

            name = baseParts.concat(name);

            //start trimDots
            for (i = 0; i < name.length; i += 1) {
                part = name[i];
                if (part === ".") {
                    name.splice(i, 1);
                    i -= 1;
                } else if (part === "..") {
                    if (i === 1 && (name[2] === '..' || name[0] === '..')) {
                        //End of the line. Keep at least one non-dot
                        //path segment at the front so it can be mapped
                        //correctly to disk. Otherwise, there is likely
                        //no path mapping for a path starting with '..'.
                        //This can still fail, but catches the most reasonable
                        //uses of ..
                        break;
                    } else if (i > 0) {
                        name.splice(i - 1, 2);
                        i -= 2;
                    }
                }
            }
            //end trimDots

            name = name.join("/");
        } else if (name.indexOf('./') === 0) {
            // No baseName, so this is ID is resolved relative
            // to baseUrl, pull off the leading dot.
            name = name.substring(2);
        }
    }

    //Apply map config if available.
    if ((baseParts || starMap) && map) {
        nameParts = name.split('/');

        for (i = nameParts.length; i > 0; i -= 1) {
            nameSegment = nameParts.slice(0, i).join("/");

            if (baseParts) {
                //Find the longest baseName segment match in the config.
                //So, do joins on the biggest to smallest lengths of baseParts.
                for (j = baseParts.length; j > 0; j -= 1) {
                    mapValue = map[baseParts.slice(0, j).join('/')];

                    //baseName segment has  config, find if it has one for
                    //this name.
                    if (mapValue) {
                        mapValue = mapValue[nameSegment];
                        if (mapValue) {
                            //Match, update name to the new value.
                            foundMap = mapValue;
                            foundI = i;
                            break;
                        }
                    }
                }
            }

            if (foundMap) {
                break;
            }

            //Check for a star map match, but just hold on to it,
            //if there is a shorter segment match later in a matching
            //config, then favor over this star map.
            if (!foundStarMap && starMap && starMap[nameSegment]) {
                foundStarMap = starMap[nameSegment];
                starI = i;
            }
        }

        if (!foundMap && foundStarMap) {
            foundMap = foundStarMap;
            foundI = starI;
        }

        if (foundMap) {
            nameParts.splice(0, foundI, foundMap);
            name = nameParts.join('/');
        }
    }

    return name;
}

function makeRequire(relName, forceSync) {
    return function () {
        //A version of a require function that passes a moduleName
        //value for items that may need to
        //look up paths relative to the moduleName
        return req.apply(undef, aps.call(arguments, 0).concat([relName, forceSync]));
    };
}

function makeNormalize(relName) {
    return function (name) {
        return normalize(name, relName);
    };
}

function makeLoad(depName) {
    return function (value) {
        defined[depName] = value;
    };
}

function callDep(name) {
    if (hasProp(waiting, name)) {
        var args = waiting[name];
        delete waiting[name];
        defining[name] = true;
        main.apply(undef, args);
    }

    if (!hasProp(defined, name) && !hasProp(defining, name)) {
        throw new Error('No ' + name);
    }
    return defined[name];
}

//Turns a plugin!resource to [plugin, resource]
//with the plugin being undefined if the name
//did not have a plugin prefix.
function splitPrefix(name) {
    var prefix,
        index = name ? name.indexOf('!') : -1;
    if (index > -1) {
        prefix = name.substring(0, index);
        name = name.substring(index + 1, name.length);
    }
    return [prefix, name];
}

/**
 * Makes a name map, normalizing the name, and using a plugin
 * for normalization if necessary. Grabs a ref to plugin
 * too, as an optimization.
 */
makeMap = function (name, relName) {
    var plugin,
        parts = splitPrefix(name),
        prefix = parts[0];

    name = parts[1];

    if (prefix) {
        prefix = normalize(prefix, relName);
        plugin = callDep(prefix);
    }

    //Normalize according
    if (prefix) {
        if (plugin && plugin.normalize) {
            name = plugin.normalize(name, makeNormalize(relName));
        } else {
            name = normalize(name, relName);
        }
    } else {
        name = normalize(name, relName);
        parts = splitPrefix(name);
        prefix = parts[0];
        name = parts[1];
        if (prefix) {
            plugin = callDep(prefix);
        }
    }

    //Using ridiculous property names for space reasons
    return {
        f: prefix ? prefix + '!' + name : name, //fullName
        n: name,
        pr: prefix,
        p: plugin
    };
};

function makeConfig(name) {
    return function () {
        return (config && config.config && config.config[name]) || {};
    };
}

handlers = {
    require: function (name) {
        return makeRequire(name);
    },
    exports: function (name) {
        var e = defined[name];
        if (typeof e !== 'undefined') {
            return e;
        } else {
            return (defined[name] = {});
        }
    },
    module: function (name) {
        return {
            id: name,
            uri: '',
            exports: defined[name],
            config: makeConfig(name)
        };
    }
};

main = function (name, deps, callback, relName) {
    var cjsModule, depName, ret, map, i,
        args = [],
        callbackType = typeof callback,
        usingExports;

    //Use name if no relName
    relName = relName || name;

    //Call the callback to define the module, if necessary.
    if (callbackType === 'undefined' || callbackType === 'function') {
        //Pull out the defined dependencies and pass the ordered
        //values to the callback.
        //Default to [require, exports, module] if no deps
        deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
        for (i = 0; i < deps.length; i += 1) {
            map = makeMap(deps[i], relName);
            depName = map.f;

            //Fast path CommonJS standard dependencies.
            if (depName === "require") {
                args[i] = handlers.require(name);
            } else if (depName === "exports") {
                //CommonJS module spec 1.1
                args[i] = handlers.exports(name);
                usingExports = true;
            } else if (depName === "module") {
                //CommonJS module spec 1.1
                cjsModule = args[i] = handlers.module(name);
            } else if (hasProp(defined, depName) ||
                       hasProp(waiting, depName) ||
                       hasProp(defining, depName)) {
                args[i] = callDep(depName);
            } else if (map.p) {
                map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
                args[i] = defined[depName];
            } else {
                throw new Error(name + ' missing ' + depName);
            }
        }

        ret = callback ? callback.apply(defined[name], args) : undefined;

        if (name) {
            //If setting exports via "module" is in play,
            //favor that over return value and exports. After that,
            //favor a non-undefined return value over exports use.
            if (cjsModule && cjsModule.exports !== undef &&
                    cjsModule.exports !== defined[name]) {
                defined[name] = cjsModule.exports;
            } else if (ret !== undef || !usingExports) {
                //Use the return value from the function.
                defined[name] = ret;
            }
        }
    } else if (name) {
        //May just be an object definition for the module. Only
        //worry about defining if have a module name.
        defined[name] = callback;
    }
};

requirejs = require = req = function (deps, callback, relName, forceSync, alt) {
    if (typeof deps === "string") {
        if (handlers[deps]) {
            //callback in this case is really relName
            return handlers[deps](callback);
        }
        //Just return the module wanted. In this scenario, the
        //deps arg is the module name, and second arg (if passed)
        //is just the relName.
        //Normalize module name, if it contains . or ..
        return callDep(makeMap(deps, callback).f);
    } else if (!deps.splice) {
        //deps is a config object, not an array.
        config = deps;
        if (config.deps) {
            req(config.deps, config.callback);
        }
        if (!callback) {
            return;
        }

        if (callback.splice) {
            //callback is an array, which means it is a dependency list.
            //Adjust args if there are dependencies
            deps = callback;
            callback = relName;
            relName = null;
        } else {
            deps = undef;
        }
    }

    //Support require(['a'])
    callback = callback || function () {};

    //If relName is a function, it is an errback handler,
    //so remove it.
    if (typeof relName === 'function') {
        relName = forceSync;
        forceSync = alt;
    }

    //Simulate async callback;
    if (forceSync) {
        main(undef, deps, callback, relName);
    } else {
        //Using a non-zero value because of concern for what old browsers
        //do, and latest browsers "upgrade" to 4 if lower value is used:
        //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
        //If want a value immediately, use require('id') instead -- something
        //that works in almond on the global level, but not guaranteed and
        //unlikely to work in other AMD implementations.
        setTimeout(function () {
            main(undef, deps, callback, relName);
        }, 4);
    }

    return req;
};

/**
 * Just drops the config on the floor, but returns req in case
 * the config return value is used.
 */
req.config = function (cfg) {
    return req(cfg);
};

/**
 * Expose module registry for debugging and tooling
 */
requirejs._defined = defined;

define = function (name, deps, callback) {

    //This module may not have dependencies
    if (!deps.splice) {
        //deps is not an array, so probably means
        //an object literal or factory function for
        //the value. Adjust args.
        callback = deps;
        deps = [];
    }

    if (!hasProp(defined, name) && !hasProp(waiting, name)) {
        waiting[name] = [name, deps, callback];
    }
};

define.amd = {
    jQuery: true
};

}());

define(“contrib/almond/almond”, function(){});

define(‘tools’,[], function(){

var Tools = {
    STL: Nyaplot.STL,
    _: Nyaplot._,
    uuid: Nyaplot.uuid,
    Manager: Nyaplot.Manager
};

return Tools;

});

define(‘components/scale’,, function(Tools){

var _ = Tools._;

function scale(domains, ranges, _options){
    var width = Math.abs(ranges.x[1] - ranges.x[0]);
    var height = Math.abs(ranges.y[1] - ranges.y[0]);

    this.scales = {};
    this.center = {x: width/2, y: height/2};
    this.max_r = Math.min(width, height)/2;
    return this;
}

scale.prototype.init = function(inner_radius, outer_radius, inner_num, outer_num){
    this.inner_radius = inner_radius;
    this.outer_radius = outer_radius;
    this.inner_num = inner_num;
    this.outer_num = outer_num;
    this.inner_thickness = inner_radius/(inner_num+1);
    this.outer_thickness = (this.max_r - outer_radius)/outer_num;
};

scale.prototype.addGroup = function(name, axis, startAngle, endAngle){
    var scale = d3.scale.ordinal().domain(axis).rangePoints([startAngle, endAngle], 1);
    this.scales[name] = scale;
    this.width = (endAngle - startAngle)/(axis.length+1);
};

scale.prototype.groups = function(){
    return _.keys(this.scales);
};

scale.prototype.getWidth = function(){
    return this.width;
};

scale.prototype.getHeight = function(layer){
    if(layer >= 0)return this.outer_thickness;
    else return this.inner_thickness;
};

scale.prototype.getCenter = function(){
    return this.center;
};

scale.prototype.getRange = function(layer){
    var min, max;
    if(layer > 0){
        min = this.outer_radius + this.outer_thickness*(layer-1);
        max = min + this.outer_thickness;
    }else{
        max = this.inner_radius;
        min = max - this.inner_thickness;
    }
    return [min, max];
};

scale.prototype.get = function(layer, group, x){
    var r, theta;
    if(layer > 0)r = this.outer_radius + this.outer_thickness*layer;
    else r = this.inner_radius - this.inner_thickness*layer*-1;
    theta = this.scales[group](x);
    return {x: r*Math.sin(theta), y: -r*Math.cos(theta), r:r, theta:theta};
};

return scale;

});

define(‘components/axis’,, function(Tools){

function Axis(parent, scales, _options){
    var _ = Tools._;
    var Manager = Tools.Manager;

    var options = {
        width:0,
        height:0,
        margin: {top:0,bottom:0,left:0,right:0},
        x_label:'X',
        y_label:'Y',
        zoom:true,
        zoom_range:[0.5, 5],
        rotate_x_label:0,
        rotate_y_label:0,
        pane_uuid: null,
        z_index:0,
        extra: {}
    };

    var options_extra = {
        df_id: null,
        inner_radius: 150,
        outer_radius: 170,
        group_by: null,
        fill_by: null,
        axis: null,
        chord: false,
        matrix: null,
        padding: 0.05,
        inner_num: 0,
        outer_num: 1,
        color: ['#253494'],
        text_color: '#fff',
        text_size: '1em'
    };

    if(arguments.length>2){
        _.extend(options, _options);
        _.extend(options_extra, _options.extra);
        options.extra = options_extra;
    }

    var df = Manager.getData(options.extra.df_id);
    var groups = df.column(options.extra.group_by);
    var axies = {};
    var matrix = (options.extra.chord ? options.extra.matrix: []);

    var fill_scale = (function(){
        if(options.extra.fill_by){
            var scale = df.scale(options.extra.fill_by, options.extra.color);
            var pairs = _.zip.apply(null, _.map(df.column(options.extra.fill_by), function(val, i){
                return [i, scale(val)];
            }));
            return d3.scale.ordinal().domain(pairs[0]).range(pairs[1]);
        }else{
            return d3.scale.ordinal().range(options.extra.color);
        }
    })();

    _.each(groups, function(group, i){
        var axis = df.nested_column(i, options.extra.axis);
        axies[group] = axis;
        if(options.extra.matrix==null){
            matrix[i] = [];
            for(var j=0; j<groups.length; j++){
                if(j==i)matrix[i][j] = axis.length;
                else matrix[i][j] = 0;
            }
        }
    });

    var chord = d3.layout.chord().padding(options.extra.padding).matrix(matrix);
    var model = parent.append("g").attr('transform', 'translate(' + options.width/2 + ',' + options.height/2 + ')');
    var clip_id = "clip" + options.pane_uuid;

    model.append("clipPath")
        .attr("id", clip_id)
        .append("rect")
        .attr({
            "x": -options.width/2,
            "y": -options.height/2,
            "width": options.width,
            "height": options.height
        });

    model
        .attr("clip-path", "url(#" + clip_id + ")")
        .style("z-index", options.z_index);

    var prefix = options.pane_uuid + "group";

    // group arcs
    model.append("g")
        .selectAll("g")
        .data(chord.groups)
        .enter().append("g")
        .attr("class", "group_arcs")
        .append("path")
        .style("fill", function(d){return fill_scale(d.index);})
        .style("stroke", function(d){return fill_scale(d.index);})
        .attr("d", d3.svg.arc()
              .innerRadius(options.extra.inner_radius)
              .outerRadius(options.extra.outer_radius))
        .attr("id", function(d, i){return prefix+i;});

    // labels for group arcs
    model.selectAll(".group_arcs")
        .append("text")
        .attr("x",6)
        .attr("dy",15)
        .append("textPath")
        .attr("xlink:href", function(d,i){return "#" + prefix + i;})
        .text(function(d,i){return groups[i];})
        .attr("fill", options.extra.text_color)
        .attr("font-size", options.extra.text_size);

    // chord
    if(options.extra.chord){
        model.append("g").selectAll("path")
            .data(chord.chords)
            .enter().append("path")
            .attr("d", d3.svg.chord().radius(options.extra.inner_radius))
            .style("fill", "#fff");
    }

    // scales
    scales.init(
        options.extra.inner_radius, options.extra.outer_radius,
        options.extra.inner_num, options.extra.outer_num);

    model.selectAll(".group_arcs").each(function(d, i){
        scales.addGroup(groups[i], axies[groups[i]], d.startAngle, d.endAngle);
    });

    // tick
    var tick_data = _.flatten(_.map(axies, function(x_arr, group){
        return _.map(x_arr, function(x){
            return scales.get(0, group, x);
        });
    }));

    // dirty code. should be modified soon.
    if(options.zoom){
        parent.call(
            d3.behavior.zoom()
                .scaleExtent(options.zoom_range)
                .on("zoom", function(){
                    var translate = d3.event.translate;
                    var scale = d3.event.scale;
                    parent.select(".context_child").attr('transform', 'translate(' + translate + ') scale(' + scale + ')');
                    translate[0] += (scale-1)*options.width/2;
                    translate[1] += (scale-1)*options.height/2;
                    model.select("g").attr('transform', 'translate(' + translate + ') scale(' + scale + ')');
                }));
    }
}

return Axis;

});

define(‘diagrams/arc’,, function(Tools){

var _ = Tools._;
var Manager = Tools.Manager;

function Arc(parent, scales, df_id, _options){
    var options = {
        range: [0, 0],
        width: 0.5,
        color: ['rgb(166,206,227)', 'rgb(31,120,180)', 'rgb(178,223,138)', 'rgb(51,160,44)', 'rgb(251,154,153)', 'rgb(227,26,28)', 'rgb(253,191,111)', 'rgb(255,127,0)' ,'rgb(202,178,214)'],
        fill_by: null,
        x: null,
        y: null,
        layer: 1,
        axis: true
    };
    if(arguments.length>3)_.extend(options, _options);

    this.height_scale = (function(){
        var height = scales.getHeight(options.layer);
        return d3.scale.linear().domain(options.range).range([0, height]);
    })();

    this.inner_radius = scales.getRange(options.layer)[0];
    this.model = (function(){
        var center = scales.getCenter();
        return parent.append("g").attr('transform', 'translate(' + center.x + ',' + center.y + ')');
    })();
    this.scales = scales;
    this.df = Manager.getData(df_id);
    this.color_scale = d3.scale.ordinal().range(options.color);
    this.uuid = options.uuid;
    this.options = options;

    return this;
};

Arc.prototype.update = function(){
    var groups = this.scales.groups();
    var thisObj = this;

    if(this.options.axis){
        (function(){
            var values = thisObj.height_scale.ticks(5);
            values.reverse().pop();

            var group = thisObj.model
                .append("g")
                .selectAll("g")
                .data(values)
                .enter()
                .append("g");

            group.append("circle")
                .attr("fill", "none")
                .attr("stroke", "#000")
                .attr("r", function(d){return thisObj.inner_radius + thisObj.height_scale(d);});

            group.append("text")
                .attr("y", function(d){return -1*(thisObj.inner_radius + thisObj.height_scale(d) + 4);})
                .text(function(d){return d;});
        })();
    }

    _.each(groups, function(group, i){
        var x = thisObj.df.nested_column(i, thisObj.options.x);
        var y = thisObj.df.nested_column(i, thisObj.options.y);
        var fill_scale = (function(){
            var color = thisObj.options.color;
            if(thisObj.options.fill_by){
                var fill_by = thisObj.options.fill_by;
                var scale = thisObj.df.scale(fill_by, color);
                var pairs = _.zip.apply(null, _.map(thisObj.df.column(fill_by), function(val, i){
                    return [i, scale(val)];
                }));
                return d3.scale.ordinal().domain(pairs[0]).range(pairs[1]);
            }else{
                return d3.scale.ordinal().range(color);
            }
        })();
        var data = thisObj.processData(group, x, y, fill_scale);
        thisObj.updateModels(data);
    });
};

Arc.prototype.processData = function(group, x_arr, y_arr, fill_scale){
    var thisObj = this;
    return _.map(x_arr, function(x, i){
        var hash = thisObj.scales.get(thisObj.options.layer, group, x);
        hash['height'] = thisObj.height_scale(y_arr[i]);
        hash['fill'] = fill_scale(i);
        return hash;
    });
};

Arc.prototype.updateModels = function(data){
    var baseline = this.height_scale(0);
    var inner_radius = this.inner_radius;
    var width = this.scales.getWidth() * this.options.width;

    this.model.append("g")
        .selectAll("path")
        .data(data)
        .enter()
        .append("path")
        .attr("d", d3.svg.arc()
              .startAngle(function(d){return d.theta - width/2;})
              .endAngle(function(d){return d.theta + width/2;})
              .innerRadius(inner_radius + baseline)
              .outerRadius(function(d){return inner_radius + d.height;}))
        .attr("stroke", function(d){return d.fill;})
        .attr("fill", function(d){return d.fill;});
};

Arc.prototype.getLegend = function(){
};

Arc.prototype.checkSelectedData = function(ranges){
    return;
};

return Arc;

});

define(‘diagrams/connector’,, function(Tools){

var _ = Tools._;
var Manager = Tools.Manager;

function Connector(parent, scales, df_id, _options){
    var options = {
        color: "#737373",
        fill_by: null,
        from: null,
        to: null,
        shape: 'circle',
        stroke_width: 2,
        size: 100,
        shape_fill: '#fff',
        shape_stroke: '#3182bd',
        shape_stroke_width: 2,
        arc_height: 30,
        layer: 0
    };
    if(arguments.length>3)_.extend(options, _options);

    this.model = (function(){
        var center = scales.getCenter();
        return parent.append("g").attr('transform', 'translate(' + center.x + ',' + center.y + ')');
    })();

    this.scales = scales;
    this.df = Manager.getData(df_id);
    this.uuid = options.uuid;
    this.options = options;
}

Connector.prototype.update = function(){
    var from = this.df.column(this.options.from);
    var to = this.df.column(this.options.to);
    var data = this.processData(from, to);
    this.updateModels(data);
};

Connector.prototype.processData = function(from ,to){
    var scales = this.scales, layer = this.options.layer, height = this.options.arc_height;
    return _.map(_.zip(from, to), function(row){
        var points = _.map(row, function(str){
            var strs = str.split(/(.+)\.(.+)/);
            var group = strs[1], x = strs[2];
            var point = scales.get(layer, group, x);
            return {x: point.x, y: point.y};
        });

        var mid = (function(){
            var center = _.map(['x', 'y'], function(label){
                return (points[0][label] + points[1][label])/2;
            });
            var abs = Math.sqrt(center[0]*center[0] + center[1]*center[1]);
            var norm = _.map(center, function(c){return c/abs;});
            return ({x: norm[0]*(abs - height), y:norm[1]*(abs - height)});
        })();

        return [points[0], mid ,points[1]];
    });

};

Connector.prototype.updateModels = function(data){
    var scales = this.scales;
    var layer = this.layer;
    var options = this.options;

    var groups = this.model.selectAll("g")
            .data(data)
            .enter()
            .append("g");

    groups.append("path")
        .attr("d", d3.svg.line()
              .tension(0.2)
              .x(function(d){return d.x;})
              .y(function(d){return d.y;})
              .interpolate("cardinal"))
        .attr("fill", "none")
        .attr("stroke", options.color)
        .attr("stroke-width", options.stroke_width);

    groups.append("g")
        .selectAll("path")
        .data(_.filter(_.flatten(data), function(val, i){return i%3 != 1;}))
        .enter()
        .append("path")
        .attr("d" ,d3.svg.symbol().type(options.shape).size(options.size))
        .attr("fill", options.shape_fill)
        .attr("stroke", options.shape_stroke)
        .attr("stroke-width", options.shape_stroke_width)
        .attr("transform", function(d){return 'translate(' + d.x + ',' + d.y + ')';});
};

Connector.prototype.getLegend = function(){
    return;
};

Connector.prototype.checkSelectedData = function(ranges){
    return;
};

return Connector;

});

define(‘diagrams/labels’,, function(Tools){

var _ = Tools._;
var Manager = Tools.Manager;

function Labels(parent, scales, df_id, _options){
    var options = {
        color: "#000",
        fill_by: null,
        x: null,
        text: null,
        stroke_width: 4,
        text_size: '1em',
        layer: 1
    };
    if(arguments.length>3)_.extend(options, _options);

    this.model = (function(){
        var center = scales.getCenter();
        return parent.append("g").attr('transform', 'translate(' + center.x + ',' + center.y + ')');
    })();

    this.scales = scales;
    this.df = Manager.getData(df_id);
    this.uuid = options.uuid;
    this.options = options;
}

Labels.prototype.update = function(){
    var groups = this.scales.groups();
    var thisObj = this;
    _.each(groups, function(group, i){
        var x = thisObj.df.nested_column(i, thisObj.options.x);
        var text = thisObj.df.nested_column(i, thisObj.options.text);
        var data = thisObj.processData(group, x, text);
        thisObj.updateModels(data);
    });
};

Labels.prototype.processData = function(group, x, text){
    var scales = this.scales, layer = this.options.layer;
    return _.filter(_.map(_.zip(x, text), function(row){
        return {theta: scales.get(layer, group, row[0]).theta,text: row[1]};
    }), function(row){return row.text != null && row.text.length > 0;});
};

Labels.prototype.updateModels = function(data){
    var scales = this.scales, layer = this.options.layer, options = this.options;
    var inner_radius = scales.getRange(layer)[0];

    var groups = this.model.append("g")
            .selectAll("g")
            .data(data)
            .enter()
            .append("g")
            .attr("transform", function(d){
                return "rotate(" + 180*((d.theta-Math.PI/2)/Math.PI) + ")";
            });

    groups.append("text")
        .text(function(d){return d.text;})
        .attr("text-anchor", "start")
        .attr("dominant-baseline", "middle")
        .attr("fill", options.color)
        .attr("x", inner_radius + 10)
        .attr("y", 0)
        .attr("font-size", options.text_size);

    groups.append("line")
        .attr("x1", inner_radius)
        .attr("x2", inner_radius + 5)
        .attr("y1", 0)
        .attr("y2", 0)
        .attr("stroke", "#000");
};

Labels.prototype.getLegend = function(){
    return;
};

Labels.prototype.checkSelectedData = function(ranges){
    return;
};

return Labels;

});

define(‘main’,,function(require, exports, module){

var Bionya = {};
Bionya.Nya = {
    'scale':require('components/scale'),
    'axis':require('components/axis'),
    'diagrams': {
        'arc': require('diagrams/arc'),
        'connector': require('diagrams/connector'),
        'labels': require('diagrams/labels')
    }
};

return Bionya;

});

return require(‘main’); }));