//## ScatterPlot ##
$.fn.scatterPlotCluster = function(data, inSettings) {
	var plot = scatterPlotCluster($(this).attr('id'), data, inSettings);
	$(this).data('plot', plot);
	return plot;
}

function scatterPlotCluster(id, data, inSettings) {
	var plot = {};
	var extraDefaults = {
		xTickFormat: ".2s",
		xNumMaxTicks: 10,
		xNumMinTicks: 4,
		yNumMaxTicks: 10,
		yNumMinTicks: 4,
		transitionTime: 1000,
        radius:2,
        removeTooltip:false
	};
	var settings = addDefaultPlotSettings(inSettings, extraDefaults);
	plot.settings = settings;
	
	// Inner dimension
	var w = plot.w = settings.dimension.w - settings.padding.l - settings.padding.r; // inner width
  var h = plot.h = settings.dimension.h - settings.padding.t - settings.padding.b; // inner height
	
	var xMin = settings.xMin;
	var xMax = settings.xMax;
	var yMin = settings.yMin;
	var yMax = settings.yMax;
	
	//plot.data = data; 
	plot.xMin = xMin; plot.xMax = xMax; plot.yMin = yMin; plot.yMax = yMax;
	
  // X axis
  var xScale = plot.x = d3.scaleLinear()
		.domain([xMin, xMax])
		.range([0, w]);
	
  // Y axis
  var yScale = plot.y = d3.scaleLinear()
		.domain([yMin, yMax])
		.range([h, 0]);

	var xAxis = d3.axisBottom(xScale)
		.tickFormat(d3.format(settings.xTickFormat))
		.ticks(Math.min(Math.max(Math.ceil(xMax), settings.xNumMinTicks), settings.xNumMaxTicks));

	var yAxis = d3.axisLeft(yScale)
		.tickFormat(d3.format(settings.yTickFormat))
		.ticks(Math.min(Math.max(Math.ceil(yMax), settings.yNumMinTicks), settings.yNumMaxTicks));
	if (settings.grid) yAxis.tickSizeInner(-w);
	
  // Visualisation selection
  var vis = plot.vis = d3.select('#'+id)
		.append("svg")
		.attr("width", settings.dimension.w)
		.attr("height", settings.dimension.h)
		.attr("class", "chart scatterplot")
		.append("g")
		.attr("transform", "translate(" + settings.padding.l + "," + settings.padding.t + ")");
	
	// Plot area background
	vis.append("rect")
		.attr("class", "plotBG")
		.attr("width", xScale(xMax))
		.attr("height", yScale(0));
	
	var group = vis.selectAll(".group")
		.data(data)
    .enter().append("g")
		.attr("class", function(d, i) { return "group group"+i; })
		.each(function(d) {
			d3.select(this).selectAll('.dot')
				.data(d.data)
				.enter()
				.append("circle")
				.attr("r", settings.radius)
				.each(function(d) {
					var el = d3.select(this);
					el.attr("class", d.class);
					el.attr('cx', xScale(d.x));
					el.attr('cy', yScale(d.y));
					if (!settings.removeTooltip) {
                        el.attr("title", d.tooltip);
                    }
				});
		});
	
	// Y axis
	if (settings.yAxisLabel) {
		vis.append("g")
			.attr("class", "y axis")
			.call(yAxis)
			.append("text")
			.attr("transform", "rotate(-90)")
			.attr("y", 10)
			.attr("x", -2)
			.attr("class", "label")
			.style("text-anchor", "end")
			.text(settings.yAxisLabel)
			//.attr('url', data[i].url).style('cursor', 'pointer');
	}
	
	// X axis
	if (settings.xAxisLabel) {
		vis.append("g")
			.attr("class", "x axis")
			.attr("transform", "translate(0," + h + ")")
			.call(xAxis)
			.append("text")
			.attr("y",-2)
			.attr("x", w-2)
			.attr("class", "label")
			.style("text-anchor", "end")
			.text(settings.xAxisLabel);
	}
	
	// Legend
	if (settings.legend !== '') {
		var legend = vis.selectAll(".legend")
			.data(data)
			.enter().append("g")
			.attr("class", function(d, i) { return "legend legend"+i; })
			.attr("name", function(d, i) { return "legend"+i; })
			.attr("transform", function(d, i) { return "translate("+settings.legend.x+"," + (settings.legend.y + i * (settings.legend.size+2)) + ")"; });

		legend.append("rect")
			.attr("width", settings.legend.size)
			.attr("height", settings.legend.size)
			.style("fill", function(d, i) { return d.color? d.color : color(i); });

		legend.append("text")
			.attr("x", settings.legend.size+2)
			.attr("y", settings.legend.size/2)
			.attr("dy", ".35em")
			.text(function(d) { return d.name; });
	}
	return plot;
}

