function fileDownload(blob,name){
  if(window.navigator.msSaveBlob){
    window.navigator.msSaveBlob(blob, name);
  }else{
    var reader = new FileReader();
    reader.onload = function (event) {
      var save = document.createElement('a');
      save.href = event.target.result;
      save.target = '_blank';
      save.download = name;
      var clicEvent = new MouseEvent('click', {
        'view': window,
        'bubbles': true,
        'cancelable': true
      });
      save.dispatchEvent(clicEvent);
      (window.URL || window.webkitURL).revokeObjectURL(save.href);
    }
    reader.readAsDataURL(blob);
  }
}

function pdfPolygon(path, x, y, scale, style){
    if(path.indexOf("A")!=-1){
      this.circle(x, y, 4.5*scale[0], 'FD');
    }else{
      var closed = path.indexOf("Z")!=-1,
          points = [];
      path = path.replace(/M|Z/g,"").split(/[LHV]/); 
      for(var i = 0; i<path.length; i++){
        var p = path[i].split(/[,| ]/).filter(function(d){ return d.length>0; }),
        pLen = p.length;
        if(pLen==1){
          if(i%2!=0){
            points.push([+p[0],points[points.length-1][1]]);
          }else{
            points.push([+points[points.length-1][0],+p[0]]);
          }
        }
        if(pLen==2){
          points.push([+p[0],+p[1]]);
        }
        if(pLen>2){
          for(var j = 0; j<pLen; j=j+2){
            points.push([+p[j],+p[j+1]]);
          }
        }
      }

      var acc = [],
        x1 = points[0][0],
        y1 = points[0][1],
        cx = x1,
        cy = y1;
      for(var i=1; i<points.length; i++) {
          var point = points[i],
            dx = point[0]-cx,
            dy = point[1]-cy;
          acc.push([dx, dy]);
          cx += dx;
          cy += dy;
      }
      this.lines(acc, x+(x1*scale[0]), y+(y1*scale[1]), scale, style, closed);
    }
}

function applyOpacity(rgb,alpha,old){
  var blending = function(newC,old){
    return alpha * newC + (1 - alpha) * old;
  }
  return {r: blending(rgb.r,old.r), g: blending(rgb.g,old.g), b: blending(rgb.b,old.b)};
}

function viewport(){
  var e = window,
      a = 'inner';
  if ( !( 'innerWidth' in window ) ){
    a = 'client';
    e = document.documentElement || document.body;
  }
  return { width : e[a+'Width'] , height : e[a+'Height'] }
}

function formatter(d){
  if(typeof d == 'number'){
    var dabs = Math.abs(d);
    if(dabs>0 && dabs<1e-2)
      d = d.toExponential(2);
    else
      d = (d % 1 === 0)?d:d.toFixed(2);
  }
  return d;
}

function downloadExcel(data,name){
  var sheets = ["void"],
      contentTypes = [],
      workbook = [],
      workbookRels = [],
      sheetXML = function(dat){
        var xml = [];
        dat.forEach(function(d){
          xml.push('<row>');
          d.forEach(function(dd){
            if(typeof dd == 'number')
              xml.push('<c t="n"><v>'+dd+'</v></c>');
            else
              xml.push('<c t="inlineStr"><is><t>'+dd+'</t></is></c>');
          });
          xml.push('</row>');
        });
        return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"><sheetData>'+xml.join('')+'</sheetData></worksheet>';
      }

  for(d in data)
    sheets.push(d);

  var zip = new JSZip(),
      rels = zip.folder("_rels"),
      xl = zip.folder("xl"),
      xlrels = xl.folder("_rels"),
      xlworksheets = xl.folder("worksheets");

  rels.file(".rels", '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/></Relationships>');

  for(var i = 1; i < sheets.length; i++){
    contentTypes.push('<Override PartName="/xl/worksheets/sheet'+i+'.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>');
    workbook.push('<sheet name="'+sheets[i]+'" sheetId="'+i+'" r:id="rId'+i+'"/>');
    workbookRels.push('<Relationship Id="rId'+i+'" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet'+i+'.xml"/>');
    xlworksheets.file("sheet"+i+".xml", sheetXML(data[sheets[i]]));
  }

  zip.file("[Content_Types].xml", '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="xml" ContentType="application/xml"/><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="jpeg" ContentType="image/jpeg"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>'+contentTypes.join('')+'</Types>');

  xl.file("workbook.xml", '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="24816"/><workbookPr showInkAnnotation="0" autoCompressPictures="0"/><bookViews><workbookView xWindow="0" yWindow="0" windowWidth="25600" windowHeight="19020" tabRatio="500"/></bookViews><sheets>'+workbook.join('')+'</sheets></workbook>');

  xlrels.file("workbook.xml.rels", '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'+workbookRels.join('')+'</Relationships>');

  zip.generateAsync({type:"blob"})
  .then(function(content) {
      fileDownload(content, name + '.xlsx');
  });
}

