var e451VizColors = [
    "#B47CD6",
    "#2FA4DE",
    "#A2D4AD",
    "#7A73CD",
    "#FCD067",
    "#D7859B",
    "#9DD3F1",
    "#78B692"
];

// takes two arrays of values and returns an array of intersecting values
function findIntersection(set1, set2) {
  //see which set is shorter
  var temp;
  if (set2.length > set1.length) {
      temp = set2, set2 = set1, set1 = temp;
  }

  return set1
    .filter(function(e) { //puts in the intersecting names
      return set2.indexOf(e) > -1;
    })
    .filter(function(e,i,c) { // gets rid of duplicates
      return c.indexOf(e) === i;
    })
}

//for the difference of arrays - particularly in the intersections and middles
//does not mutate any of the arrays
Array.prototype.diff = function(a) {
    return this.filter(function(i) {return a.indexOf(i) < 0;});
};

//for calculating solo datasets
function subtractUpset(i, inds, names) {
  var result = names[i].slice(0)
  for (var ind = 0; ind < inds.length; ind++) {
    // set1 vs set2 -> names[i] vs names[ind]
    for (var j = 0; j < names[inds[ind]].length; j++) { // for each element in set2
      if (result.includes(names[inds[ind]][j])) { 
        // if result has the element, remove the element
        // else, ignore
        var index = result.indexOf(names[inds[ind]][j])
        if (index > -1) {
          result.splice(index, 1)
        }
      }
    }
  }
  return result
}

//recursively gets the intersection for each dataset
function helperUpset(start, end, numSets, names, data) {
  if (end == numSets) {
    return data
  }
  else {
    var intSet = {
      "set": data[data.length-1].set + end.toString(),
      "names": findIntersection(data[data.length-1].names, names[end])
    }
    data.push(intSet)
    return helperUpset(start, end+1, numSets, names, data)
  }
}


