<!--
Library     : d3blocks
Author      : E.Taskesen, O.Verver
Mail        : erdogant@gmail.com, oliver@sensibly.nl
Github      : https://github.com/d3blocks/d3blocks
Licensed    : GPL3
-->

<!DOCTYPE html>
<head>
<title>{{ TITLE }}</title>

<style>
{% include "style.css" %}
    body { font-size: {{ FONTSIZE }}; }
.node { stroke-width: 1.5px; }

</style>
</head>


<meta charset="utf-8">

<body>
    <div id="main-wrapper">
    <div id="sidebar">
    <div id="current_time">{{ START_TIME }}</div>
    
    <div id="speed">
        <div class="togglebutton slow current" data-val="slow">Slow</div>
        <div class="togglebutton medium" data-val="medium">Medium</div>
        <div class="togglebutton fast" data-val="fast">Fast</div>
        <div class="clr"></div>
    </div>


    <div id="note"></div>

        <div id="cite">
            {{ NOTE }}
        </div>

    </div>

    <div id="chart"></div>

    <b>Color method:</b>
    	<select id="ColorOptions" onchange="link_color_changed(this.value)">
    	  <option value="STATE" {{ COLOR_STATE_SELECTED }}>State</option>
    	  <option value="NODE" {{ COLOR_NODE_SELECTED }}>Node</option>
    </select>
    
    <div class="clr"></div>
    </div>



<script>

    {% include "d3-3-5-5.min.js" %}

var USER_SPEED = "slow";

var width = {{ WIDTH }},
    height = {{ HEIGHT }},
	padding = 1,
	maxRadius = 3;
	// color = d3.scale.category10();
	
var sched_objs = [],
	curr_minute = 0;

// STATE PROPERTIES
var act_codes = {{ ACT_CODES }};
var act_counts = {{ ACT_COUNTS }};
var speeds = {{ SPEED }};
var time_notes = {{ TIME_NOTES }};
var notes_index = 0;
var colorByActivity = {{ COLORBYACTIVITY }} // array of the colors per state

// NODE PROPERTIES
var node_size = {{ NODE_SIZE }}; //array of radius values, one for each node
var node_color = {{ NODE_COLOR }}; //array of color values, one for each node
var color_method = "{{ COLOR_METHOD }}"; //Nodes can be colored based on "STATE" or "NODE"

// DATA. The nodes are comma seperated and within each node, the pattern is: ["sample_id 1, time_in_state 1, ..", "sample_id 2, time_in_state 1, ..", ..]
data = {{ json_data }}

// color_method selection changes. Listen if changes are made (onchange=link_color_changed())
function link_color_changed(linkColor_value) {
    console.log(linkColor_value)
    color_method = linkColor_value
}


var center_act = {{ CENTER }},
	center_pt = { "x": 380, "y": 365 };

var theta = 2 * Math.PI / (center_act ? (act_codes.length - 1) : act_codes.length );

// Coordinates for activities
var foci = {};
act_codes.forEach(function(code, i) {
	if (code.desc == center_act) {
		foci[code.index] = center_pt;
	} else {
		foci[code.index] = {x: 250 * Math.cos(i * theta)+380, y: 250 * Math.sin(i * theta)+365 };
	}
});


// Start the SVG
var svg = d3.select("#chart").append("svg")
    .attr("width", width)
    .attr("height", height);


data.forEach(function(d) {
	var day_array = d.split(",");
	var activities = [];
	for (var i=0; i < day_array.length; i++) {
		// Duration
		if (i % 2 == 1) {
			activities.push({'act': day_array[i-1], 'duration': +day_array[i]});
		}
	}
	sched_objs.push(activities);
});


// A node for each person's schedule
var nodes = sched_objs.map(function(o, i) {
	var act = o[0].act;
	act_counts[act] += 1;
	var init_x = foci[act].x + Math.random();
	var init_y = foci[act].y + Math.random();
	return {
		act: act,
		x: init_x,
		y: init_y,
		radius: node_size[i], //use the i-th value from the node_size array to set the radius of the i-th node
		//color: color(act),
		//color: node_color[i],
        color: (color_method === "STATE" ? color(act) : node_color[i]),
		moves: 0,
		next_move_time: o[0].duration,
		sched: o,
	}
});