var infoIcon_b64 = "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTQiIHdpZHRoPSIxNCI+PGNpcmNsZSBzdHlsZT0iZmlsbDogcmdiKDI1NSwgMjU1LCAyNTUpOyBzdHJva2U6IHJnYigwLCAwLCAwKTsiIHI9IjYuNSIgY3k9IjciIGN4PSI3Ij48L2NpcmNsZT48Y2lyY2xlIHN0eWxlPSJmaWxsOiByZ2IoMCwgMCwgMCk7IiByPSIxLjQiIGN5PSI0IiBjeD0iNyI+PC9jaXJjbGU+PHBhdGggc3R5bGU9ImZpbGw6IHJnYigwLCAwLCAwKTsiIGQ9Ik0gNSA2IEwgNSA3IEwgNiA3IEwgNiA5LjU5NzY1NjIgTCA1IDkuNTk3NjU2MiBMIDUgMTEgTCA2IDExIEwgOCAxMSBMIDkgMTEgTCA5IDkuNTk3NjU2MiBMIDggOS41OTc2NTYyIEwgOCA2IEwgNSA2IHogIj48L3BhdGg+PC9zdmc+Cg==";

var xlsxIcon_b64 = " ";

var svgIcon_b64 = "PHN2ZyB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgaGVpZ2h0PSIxNCIgd2lkdGg9IjE0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgdmlld0JveD0iMCAwIDE0IDE0Ij4KPHJlY3Qgc3R5bGU9ImNvbG9yLXJlbmRlcmluZzphdXRvO2NvbG9yOiMwMDAwMDA7aXNvbGF0aW9uOmF1dG87bWl4LWJsZW5kLW1vZGU6bm9ybWFsO3NoYXBlLXJlbmRlcmluZzphdXRvO3NvbGlkLWNvbG9yOiMwMDAwMDA7aW1hZ2UtcmVuZGVyaW5nOmF1dG8iIHJ5PSIyLjYzNDciIGhlaWdodD0iMTMuNTE3IiB3aWR0aD0iMTMuNTE3IiBzdHJva2U9IiNkZWE4NTMiIHk9Ii4yNDEzOCIgeD0iLjI0MTM4IiBzdHJva2Utd2lkdGg9Ii40ODI3NiIgZmlsbD0iI2ZjZjNkYiIvPgo8ZyB0cmFuc2Zvcm09Im1hdHJpeCguNzY1NzQgLjY0MzE1IC0uNjQzMTUgLjc2NTc0IDMuNjI1OSAuMDEwNCkiPgo8cGF0aCBvcGFjaXR5PSIuOTkiIHN0eWxlPSJjb2xvci1yZW5kZXJpbmc6YXV0bztjb2xvcjojMDAwMDAwO2lzb2xhdGlvbjphdXRvO21peC1ibGVuZC1tb2RlOm5vcm1hbDtzaGFwZS1yZW5kZXJpbmc6YXV0bztzb2xpZC1jb2xvcjojMDAwMDAwO2ltYWdlLXJlbmRlcmluZzphdXRvIiBkPSJtMi4yMjQ4IDYuMDQwMmMwLTIuNjUzOCAyLjE1MTMtNC44MDUxIDQuODA1MS00LjgwNTEgMi42NTM4IDNlLTcgNC44MDUxIDIuMTUxMyA0LjgwNTEgNC44MDUxIiBzdHJva2U9IiNhMDYyMDAiIHN0cm9rZS13aWR0aD0iLjciIGZpbGw9IiNmZmQ1NmYiLz4KPHBhdGggb3BhY2l0eT0iLjk4IiBkPSJtMS4zMDUzIDEuMjM1MWgxMS40NDkiIHN0cm9rZT0iI2EwNjIwMCIgc3Ryb2tlLXdpZHRoPSIuNyIgZmlsbD0ibm9uZSIvPgo8cmVjdCBzdHlsZT0iY29sb3ItcmVuZGVyaW5nOmF1dG87Y29sb3I6IzAwMDAwMDtpc29sYXRpb246YXV0bzttaXgtYmxlbmQtbW9kZTpub3JtYWw7c2hhcGUtcmVuZGVyaW5nOmF1dG87c29saWQtY29sb3I6IzAwMDAwMDtpbWFnZS1yZW5kZXJpbmc6YXV0byIgdHJhbnNmb3JtPSJyb3RhdGUoLTQ1KSIgaGVpZ2h0PSIxLjU5MTgiIHdpZHRoPSIxLjU5MTgiIHN0cm9rZT0iIzY5NGMwZiIgeT0iNS4wNDgzIiB4PSIzLjMwMTYiIHN0cm9rZS13aWR0aD0iLjUiIGZpbGw9Im5vbmUiLz4KPC9nPgo8L3N2Zz4K";