function makeUpset(sets, names) { // names: [[],[]]
  //number of circles to make
  var numCircles = sets.length
  var numSets = sets.length

  //position and dimensions
  var margin = {
    top: 80,
    right: 100,
    bottom: 100,
    left: 100
  };
  var width = 600;
  var height=500;
  

  // make the canvas
  var svg = d3.select("#venn") 
      .append("svg")
          .attr("width", width + margin.left + margin.right)
          .attr("height", height + margin.top + margin.bottom)
      .attr("xmlns", "http://www.w3.org/2000/svg")
      .attr("xmlns:xlink", "http://www.w3.org/1999/xlink")
      .append("g")
          .attr("transform",
                "translate(" + margin.left + "," + margin.top + ")")
      .attr("fill", "white");

  // graph title
  var graphTitle = svg.append("text")
    .attr("text-anchor", "middle")
    .attr("fill","black")
    .style("font-size", "20px")
    .attr("transform", "translate("+ (width/2) +","+ -20 +")")
    .text("UpSet Plot Test");

     // make a group for the upset circle intersection things
  var upsetCircles = svg.append("g")
  .attr("id", "upsetCircles")
  .attr("transform", "translate(20," + (height-60) + ")")
  
  
  var rad = 13,
  height = 400;

  // computes intersections
  var data2 = []
    
  for (var i = 0; i < numSets; i++) {
    var intSet = {
      "set": i.toString(),
      "names": names[i]
    }
    data2.push(intSet)

    for (var j = i + 1; j < numSets; j++) {
      var intSet2 = {
        "set": i.toString() + j.toString(),
        "names": findIntersection(names[i], names[j])
      }
      data2.push(intSet2)
      helperUpset(i, j+1, numSets, names, data2)
    }
  }

  //removing all solo datasets and replacing with data just in those datasets (cannot intersect with others)
  var tempData = []
  for (var i = 0; i < data2.length; i++) {
    if (data2[i].set.length != 1) { // solo dataset
      tempData.push(data2[i])
    }
  }
  data2 = tempData

  for (var i = 0; i < numSets; i++) {
    var inds = Array.apply(null, {length: numSets}).map(Function.call, Number)
    var index = inds.indexOf(i)
    if (index > -1) {
      inds.splice(index, 1);
    }
    var result = subtractUpset(i, inds, names)
    data2.push({
      "set": i.toString(),
      "names": result
    })
  }

  // makes sure data is unique
  var unique = []
  var newData = []
  for (var i = 0; i < data2.length; i++) {
    if (unique.indexOf(data2[i].set) == -1) {
      unique.push(data2[i].set)
      newData.push(data2[i])
    }
  }

  var data = newData


  // making dataset labels
  for (var i = 0; i < numSets; i++) {

    upsetCircles.append("text")
      .attr("dx", -20)
      .attr("dy", 5 + i * (rad*2.7))
      .attr("text-anchor", "end")
      .attr("fill", "black")
      .style("font-size", 13)
      .text(sets[i])
  }

  // sort data decreasing
  data.sort(function(a, b) {
    return parseFloat(b.names.length) - parseFloat(a.names.length);
  });

  // make the bars
  var upsetBars = svg.append("g")
    .attr("id", "upsetBars")
    
    
    var nums = []
    for (var i = 0; i < data.length; i++) {
      nums.push(data[i].names.length)
    }

    var names = []
    for (var i = 0; i < data.length; i++) {
      names.push(data[i].names)
    }

  //set range for data by domain, and scale by range
  var xrange = d3.scale.linear()
    .domain([0, nums.length])
    .range([0, width]);


  var yrange = d3.scale.linear()
    .domain([0, nums[0]])
    .range([height, 0]);


  //set axes for graph
  var xAxis = d3.svg.axis()
    .scale(xrange)
    .orient("bottom")
    .tickPadding(2)
    .tickFormat(function(d,i) { return data[i].set})
    .tickValues(d3.range(data.length));

  var yAxis = d3.svg.axis()
    .scale(yrange)
    .orient("left")
    .tickSize(5)

  //add X axis
  upsetBars.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," +  height + ")")
      .attr("fill", "none")
      .attr("stroke", "black")
      .attr("stroke-width", 1)
      .call(xAxis)
      .selectAll(".tick")
      .remove()


  // Add the Y Axis
  upsetBars.append("g")
      .attr("class", "y axis")
      .attr("fill", "none")
      .attr("stroke", "black")
      .attr("stroke-width", 1)
      .call(yAxis)
      .selectAll("text")
      .attr("fill", "black")
      .attr("stroke", "none");

    

  var chart = upsetBars.append('g')
          .attr("transform", "translate(1,0)")
          .attr('id','chart')

  // adding each bar
  chart.selectAll('.bar')
          .data(data)
          .enter()
      .append('rect')
        .attr("class", "bar")
        .attr('width', 15)
        .attr({
          'x':function(d,i){ return (rad-1) + i * (rad*2.7)},
          'y':function(d){ return yrange(d.names.length)}
        })
            .style('fill', e451VizColors[0])
            .attr('height',function(d){ return height - yrange(d.names.length); })

  //circles
  for (var i = 0; i < data.length; i++) {
    for (var j = 0; j < numSets; j++) {
      upsetCircles.append("circle")
        .attr("cx", i * (rad*2.7))
        .attr("cy", j * (rad*2.7))
        .attr("r", rad)
        .attr("id", "set" + i)
        .style("opacity", 1)
        .attr("fill", function() {
          if (data[i].set.indexOf(j.toString()) != -1) {
            return "mistyrose"
          } else {
            return "silver"
          }
        })
      
    }

    if (data[i].set.length != 1) {
      upsetCircles.append("line")
        .attr("id",  "setline" + i)
        .attr("x1", i * (rad*2.7))
        .attr("y1", data[i].set.substring(0, 1) * (rad*2.7))
        .attr("x2", i * (rad*2.7))
        .attr("y2", data[i].set.substring(data[i].set.length - 1, data[i].set.length) * (rad*2.7))
        .style("stroke", "darkslategrey")
        .attr("stroke-width", 4)
      
    }
  }
}