var force = d3.layout.force()
	.nodes(nodes)
	.size([width, height])
	// .links([])
	.gravity(0)
	.charge(0)
	.friction(.9)
	.on("tick", tick)
	.start();

var circle = svg.selectAll("circle")
	.data(nodes)
  .enter().append("circle")
	.attr("r", function(d) { return d.radius; })
	.style("fill", function(d) { return d.color; });
	// .call(force.drag);

// Activity labels
var label = svg.selectAll("text")
	.data(act_codes)
  .enter().append("text")
	.attr("class", "actlabel")
	.attr("x", function(d, i) {
		if (d.desc == center_act) {
			return center_pt.x;
		} else {
			return 340 * Math.cos(i * theta)+380;
		}
		
	})
	.attr("y", function(d, i) {
		if (d.desc == center_act) {
			return center_pt.y;
		} else {
			return 340 * Math.sin(i * theta)+365;
		}
		
	});
	
label.append("tspan")
	.attr("x", function() { return d3.select(this.parentNode).attr("x"); })
	// .attr("dy", "1.3em")
	.attr("text-anchor", "middle")
	.text(function(d) {
		return d.short;
	});
label.append("tspan")
	.attr("dy", "1.3em")
	.attr("x", function() { return d3.select(this.parentNode).attr("x"); })
	.attr("text-anchor", "middle")
	.attr("class", "actpct")
	.text(function(d) {
		return act_counts[d.index] + "%";
	});
	

// Update nodes based on activity and duration
function timer() {
	d3.range(nodes.length).map(function(i) {
		var curr_node = nodes[i],
			curr_moves = curr_node.moves; 

		// Time to go to next activity
		if (curr_node.next_move_time == curr_minute) {
			if (curr_node.moves == curr_node.sched.length-1) {
				curr_moves = 0;
			} else {
				curr_moves += 1;
			}
		
			// Subtract from current activity count
			act_counts[curr_node.act] -= 1;
		
			// Move on to next activity
			curr_node.act = curr_node.sched[ curr_moves ].act;
		
			// Add to new activity count
			act_counts[curr_node.act] += 1;
		
			curr_node.moves = curr_moves;
			curr_node.cx = foci[curr_node.act].x;
			curr_node.cy = foci[curr_node.act].y;
		
			nodes[i].next_move_time += nodes[i].sched[ curr_node.moves ].duration;
		}

	});

	force.resume();
	curr_minute += 1;

	// Update percentages
	label.selectAll("tspan.actpct")
		.text(function(d) {
			return readablePercent(act_counts[d.index]);
		});

	// Update time
	var true_minute = curr_minute % 1440;
	d3.select("#current_time").text(minutesToTime(true_minute));
	
	// Update notes
	// var true_minute = curr_minute % 1440;
	if (true_minute == time_notes[notes_index].start_minute) {
		d3.select("#note")
			.style("top", "0px")
		  .transition()
			.duration(600)
			.style("top", "20px")
			.style("color", "#000000")
			.text(time_notes[notes_index].note);
	} 
	
	// Make note disappear at the end.
	else if (true_minute == time_notes[notes_index].stop_minute) {
		
		d3.select("#note").transition()
			.duration(1000)
			.style("top", "300px")
			.style("color", "#ffffff");
			
		notes_index += 1;
		if (notes_index == time_notes.length) {
			notes_index = 0;
		}
	}
	
	
	setTimeout(timer, speeds[USER_SPEED]);
}
setTimeout(timer, speeds[USER_SPEED]);



	
function tick(e) {
  var k = 0.04 * e.alpha;

  // Push nodes toward their designated focus.
  nodes.forEach(function(o, i) {
	var curr_act = o.act;
	
	// Make sleep more sluggish moving.
	var damper = {{ DAMPER }};
	
	//if (curr_act == "0") {
	//	var damper = 0.6;
	//} else {
	//	var damper = 1;
	//}

	if (color_method === "STATE") {
		o.color = color(curr_act);
	} else {
		o.color = node_color[i];
	}
	// console.log(color_method)
    // console.log(o.color)

	o.y += (foci[curr_act].y - o.y) * k * damper;
	o.x += (foci[curr_act].x - o.x) * k * damper;
  });

  circle
	  .each(collide(.5))
	  .style("fill", function(d) { return d.color; })
	  .attr("cx", function(d) { return d.x; })
	  .attr("cy", function(d) { return d.y; });
}


