// This file is Free Software under the GNU GPL, Version >=2;
// and comes with NO WARRANTY!
//
// javascript source to render charts
// This file is a part of the burndown chart moinmo.in parser
//
// Version 1.3
// Initial Version 2015-03-05
// @copyright: 2015 by Intevation GmbH Osnabrueck
// @author: Sean Engelhardt <sean.engelhardt@intevation.de>
// @license: GNU GPLv>=2.

var yAxisDomain = [];

// testdata
// ideal.push({date : new Date(2015,03,01), points: 50});
// ideal.push({date : new Date(2015,03,05), points: 0});
// actual.push({date : new Date(2015,03,01), points: 2});
// actual.push({date : new Date(2015,03,03), points: 2});
// actual.push({date : new Date(2015,03,04), points: 0});

//calculates the difference between two dates
var daysInSprint = function(){
	return Math.max(
		dayDifference(
			getFirstDateInStructure(actual), getLastDateInStructure(actual)
		),
		dayDifference(
			getFirstDateInStructure(ideal), getLastDateInStructure(ideal)
		)
	);
};

var pointsInSprint = function(){
	var max = Math.max(
		getMaxPointInStructure(actual), getMaxPointInStructure(ideal)
	);

	var min = Math.min(
		getMinPointInStructure(actual), getMinPointInStructure(ideal)
	);

	return (max - min);
};

function dayDifference(first, second) {
	"use strict";
	var difference = (second - first) / (1000 * 60 * 60 * 24);

	// just to avoid the get thousands of lines... would look ugly.
	if (difference > 60) {
		difference = 60;
	}

	return difference;
}

//to get the highest point in the assoziative arrays
function getMaxPointInStructure(structure) {
	"use strict";
	var max = 0;
	for (var i = 0; i < structure.length; i++) {
		if (structure[i].points > max){
			max = structure[i].points;
		}
	}

	return max;
}

//to get the lowest number of points in the assoziative arrays
function getMinPointInStructure(structure){
	"use strict";
	var min = 0;
	for (var i = 0; i < structure.length; i++) {
		if (structure[i].points < min){
			min = structure[i].points;
		}
	}
	return min;
}

//to get the last date of the array
function getLastDateInStructure(structure){
	"use strict";
	var last = structure[0].date;
	for (var i = 0; i < structure.length; i++) {
		if (structure[i].date > last){
			last = structure[i].date;
		}
	}

	return last;
}

//to get the first date of the array
function getFirstDateInStructure(structure){
	"use strict";
	var first = structure[0].date;
	for (var i = 0; i < structure.length; i++) {
		if (structure[i].date < first){
			first = structure[i].date;
		}
	}

	return first;
}

//determintate if there is a preview CSS container or a content CSS container
//used for moinmo.in systemsds
function contentOrPreviewDiv(){
    if (document.getElementById("preview")) {
        return "#preview";
    }
    else if (document.getElementById("content")) {
        return "#content";
    }
    else {
        return "body";
    }
}

function setPointTickLimit(limit){
	if (pointsInSprint() < limit){
		return pointsInSprint();
	} else {
		return limit;
	}
}

function setDateTickLimit(limit){
	if ( daysInSprint() < limit ){
		return daysInSprint();
	} else {
		return limit;
	}
}