function makeUpsetNew(products, barData) { // names: [[],[]]
  //number of circles to make
  
  var numCircles = products.length
  var numSets = products.length

  //position and dimensions
  var margin = {
    top: 80,
    right: 100,
    bottom: 100,
    left: 100
  };
  var width = 600;
  var height=500;
  

  // make the canvas
  var svg = d3.select("#upset") 
      .append("svg")
          .attr("width", width + margin.left + margin.right)
          .attr("height", height + margin.top + margin.bottom)
      .attr("xmlns", "http://www.w3.org/2000/svg")
      .attr("xmlns:xlink", "http://www.w3.org/1999/xlink")
      .append("g")
          .attr("transform",
                "translate(" + margin.left + "," + margin.top + ")")
      .attr("fill", "white");

  // graph title
  var graphTitle = svg.append("text")
    .attr("text-anchor", "middle")
    .attr("fill","black")
    .style("font-size", "20px")
    .attr("transform", "translate("+ (width/2) +","+ -20 +")")
    .text("%HHs Cross Purchase");

     // make a group for the upset circle intersection things
  var upsetCircles = svg.append("g")
  .attr("id", "upsetCircles")
  .attr("transform", "translate(20," + (height-60) + ")")
  
  var rad = 13,
  height = 400;

  products.forEach((product, i)=>{
    upsetCircles.append("text")
    .attr("dx", -20)
    .attr("dy", 5 + i * (rad*2.7))
    .attr("text-anchor", "end")
    .attr("fill", "black")
    .style("font-size", 13)
    .text(product.name);
  })

  var productNames = products.map(x=>x.name);

  // sort data decreasing
  barData.sort(function(a, b) {
    return b.value - a.value;
  });
  console.log(barData);

  // make the bars
  var upsetBars = svg.append("g")
    .attr("id", "upsetBars")
    
  var barVals = barData.map(x=>x.value);

  //set range for data by domain, and scale by range
  var xrange = d3.scale.linear()
    .domain([0, barVals.length])
    .range([0, width]);


  var yrange = d3.scale.linear()
    .domain([0, barVals[0]])
    .range([height, 0]);


  //set axes for graph
  var xAxis = d3.svg.axis()
    .scale(xrange)
    .orient("bottom")
    .tickPadding(2)
    // .tickFormat(function(d,i) { debugger; return data[i].set})
    .tickValues(d3.range(barVals.length));

  var yAxis = d3.svg.axis()
    .scale(yrange)
    .orient("left")
    .tickSize(5)
    .tickFormat(function(d){return d+"%"});

  //add X axis
  upsetBars.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," +  height + ")")
      .attr("fill", "none")
      .attr("stroke", "black")
      .attr("stroke-width", 1)
      .call(xAxis)
      .selectAll(".tick")
      .remove()


  // Add the Y Axis
  upsetBars.append("g")
      .attr("class", "y axis")
      .attr("fill", "none")
      .attr("stroke", "black")
      .attr("stroke-width", 1)
      .call(yAxis)
      .selectAll("text")
      .attr("fill", "black")
      .attr("stroke", "none");

    

  var chart = upsetBars.append('g')
          .attr("transform", "translate(1,0)")
          .attr('id','chart')

  // adding each bar
  chart.selectAll('.bar')
          .data(barData)
          .enter()
      .append('rect')
        .attr("class", "bar")
        .attr('width', 15)
        .attr({
          'x':function(d,i){return (rad-1) + i * (rad*2.7)},
          'y':function(d){ return yrange(d.value)}
        })
            .style('fill', e451VizColors[0])
            .attr('height',function(d){ return height - yrange(d.value); })

  //circles

  barData.forEach((comboSet, index)=>{
    comboSet.products.forEach((product, prodIndex)=>{
      upsetCircles.append("circle")
        .attr("cx", index * (rad*2.7))
        .attr("cy", (product-1) * (rad*2.7))
        .attr("r", rad)
        .attr("id", "set"+index)
        .style("opacity", 1)
        .attr("fill", function(){
          if(product==="1"){
            return e451VizColors[1]
          } else if(product==="2"){
            return e451VizColors[2]
          } else if(product==="3"){
            return e451VizColors[3]
          } else if(product==="4"){
            return e451VizColors[4]
          }
        })
    });

    if(comboSet.products.length !== 1){
      upsetCircles.append("line")
        .attr("id", "setline"+index)
        .attr("x1", index*(rad*2.7))
        .attr("y1", (comboSet.products[0]-1)*(rad*2.7))
        .attr("x2", index*(rad*2.7))
        .attr("y2", (comboSet.products[comboSet.products.length-1]-1)*(rad*2.7))
        .style("stroke", "darkslategrey")
        .attr("stroke-width", 4)
    }
  });
}