$.fn.bubble_plot = function(data,inSettings) {
	var plot = {};
	var extraDefaults = {
		xTickFormat: ".2s",
		xNumMaxTicks: 10,
		xNumMinTicks: 4,
		yNumMaxTicks: 10,
		yNumMinTicks: 4,
		transitionTime: 1000,
		radius:2,
		removeTooltip:false
	};
	var settings = addDefaultPlotSettings(inSettings, extraDefaults);
	plot.settings = settings;
	
	// Inner dimension
	var w = plot.w = settings.dimension.w - settings.padding.l - settings.padding.r; // inner width
	var h = plot.h = settings.dimension.h - settings.padding.t - settings.padding.b; // inner height
	
	// append the svg object to the body of the page
	var svg = d3.select($(this).get(0))
			.append("svg")
			.attr("width", settings.dimension.w)
			.attr("height", settings.dimension.h)
			.append("g")
			.attr("transform", "translate(" + settings.padding.l + "," + settings.padding.t + ")");
	// Build X scales and axis:
	var x = d3.scaleBand()
			.range([ 0, w])
			.domain(data.map(function(d) {return d.tissue;}))
			.padding(0.01);
	var xAxis = d3.axisBottom(x);
	svg.append("g")
			.attr("class", "x axis")
			.attr("transform", "translate(0," + h + ")")
			.call(xAxis)
			.selectAll(".tick text")
			.attr("class", "barchartlabel")
			.attr("y", 0)
			.attr("x", -9)
			.attr("transform", "rotate(-55)")
			.style("text-anchor", "end")
			.each(function(d, i) {
				if (data[i].tooltip) {
					d3.select(this).attr('title', d).style('cursor', 'default');
				}
			});
	var y = d3.scaleBand()
			.range([ h, 0 ])
			.domain(data.map(function(d) {return d.cell_type; }))
			.padding(0.01);
	svg.append("g")
			.call(d3.axisLeft(y))
			.selectAll(".tick text")
			.each(function(d, i) {
				if (data[i].tooltip) {
					d3.select(this).attr('title', data[i].cell_type);
				}
				
				d3.select(this).attr('url',data[i].url).style('cursor', 'pointer');
				
			});
			
	
	// Build color scale
	var myColor = d3.scaleLinear()
			.range(["white", "#69b3a2"])
			.domain([1,100])
	svg.selectAll()
			.data(data, function(d) {return d.tissue+':'+d.cell_type;})
			.enter()
			.append("rect")
			.attr("x", function(d) { return x(d.tissue) })
			.attr("y", function(d) { return y(d.cell_type) })
			.attr("width", x.bandwidth())
			.attr("height", y.bandwidth())
			//.attr("width", x.bandwidth() )
			//.attr("height", y.bandwidth() )
			.style("fill", function(d) { return (d.value == -1)?'white':'white'} )
	svg.selectAll()
			.data(data)
			.enter()
			.append("line")
			.style("stroke", "#E0E0E0")
			.style("stroke-width", .25)
			.attr("x1", function(d) { return x(d.tissue) + x.bandwidth()/2 })
			.attr("y1", function(d) { return h})
			.attr("x2", function(d) { return x(d.tissue) + x.bandwidth()/2 })
			.attr("y2", function(d) { return 0 })
	svg.selectAll()
			.data(data)
			.enter()
			.append("line")
			.style("stroke", "#E0E0E0")
			.style("stroke-width", .25)
			.attr("x1",0)
			.attr("y1", function(d) { return y(d.cell_type) + y.bandwidth()/2})
			.attr("x2", w)
			.attr("y2", function(d) { return y(d.cell_type) + y.bandwidth()/2})
	//.attr("width", x.bandwidth() )
	//.attr("height", y.bandwidth() )
	svg.selectAll()
			.data(data, function(d) {return d.tissue+':'+d.cell_type;})
			.enter()
			.append("circle")
			.attr("cx", function(d) { return x.bandwidth()/2 + x(d.tissue) })
			.attr("cy", function(d) { return y.bandwidth()/2 +y(d.cell_type) })
			.attr("r", function(d) { if(d.value >= 0.1) {return d.value*5+3} else if (d.value >= 0) {return 3} else {return 0}})
			//
			//.attr("width", x.bandwidth() )
			//.attr("height", y.bandwidth() )
			.style("fill", function(d) { return ((d.value==0)?'lightgrey':d.color)} )
			.each(function(d, i) {
				if (data[i].tooltip) {
					d3.select(this).attr('title', data[i].tooltip);
				}
				if (data[i].url) {
					d3.select(this).attr('url', data[i].url).style('cursor', 'pointer');
				}
			});
		$(this).on('click', '[url]', function() {
			document.location.href = $(this).attr('url');
		});
}

