$(document).ready(function(){
var Eventer=function(){if(!(this instanceof Eventer))return new Eventer;this.publish=function(c,d){topics=b(c),topics.forEach(function(b){"object"==typeof a[b]&&a[b].forEach(function(a){a.apply(this,d||[])})})},this.subscribe=function(b,c){var d=[].concat(c);return d.forEach(function(c){a[b]||(a[b]=[]),a[b].push(c)}),[b,c]},this.unsubscribe=function(b,c){a[b]&&a[b].forEach(function(d,e){d==c&&a[b].splice(e,1)})},this.queue=function(){return a},this.on=this.subscribe,this.off=this.unsubscribe,this.trigger=this.publish;var a={},b=function(a){return"string"==typeof a?a.split(" "):a};return this};
var eventer = new Eventer;


var Chart = function() {

    /* -------------------------
      メニューとして表示したい名称
    ------------------------- */

    var varAll = "すべて";

    //定性的データ
    var varString1 = "メーカー名";
    var varString2 = "特徴";

    //定量的データ
    var varNum1 = "容量(g)";
    var varNum2 = "エネルギー(kcal)";
    var varNum3 = "1gあたりエネルギー(kcal)";

    //配列化
    var kirikuchiLabel = [
        varAll,
        varString1,
        varString2,
        varNum1,
        varNum2,
        varNum3
    ];

    var circleScale = 20;
    var keyString1, keyValue2;
    var varForColor;
    var labelsArray;


    /* -------------------------
      使いたい色リスト
    ------------------------- */
    var colorArray = [
        "#CA03B0",
        "#60B00A",
        "#AB1008",
        "#243753",
        "#D0ABE5",
        "#225232",
        "#F869B6",
        "#7E0B21",
        "#E96754"
    ];


    /* -------------------------
      valueNumの値をいくつかにグルーピング
    ------------------------- */

    // varNum1
    var lengthArray1 = [
        {min: 80, max: 100},
        {min: 101, max: 150},
        {min: 151, max: 220}
    ];

    // varNum2
    var lengthArray2 = [
        {min: 30, max: 90},
        {min: 91, max: 120},
        {min: 121, max: 150},
        {min: 151, max: 180}
    ];

    // varNum3
    var lengthArray3 = [
        {min: 0.0, max: 0.4},
        {min: 0.41, max: 0.80},
        {min: 0.81, max: 1.00},
        {min: 1.01, max: 1.50}
    ];


    /* -------------------------
      変数の設定
    ------------------------- */
    var margin = 80;


    /* --------------------
      描画エリアの設定
    -------------------- */
    var width = 962 - margin * 2,
        height = 600 - margin * 2;

    var svg = d3.select('#content').append('svg')
            .attr('width', width + margin)
            .attr('height', height + margin);

    var dataContainer = svg.append("svg:g")
                      .attr("id", "dataCircle")
                      .attr('width', width + margin)
                      .attr('height', height + margin)
                      .attr('transform', 'translate(' + [margin/2, margin/2].join(',') + ')');

    var coreContainer = svg.append("svg:g")
                      .attr("id", "coreCircle")
                      .attr('width', width + margin)
                      .attr('height', height + margin)
                      .attr('transform', 'translate(' + [margin/2, margin/2].join(',') + ')');


    /* -------------------------
      スケールの設定
    ------------------------- */
    var wScale = d3.scale.linear();


    /* -------------------------
      イベントリスナー
    ------------------------- */
    var self = this;
    this.e = new Eventer;

    this.init = function() {
        this.e.subscribe( 'load', [this.getData] );
        this.e.subscribe( 'load:data', [this.canvas.setup] );
        this.e.subscribe( 'draw:menu', [this.drawMenu] );
        this.e.subscribe( 'draw', [this.canvas.draw] );

        this.e.publish( 'load' );
    };


    /* --------------------
      色んな機能
    -------------------- */

    //ボタンメニューの生成
    this.drawMenu = function() {

          var menuItems = d3.select("#menuBlock").select('form').selectAll("span")
              .data( kirikuchiLabel )
              .enter().append("span").attr("class", "navColumn");

          menuItems.append("input")
              .attr({
                  type: "radio",
                  class: "nav",
                name: "nav",
                  value: function(d, i) {return i;}
              })
                .attr('id', function(d, i) {
                    return "id" + i;
                })
              .attr('value', function(d, i) {
                return i;
              })
              .property("checked", function(d, i) {
                if (i === 0) { return true; } else { return false; };
              })
              .on("change", function(d,i){
                    self.e.publish(['draw'], [self.data, {selected: i, value: this.value}]);
              });

          menuItems.append("label")
            .attr('for', function(d, i) {
              return "id" + i;
            })
            .text(function(d,i) {
              return d;
            });

    }


    /* --------------------
      データの取得
    -------------------- */
    this.getData = function() {

        d3.tsv('data.tsv', function(error, data){

            //データ型を確定させる
            data.forEach(function(d){
                d.valueString1 = String(d.valueString1);
                d.valueString2 = String(d.valueString2);
                d.valueNum1 = parseInt(d.valueNum1);
                d.valueNum2 = parseInt(d.valueNum2);
            });

            self.data = data;
            self.e.publish('load:data', [data]);
        });
    };


    this.canvas = {
      /* -------------------------
        描画の設定
      ------------------------- */
        setup: function(data) {

            // force layoutの初期化
            self.force = d3.layout.force().nodes(data);

            //定性的データに含まれるユニークな値を配列化する
            keyString1 = d3.set( data.map(function(d){ return d.valueString1 }) ).values(),
                options = keyString1.map(function(d) {
                    return '<option>' + d + '</option>';
                }).join('');

            keyString2 = d3.set( data.map(function(d){ return d.valueString2 }) ).values(),
                options = keyString2.map(function(d) {
                return '<option>' + d + '</option>';
                }).join('');

            //値と色を関連づける
            varForColor = keyString2;

            self.colors = {};
            for(i = 0; i < varForColor.length; i++) {
                var key = varForColor[i];
                self.colors[varForColor[i]] = [colorArray[i]].join('');
            }

            self.e.publish('draw', [ data ]);
            self.e.publish('draw:menu');
            self.e.publish('draw:emptyinfo');
        },


        draw: function(data, filter) {

            self.force
                .nodes(data)
                .charge(function(d){ return -d.valueNum1/2 })
                .size([width, height / 2])
                .on('tick', function(e){

                    var center = {
                            x: width / 2,
                            y: height / 2 + height / 4
                        },
                        centerx;

                    self.data.forEach(function(o, i) {

                        if((filter || {}).value) {

                              switch (filter.selected){

                                case 0:
                                    labelsArray = [varAll];
                                    centerx = 1;
                                    break;

                                case 1:
                                    labelsArray = keyString1.slice();
                                    var _l = keyString1.length;

                                    wScale.domain([0, _l]).range([0, 3]);

                                    for (var j=0; j<_l; j++) {
                                        if (o.valueString1 == keyString1[j]) {
                                            centerx = wScale(j);
                                        }
                                    };
                                    break;

                                case 2:
                                    labelsArray = keyString2.slice();
                                    var _l = keyString2.length;
                                       wScale.domain([0, _l]).range([0, 3]);
                                    for (var j=0; j<_l; j++) {
                                    if (o.valueString2 == keyString2[j]) { centerx = wScale(j); }
                                    };
                                    break;

                                case 3:
                                    labelsArray.length=0;
                                    for (var i=0; i<lengthArray1.length; i++) {
                                        labelsArray[i] = lengthArray1[i].min + "〜" + lengthArray1[i].max;
                                    };

                                    var _l = lengthArray1.length;
                                    wScale.domain([0, _l]).range([0, 3]);

                                    for (var j=0; j<_l; j++) {
                                        if ((o.valueNum1 >= parseInt(lengthArray1[j].min)) && (o.valueNum1 <= parseInt(lengthArray1[j].max))) {
                                            centerx = wScale(j);
                                        }
                                    };
                                  break;

                                case 4:
                                    labelsArray.length=0;
                                    for (var i=0; i<lengthArray2.length; i++) {
                                        labelsArray[i] = lengthArray2[i].min + "〜" + lengthArray2[i].max;
                                    };

                                    var _l = lengthArray2.length;
                                    wScale.domain([0, _l]).range([0, 3]);

                                    for (var j=0; j<_l; j++) {
                                        if ((o.valueNum2 >= parseInt(lengthArray2[j].min)) && (o.valueNum2 <= parseInt(lengthArray2[j].max))) {
                                            centerx = wScale(j);
                                        }
                                    };
                                  break;

                                case 5:
                                      labelsArray.length=0;
                                      var valueNum3 = o.valueNum2/o.valueNum1;
                                      for (var i=0; i<lengthArray3.length; i++) {
                                          labelsArray[i] = lengthArray3[i].min + "〜" + lengthArray3[i].max;
                                      };

                                      var _l = lengthArray3.length;
                                      wScale.domain([0, _l]).range([0, 3]);

                                      for (var j=0; j<_l; j++) {
                                          if ((valueNum3 >= parseFloat(lengthArray3[j].min)) && (valueNum3 <= parseFloat(lengthArray3[j].max))) {
                                              centerx = wScale(j);
                                          }
                                      };
                                    break;
                              }

                        } else {

                            labelsArray = [varAll];
                            centerx = 1;
                        }

                        o.x += (center.x * centerx - o.x) * e.alpha * 0.04;
                        o.y += (center.y - o.y) * e.alpha * 0.04;

                    });

                    d3.select("#labels").text( labelsArray.join(" - ") );
                    d3.selectAll('.coreC').attr("transform", function(d) { return ['translate(', d.x, ', ', d.y, ')'].join(''); });
                    d3.selectAll('.dataC').attr("transform", function(d) { return ['translate(', d.x, ', ', d.y, ')'].join(''); });

                })
                .start();


            /*
            各円の中心にある白い円
            */
            var coreCircles = coreContainer.selectAll('.coreC')
                .data(data)

            coreCircles.enter()
                .append('circle')
                .attr('class', 'coreC')
                .attr('r', 0)
                .attr('fill', "#FFF")
                .call( self.force.drag )

            coreCircles
                .transition()
                .duration(1100)
                .delay(function(d, i) { return i * 10; })
                .attr('fill', "#FFF")
                .attr('r', 2);


            /* -------------------------
              データによりサイズが変化する色のついた円
            ------------------------- */
            var dataCircles = dataContainer.selectAll('.dataC')
                .data(data)

            dataCircles.enter()
                .append('circle')
                .attr('class', 'dataC')
                .attr('r', 0)
                .attr('fill', function(d){
                    return "#FFFFFF";
                })
                .call( self.force.drag )

            dataCircles
                .transition()
                .duration(1100)
                .delay(function(d, i) { return i * 10; })
                /* 円を描画 */
                .attr('fill', function(d){
                    return self.colors[d.valueString2];
                })
                //円の大きさと値を関連づける
                .attr('r', function(d){
                    var valueNum3 = d.valueNum2/d.valueNum1;
                    return valueNum3 * circleScale;
                });

            dataCircles.on('mouseenter', function(d){
                d3.select(this)
                    .attr('class', 'dataC active')

                d3.select('#tooltip')
                    .attr('class', 'active')
                    .html([
                        '<p class="name">', d.name, '</p>',
                        '<p class="valData">', varString1 + ":", d.valueString1, '</p>',
                        '<p class="valData">', varString2 + ":", d.valueString2, '</p>',
                        '<p class="valData">', varNum1 + ":", d.valueNum1, '</p>',
                        '<p class="valData">', varNum2 + ":", d.valueNum2, '</p>',
                        '<p class="valData">', varNum3 + ":", d.valueNum2/d.valueNum1, '</p>'
                    ].join(''));
            });

            dataCircles.on('mouseleave', function(d){
                d3.select(this).attr('class', 'dataC')
                d3.select('#tooltip').attr('class', 'deactive');
            });
        }
    };


    this.init.apply( this, arguments );
};

var chart = new Chart;

});