var pdfIcon_b64 = " ";

function iconButton(sel,alt,src,title,job){
    sel.append("img")
      .attr("class","icon")
      .attr("alt", alt)
      .attr("width", 14)
      .attr("height", 14)
      .attr("src", "data:image/svg+xml;base64,"+src)
      .attr("title", title)
      .on("click", job);
}

function displayWindow(txt){
  var docSize = viewport(),
      bg = d3.select("body").append("div")
        .style({"position":"fixed","top":0,"left":0,"width":docSize.width+"px","height":docSize.height+"px","background":"rgba(0,0,0,0.8)","z-index":10});

  var boxStyle = {"background-color":"#fff","margin":"0 auto","margin-top":(docSize.height/5)+"px","padding":"30px","width":(docSize.width/2)+"px"};

  if(txt){
    boxStyle["font-size"] = "16px";
    boxStyle["text-align"] = "center";
  }else{
    boxStyle["height"] = (docSize.height/2)+"px";
    boxStyle["overflow-y"] = "auto";
  }

  var win = bg.append("div")
    .attr("class","window")
    .style(boxStyle)
    .on("click",function(){ d3.event.stopPropagation(); })

  bg.append("div")
    .attr("class","close-button")
    .style({"position":"absolute","top":(12+docSize.height/5)+"px","right":(docSize.width/4)+"px"})
    .html("&#x2716;")
    .on("click", function(){ bg.remove() });

  if(txt)
    win.text(txt);
  else
    return win;
}

function brushSlider(sel,domain,current,callback,baseWidth){
  var margin = {top: 36, right: 17, bottom: 0, left: 17},
      width = baseWidth - margin.left - margin.right,
      height = 57 - margin.top - margin.bottom;

  if(!current)
    current = domain;

  var x = d3.scale.linear()
      .range([0, width])
      .domain(domain);

  var brush = d3.svg.brush()
      .x(x)
      .extent(current)
      .on("brush", brushmove);

  var svg = sel.append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom);

  var brushg = svg.append("g")
      .attr("class", "axis brushSlider")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
      .call(d3.svg.axis()
        .scale(x)
        .orient("top")
        .tickValues(domain)
        .tickFormat(formatter)
        .tickSize(0)
        .tickPadding(12));

  brushg.selectAll("text")
    .style("text-anchor", "middle");

  brushg.append("g")
      .attr("class","brush")
      .call(brush);

  brushg.selectAll(".resize>rect").remove();

  brushg.selectAll(".resize").append("circle")
      .attr("class", "handle")
      .attr("r",6)

  brushg.selectAll(".resize").append("path")
      .attr("d","m -12,-22 c -1,0 -2,1 -2,2 l 0,8 c 0,1 1,2 2,2 l 10,0 2,2 2,-2 10,0 c 1,0 2,-1 2,-2 l 0,-8 c 0,-1 -1,-2 -2,-2 l -24,0 z")
      .style({"visibility":null,"fill":"#ddd","stroke":"#aaa"})

  var cloudText = brushg.selectAll(".resize")
      .append("text")
      .attr("x",0)
      .attr("y",-12)
      .style("text-anchor","middle")
      .text(function(d,i){ return d3.round(current[+!i],1); });

  brushg.select(".extent")
      .attr("y",-3)
      .attr("height", 6)
      .style({"fill-opacity": ".8", "stroke": "none", "fill": "#47c0c0"});

  brushg.select(".background").remove();

  function brushmove() {
    var extent = brush.extent();
    cloudText.text(function(d,i){ return d3.round(extent[+!i],1); })
    callback(extent);
  }
}