//draw the chart
function makeChart(){
	"use strict";

	//declaration
	var margin = {top: 10, right: 30, bottom: 100, left: 65},
		width = 800 - margin.left - margin.right,
		height = 600 - margin.top - margin.bottom;

	// var  = width-85;

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

	var y = d3.scale.linear()
		.range([height, 0]);

	var idealLine = d3.svg.line()
		.x(function(d) { return x(d.date); })
		.y(function(d) { return y(d.points); });

	var actualLine = d3.svg.line()
		.x(function(d) { return x(d.date); })
		.y(function(d) { return y(d.points); });

	//get the max value for the y-domain
	yAxisDomain.push( getMinPointInStructure(actual), Math.max(getMaxPointInStructure(actual), getMaxPointInStructure(ideal)) );

	//set the domain of the y-axis 10% over the max-val
	// yAxisDomain[1] = (Math.round(yAxisDomain[1] / 5) * 5)*1.1;
	// yAxisDomain[1] = (Math.round((yAxisDomain[1]*1.1) / 5) * 5);
	// yAxisDomain[1] = Math.ceil(1+yAxisDomain[1]/5)*5;
	// yAxisDomain[1] = Math.ceil((yAxisDomain[1]*1.1)/5)*5
	// yAxisDomain[1] = Math.ceil(((yAxisDomain[1])*1.1)/10) *10;
	yAxisDomain[1] = function() {
		if ( yAxisDomain[1] <= 10 ){
			return Math.ceil(yAxisDomain[1]*1.1);
		} else if (yAxisDomain[1] < 100){
			return Math.ceil((yAxisDomain[1]+1) / 5) *5;
		} else{
			return Math.ceil((yAxisDomain[1]+1) / 10) *10;
		}
	}();

	//set domain of y axis
	y.domain(d3.extent(yAxisDomain, function(d){return d; }));

	//set the domain of the x axis the the array wth the last date
	x.domain(d3.extent(ideal, function(d){return d.date; }));

	var xAxis = d3.svg.axis()
		.scale(x)
		.orient("bottom")
		.ticks(setDateTickLimit(10))
		.tickFormat(d3.time.format("%m-%d"));


	var yAxis = d3.svg.axis()
		.scale(y)
		.orient("left")
		.ticks(setPointTickLimit(10));


	var vGridLines = d3.svg.axis()
		.scale(x)
		.orient("bottom")
		.ticks(setDateTickLimit(25));


	var hGridLines = d3.svg.axis()
		.scale(y)
		.orient("left")
		.ticks(setPointTickLimit(25));


	//contentOrPreviewDiv()
	var svg = d3.select(contentOrPreviewDiv())
		.append("svg")
		.attr("class", "svg")
		.attr("width", width + margin.left + margin.right)
		.attr("height", height + margin.top + margin.bottom)
		.append("g")
		.attr("transform", "translate(" + margin.left + "," + margin.top + ")");


	// Draw the horitontal Grid lines
	svg.append("g")
		.attr("class", "grid")
		.attr("transform", "translate(0," + height + ")")
		.call(vGridLines
			.tickSize(-height, 0, 0)
			.tickFormat("")
		);

	// Draw the vertical Grid lines
	svg.append("g")
		.attr("class", "grid")
		.call(hGridLines
			.tickSize(-width, 0, 0)
			.tickFormat("")
		);

	// Draw the x-axis
	svg.append("g")
		.attr("class", "x axis")
		.attr("transform", "translate(0," + height + ")")
		.call(xAxis)
		.selectAll("text")
		.style("text-anchor", "end")
		.attr("dx", "-.7em")
		.attr("dy", ".2em")
		.attr("transform", function() {
			return "rotate(-65)";
		});

	// Draw the y-axis
	svg.append("g")
		.attr("class", "y axis")
		.call(yAxis)
		.append("text")
		.attr("transform", "rotate(-90)")
		.attr("y", 6)
		.attr("dy", ".5em")
		.style("text-anchor", "end");

	// Text for x-axis
	svg.append("text")
		.attr("x", width / 2 )
		.attr("y", height + 60 )
		.attr("dy", ".5em")
		.style("text-anchor", "middle")
		.text("Date");

	// Text for y-axis
	svg.append("text")
		.attr("transform", "rotate(-90)")
		.attr("y", 10 - margin.left)
		.attr("x", 0 - (height / 2))
		.attr("dy", "1em")
		.style("text-anchor", "middle")
		.text("Points");

	// Ideal line
	svg.append("path")
		.datum(ideal)
		.attr("class", "line ideal")
		.attr("d", idealLine);

	// actual line
	svg.append("path")
		.datum(actual)
		.attr("class", "line actual")
		.attr("d", actualLine);

	// points on ideal line
	svg.selectAll("circle.point.ideal")
		.data(ideal)
		.enter()
		.append("circle")
		.attr("cx", function(d) { return x(d.date); })
		.attr("cy", function(d) { return y(d.points); })
		.attr("r", 4)
		.attr("class", "point ideal");

	// points on ideal line
	svg.selectAll("circle.point.actual")
		.data(actual)
		.enter()
		.append("circle")
		.attr("cx", function(d) { return x(d.date); })
		.attr("cy", function(d) { return y(d.points); })
		.attr("r", 4)
		.attr("class", "point actual");
}

makeChart();