$.fn.sc_heatmap = function(id,data,col_ct,inSettings) {
	var plot = {};
	var settings = {
		dimension: {w: 400, h: 200},
		padding: {t: 150, r: 80, b: 20, l: 280},
		xAxisLabel:'umap',
		yAxisLabel:'umap',
		yTickFormat: "",
		xTickFormat: "0.5",
		legend: {txtX: 22, txtAnchor: 'start', size:10}
	}
	plot.settings = settings;
	
	var itemSize = 15;
	var cellSize = itemSize - 1;
	
	var y_elements = Object.keys(data);
	var cell_groups = {};
	var cell_types = {};
	var x_elements = [];
	var max_tpm = {};
	var sum_tpm = {};
	var cnt_tpm = {};
	var mean_tpm = {};
	var sd_tpm = {};
	var first = true;
	var last_cell_type = '';
	var last_cell_group = '';
	$.each(data, function(i, d) {
		max_tpm[i] = sum_tpm[i] = cnt_tpm[i] = sd_tpm[i] = 0;
		$.each(d.data, function(i2, d2) {
			d2.logValue = 1*d2.value==0?0:Math.log(d2.value);
			if (d2.label=='All cells') return;
			if (first) x_elements.push(d2.label);
			max_tpm[i] = Math.max(max_tpm[i], d2.value);
			sum_tpm[i] = sum_tpm[i] + d2.logValue*1;
			cnt_tpm[i]++;
		});
		mean_tpm[i] = sum_tpm[i]/cnt_tpm[i];
		$.each(d.data, function(i2, d2) {
			sd_tpm[i] = sd_tpm[i] + Math.pow(d2.logValue*1-mean_tpm[i],2);
		});
		sd_tpm[i] = Math.sqrt(sd_tpm[i] / (cnt_tpm[i] - 1));
		if (!cell_types[d.cell_type_name]) cell_types[d.cell_type_name] = {'minY':i, 'maxY':i, 'cell_type_name':d.cell_type_name.split('|')[0],'group_name':d.group_name.split('|')[0]};
		else cell_types[d.cell_type_name].maxY = i;
		if (!cell_groups[d.group_name]) cell_groups[d.group_name] = {'minY':i, 'maxY':i, 'group_name':d.group_name.split('|')[0]};
		else cell_groups[d.group_name].maxY = i;
		first = false;
	});
	var width = plot.w = x_elements.length*itemSize;
	var height = plot.h = y_elements.length*itemSize;
	
	
	var xScale = plot.x = d3.scaleBand()
			.domain(x_elements)
			.range([0, x_elements.length * itemSize]);
	
	var xAxis = d3.axisTop()
			.scale(xScale)
			.tickFormat(function (d) {
				return d;
			});
	
	var yScale = plot.y = d3.scaleBand()
			.domain(y_elements)
			.range([0, height]);
	
	var yAxis = d3.axisLeft()
			.scale(yScale)
			.tickFormat(function (d) {
				return d;
			});
	
	var thresholds = [0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95,1];
	var colorScale = d3.scaleThreshold()
			.domain(thresholds)
			.range(['#FCFFA4', '#F1ED6F', '#F7D340', '#FBB91F', '#FCA007', '#F8870E', '#F17020', '#E55C30', '#D64B40', '#C43C4E', '#B1325A', '#9C2964', '#87216B', '#711A6E', '#5C126E', '#460B6A', '#300A5B', '#190C3E', '#08051E', '#000004']);
	
	var vis = plot.vis = d3.select('#'+id)
			.append("svg")
			.attr("width", width + settings.padding.l + settings.padding.r)
			.attr("height", height + settings.padding.t + settings.padding.b)
			.append("g")
			.attr("transform", "translate(" + settings.padding.l + "," + settings.padding.t + ")");
	// Heatmap
	var cells = vis.selectAll('rect')
			.data(y_elements)
			.enter().append('g')
			.each(function(yd) {
				var el = d3.select(this);
				el.attr('class', yd);
				$.each(data[yd]['data'], function(i, xd) {
					var zScore = (xd.value<1 || sd_tpm[yd]==0)? 0 : (xd.logValue-mean_tpm[yd])/sd_tpm[yd];
					el.append('rect')
							.attr('class', 'heatmapCell col' + i)
							.attr('width', cellSize)
							.attr('height', cellSize)
							.attr('y', yScale(yd))
							.attr('x', xScale(xd.label))
							.attr('fill', colorScale(xd.value<1?0 : xd.value/max_tpm[yd]))
							.attr('maxNorm', colorScale(xd.value<1?0 : xd.value/max_tpm[yd]))
							.attr('zScore', d3.interpolateRdBu(1-(zScore+4)/8))
							.attr('title', xd.value+' <?= $unit?><br>zScore '+zScore.toFixed(2));
				});
			});
	// Axis
	vis.append("g")
			.attr("class", "y axis")
			.call(yAxis)
			.selectAll('text')
			.attr('font-weight', 'normal')
			.each(function (d, i) {
				var node = d3.select(this);
				var txt = node.text();
				node.text('');
				node.append('a').attr("xlink:href", data[d]['url']).text(txt).attr('style', (i<1?'font-weight:bold':''));
			});
	
	vis.append("g")
			.attr("class", "x axis")
			.call(xAxis)
			.selectAll('text')
			.attr('font-weight', 'normal')
			.style("text-anchor", "start")
			.attr("dx", ".8em")
			.attr("dy", ".5em")
			.attr("transform", function(d) { return "rotate(-65)"; });
	
	// Cell types
	var cellTypes = vis.selectAll(".cellTypes")
			.data(Object.values(cell_types))
			.enter().append("g")
			.attr("title", function(d, i) {return (d.cell_type_name+'<br>'+d.group_name.replace('Current gene','')) })
			.attr("class", "markerLabel cellTypes")
			.attr("transform", function(d, i) { return "translate(" + (-120) + ", " + yScale(d.minY) + ")"; });
	cellTypes.append("rect")
			.attr("width", cellSize/1.5)
			.attr("height", function(d, i) {return yScale(d.maxY)-yScale(d.minY)+cellSize; })
			.style("fill", function(d, i) {return col_ct[d.group_name.trim()][4]})
			.style("stroke", '#D9D9D9');
	cellTypes.append("text")
			.attr("transform", function(d, i) {return "translate(-12, "+(yScale(d.maxY)-yScale(d.minY)+cellSize+6)/2+") rotate(0)"; })
			.attr("text-anchor", "end")
			.style('font-size', '10px')
			.text(function(d, i) {return d.cell_type_name; });
	cellTypes.append("line")
			.style("stroke","#D9D9D9")
			.attr("stroke-width",1)
			.attr("x1",0)
			.attr("x2",120)
			.attr("y1",function(d) {return (yScale(d.maxY)-yScale(d.minY)+cellSize+0.5)})
			.attr("y2",function(d) {return (yScale(d.maxY)-yScale(d.minY)+cellSize+0.5)});
	
	// Hide texts longer than boxes
	vis.selectAll('.markerLabel').each(function(d, i) {
		var node = d3.select(this);
		/*if (node.select('text').node().getBBox().width > node.selectAll('rect').attr('height')) {
			node.select('text').text('...');
		}*/
	});
	
	// Legends
	var maxNorm = vis.selectAll(".maxNorm")
			.data(thresholds)
			.enter().append("g")
			.attr("class", "legend maxNorm")
			.attr("transform", function(d, i) { return "translate(0," + i * itemSize + ")"; });
	
	maxNorm.append("rect")
			.attr("x", width + 10)
			.attr("y", 10)
			.attr("width", cellSize)
			.attr("height", cellSize)
			.style("fill", function(d, i) {return colorScale(d); });
	
	maxNorm.append("text")
			.attr("x", width + 10+settings.legend.txtX)
			.attr("y", 10 + 9)
			.attr("dy", ".35em")
			.style("text-anchor", settings.legend.txtAnchor)
			.text(function(d,i) { if (i%5==0) {return d; } else return ''});
	
	var zScore = vis.selectAll(".zScore")
			.data([-4, -3.6, -3.2, -2.8, -2.4, -2, -1.6, -1.2, -0.8, -0.4, 0, 0.4, 0.8, 1.2, 1.6, 2, 2.4, 2.8, 3.2, 3.6, 4])
			.enter().append("g")
			.attr("class", "legend zScore hidden")
			.attr("transform", function(d, i) { return "translate(0," + i * itemSize + ")"; });
	
	zScore.append("rect")
			.attr("x", width + 10)
			.attr("y", 10)
			.attr("width", cellSize)
			.attr("height", cellSize)
			.style("fill", function(d, i) {return d3.interpolateRdBu(1-(d+4)/8); });
	
	zScore.append("text")
			.attr("x", width + 10+settings.legend.txtX)
			.attr("y", 10 + 9)
			.attr("dy", ".35em")
			.style("text-anchor", settings.legend.txtAnchor)
			.text(function(d,i) { if (i%5==0) {return d; } else return ''});
	
	
	$('.heatmapCell').on('mouseover', function(e) {
		var color = '#73ff96';
		var color = 'black';
		var col_class = $(this).attr('class').split(' ');
		$('.'+col_class[1]).css('stroke', color);
		var row_class = $(this).closest('g').attr('class');
		$('.'+row_class + ' rect').css('stroke', color);
		
	}).on('mouseout', function(e) {
		var col_class = $(this).attr('class').split(' ');
		$('.'+col_class[1]).css('stroke', '');
		var row_class = $(this).closest('g').attr('class');
		$('.'+row_class + ' rect').css('stroke', '');
	});
};