/*
	Author: Marnix Kok

	this file contains the solver for a discrete implementation
	of the one-dimensional wave-equation using euler-integration.
	
	M = (1 / h) * (1 / c) * [1 -2 1]
	
	where:
		 h is the distance of the points
		 c is the viscosity of the wave
		 
		
	filling this out in euler integration:
	
	u_t = u_t-1 + delta_t * M
	
*/

var DRAW_HEIGHT = 327;
var MAX_RADIUS = 30;
var MIN_RADIUS = 10;
var POINTS = 50;
var STEP = 600.0 / POINTS;

var u = [];
var u_min = [];
var c = 5.0;
var h = 0.9;			
var dt = 0.05;

var angle = 0;
var move_idx = POINTS / 2;
var move_radius = 50;

var WaveEqDiscretization = {	

	/**
	 *	Setup value field
	 */
	field_setup : function() {
		for (var idx = 0; idx < POINTS; ++idx) {
			u[idx] = 0;
		}
	},

	/** 
	 *	Calculate next step 
	 */
	calc_step : function(steps) {

		// copy into u_min
		for (var idx = 0; idx < POINTS; ++idx) {
			u_min[idx] = u[idx];
		}

		// solve for next t
		for (var idx = 1; idx < POINTS - 1; ++idx) {
			u[idx] = 
				u_min[idx] + 
				dt * steps * (
					(1.0 / h) * (1.0 / c) * (
						(-2.0 * u_min[idx]) +
						(u_min[idx - 1]) +
						(u_min[idx + 1])
					)
				);
		}

		// move one point that will create a ripple
		for (var idx = 0; idx < POINTS; idx += 10) {
			u[idx] = 10 * Math.sin((0.5 + angle) + (idx * (31.4 / POINTS)));
		}
		u[move_idx] = move_radius * Math.sin(angle + (idx * (31.4 / POINTS)));
		
		angle += 0.1;

		// move to different point when 2pi is reached
		if (angle > 6.28) {
			move_radius = MIN_RADIUS + Math.random() * (MAX_RADIUS - MIN_RADIUS);
			move_idx = 1 + Math.round(Math.random() * (POINTS - 2));
			angle = 0;
		}
	},
	
	/** 
	 *	Draw the function
	 */
	draw : function(context) {
	
		context.fillStyle = "rgba(115, 148, 179, 0.7)";
		context.strokeStyle = "rgba(163, 211, 255, 1)";

		context.beginPath();
		context.moveTo(600, 480);
		context.lineTo(0, 480);
		context.lineTo(0, DRAW_HEIGHT);

		for (var idx = 0; idx < POINTS; ++idx) {
				
			context.lineTo((idx + 1) * STEP, DRAW_HEIGHT - u[idx]);
		}
		
		context.fill();
		context.stroke();
				
	}
};