// Resolve collisions between nodes.
function collide(alpha) {
  var quadtree = d3.geom.quadtree(nodes);
  return function(d) {
	var r = d.radius + maxRadius + padding,
		nx1 = d.x - r,
		nx2 = d.x + r,
		ny1 = d.y - r,
		ny2 = d.y + r;
	quadtree.visit(function(quad, x1, y1, x2, y2) {
	  if (quad.point && (quad.point !== d)) {
		var x = d.x - quad.point.x,
			y = d.y - quad.point.y,
			l = Math.sqrt(x * x + y * y),
			r = d.radius + quad.point.radius + (d.act !== quad.point.act) * padding;
		if (l < r) {
		  l = (l - r) / l * alpha;
		  d.x -= x *= l;
		  d.y -= y *= l;
		  quad.point.x += x;
		  quad.point.y += y;
		}
	  }
	  return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
	});
  };
}




// Speed toggle
d3.selectAll(".togglebutton")
  .on("click", function() {
	if (d3.select(this).attr("data-val") == "slow") {
		d3.select(".slow").classed("current", true);
		d3.select(".medium").classed("current", false);
		d3.select(".fast").classed("current", false);
	} else if (d3.select(this).attr("data-val") == "medium") {
		d3.select(".slow").classed("current", false);
		d3.select(".medium").classed("current", true);
		d3.select(".fast").classed("current", false);
	} 
	else {
		d3.select(".slow").classed("current", false);
		d3.select(".medium").classed("current", false);
		d3.select(".fast").classed("current", true);
	}
	
	USER_SPEED = d3.select(this).attr("data-val");
});



function color(activity) {
	//var colorByActivity = {{ COLORBYACTIVITY }}
	return colorByActivity[activity];
}




// Output readable percent based on count.
function readablePercent(n) {
	
	var pct = 100 * n / data.length;
	if (pct < 1 && pct > 0) {
		pct = "<1%";
	} else {
		pct = Math.round(pct) + "%";
	}
	
	return pct;
}


// Minutes to time of day. Data is minutes from first date time point in data
function minutesToTime(m) {
	var minutes = (m + {{ START_HOUR_MIN }}*60) % 1440;
	var hh = Math.floor(minutes / 60);
	if (hh > 24) {
		hh = hh - 24;
	} else if (hh == 24) {
	} else if (hh == 0) {
		hh = 0;
	}
	var mm = minutes % 60;
	if (mm < 10) {
		mm = "0" + mm;
	}
	if (hh < 10) {
		hh = "0" + hh;
	}
	
	return hh + ":" + mm
}

//function minutesToTime(m) {
//	var minutes = (m + {{ START_HOUR_MIN }}*60) % 1440;
//	var hh = Math.floor(minutes / 60);
//	var ampm;
//	if (hh > 12) {
//		hh = hh - 12;
//		ampm = "pm";
//	} else if (hh == 12) {
//		ampm = "pm";
//	} else if (hh == 0) {
//		hh = 12;
//		ampm = "am";
//	} else {
//		ampm = "am";
//	}
//	var mm = minutes % 60;
//	if (mm < 10) {
//		mm = "0" + mm;
//	}
//	
//	return hh + ":" + mm + ampm
//}

			


</script>