function selectedValues2str(selectedValues,data){
  var query = "(true";
  d3.entries(selectedValues).forEach(function(d){
    query = query + ") && (false";
    if(typeof d.value[0] == 'number' && d.value.length == 2){
            query = query + " || ((d['" + d.key + "'] >= '" + d.value[0] + "') && (d['" + d.key + "'] <= '" + d.value[1] + "'))";
    }else{
      if(typeof data[0][d.key] !== 'string')
        d.value.forEach(function(p){
          query = query + " || (d['" + d.key + "'].indexOf('" + p + "')!=-1)";
        })
      else
        d.value.forEach(function(p){
          query = query + " || (d['" + d.key + "'] == '" + p + "')";
        })
    }
  })
  query = query + ")";
  return query;
}

function topFilter(topBar,data,name,displayGraph){

  topBar.append("h3").text(texts.filter + ":")

  var selectedValues = {},
    changeAttrSel = function(val){
      if(d3.select("body>div>div.window").empty()){

        var dat = d3.set(data.map(function(d){ return d[val]; })).values(),
            panel = displayWindow(),
            vp = viewport();

        panel.append("h3").text(val).style("margin-bottom","10px")

        if(typeof data[0][val] == 'number'){
          var extent = d3.extent(data, function(d){ return d[val]; }),
              tempValues;
          brushSlider(panel,extent,selectedValues[val],function(s){ tempValues = s; },vp.width/3);
        }else{
          var valSelector = panel.append("select")
            .attr("multiple","multiple")
            .attr("size",Math.ceil(vp.height/40))
            .style({"width":vp.width/3+"px"});

          valSelector.selectAll("option").data(dat.sort())
            .enter().append("option")
              .property("value",String)
              .property("selected",function(d){ return (selectedValues[val] && selectedValues[val].indexOf(d)!=-1); })
              .text(String);
        }

        panel.append("button")
          .text(texts.add)
          .style({"position":"fixed","left":(2*vp.width/3)+"px","top":(2*vp.height/3)+"px"})
          .on("click",function(){
            selectedValues[val] = [];
            if(typeof tempValues != 'undefined'){
              selectedValues[val] = tempValues;
            }else{
              valSelector.selectAll("option").each(function(){
                if(this.selected)
                  selectedValues[val].push(this.value);
              })
            }
            if(selectedValues[val].length == 0)
              delete selectedValues[val];
            d3.select(this.parentNode.parentNode).remove();
          })
      }
    }

  var selFilter = topBar.append("select")
    .on("click",function(){ this.selectedIndex = -1; })
    .on("change",function(){ changeAttrSel(this.value); })

  selFilter.selectAll("option")
        .data(d3.keys(data[0]).sort())
      .enter().append("option")
        .property("value",String)
        .text(String)

  topBar.append("button")
    .text(texts.clear)
    .on("click",function(){ selectedValues = {}; })

  topBar.append("button")
    .text(texts.apply)
    .on("click",function(){
      var query = selectedValues2str(selectedValues,data);
      var names = data.filter(function(d){ return eval(query); }).map(function(d){ return d[name]; });
      displayGraph(names);
    })
}

function tooltip(sel,text){
    var body = d3.select("body");

    sel
      .on("mouseover", function(d){
        var coor = [0, 0];
        coor = d3.mouse(body.node());
        body.append("div")
          .attr("class","tooltip")
          .style({"position":"absolute","top":(coor[1]+20)+"px","left":(coor[0]+20)+"px","background":"#f5f5f5","padding":"10px"})
          .html(d[text]);
      })
      .on("mouseout", function(){
        d3.select("div.tooltip").remove();
      })
}
