
// Periodické okrajové podmínky ???
//  http://en.wikipedia.org/wiki/Periodic_boundary_conditions

function objGet(x,d)	{d=d?d:document; return d.getElementById?d.getElementById(x):d.all?d.all[x]:d.layers?d.layers[x]:null;}
function creEl(x,d)	{d=d?d:document; return d.createElement(x);}
function addEl(x,d)	{d=d?d:document; d.appendChild(x);}

function classFlake(n,x,y)
{
this.n = n;
this.x0 = x;
this.y0 = y;
this.x = x;
this.y = y;
this.state = -1;
this.data = {traj:0, size:1, color:''};
this.obj_id = "f"+n;
}

function classDropped(n)
{
this.obj_id = "d"+n;
this.x = 0;
this.y = 0;
this.size = 0;
this.color = '';
this.state = -1;
}

function rnd(n)
{
return Math.floor(Math.random()*n);
}

function classSnowGame(flakes,area)
{
var root = this;
this.area = [0,0,200,200];
this.traj = [];
this.nmax = 100;
this.n = 0;
this.nd = [];
this.ndmax = this.area[2] * 100;
this.flakes = [];
this.dropped = [];
this.dropped_line = [];
this.items  = {};
//this.items_line = [];
this.counter = [];
this.flakeAdd = function (root,n,x,y)
	{
	root.flakes[n].x0 = x;
	root.flakes[n].y0 = y;
	root.flakeMove(root,n,x,y);
	root.flakeStateSet(root,n,0);
	++root.n;
	root.counter[1].value = root.n;	//n
	root.counter[1].max = root.counter[1].max>n ? root.counter[1].max : n;
	root.counterWrite(root);
	};
this.droppedAdd = function (root,nd,n)
	{
	root.dropped[nd].color = root.flakes[n].data.color;
	root.dropped[nd].size = root.flakes[n].data.size;
	root.dropped[nd].x = root.flakes[n].x;
	root.dropped[nd].y = root.dropped_line[root.flakes[n].x] - root.dropped[nd].size;
	root.dropped_line[root.dropped[nd].x] = root.dropped[nd].y;
	root.droppedSet(root, nd, n);
	root.droppedMove(root, nd, root.dropped[nd].x, root.dropped[nd].y);
	root.droppedStateSet(root, nd, 0);
	++root.nd;
	root.counter[2].value = root.nd;
	root.counter[2].max   = root.counter[2].max>root.nd ? root.counter[2].max : root.nd;
	root.counterWrite(root);
	};
this.droppedSet = function (root,nd,n)
	{
	var obj = root.dropped[nd].obj_id;
	obj.style.width  = root.flakes[n].data.size + "px";
	obj.style.height = root.flakes[n].data.size + "px";
	obj.style.backgroundColor = root.dropped[nd].color;
	};
this.counterWrite = function (root)
	{
	var i, li;
	li = root.counter.length
	for(i=0;i<li;++i)
		{
		root.counter[i].obj.value = root.counter[i].max;
		}
	}
this.counterInit = function (root)
	{
	root.counter[0] = {obj:objGet('time'),value:0,max:0,time:0};
	root.counter[1] = {obj:objGet('numb'),value:0,max:0};
	root.counter[2] = {obj:objGet('dropped'),value:0,max:0};
	}
this.flakeAddAllTimer = function (root)
	{
	var i,li;
	if (root.n<root.nmax)
		{
		li = root.flakes.length;
		for (i=0;i<li;++i)
			{
			if (root.flakes[i].state === -1)
				{
				root.flakeAdd(root,i,rnd(root.area[2]), rnd(root.area[3]*0.25)-10);
				}
			}
		}
	};
this.flakeAddOneTimer = function (root)
	{
	var i,li;
	if (root.n<root.nmax)
		{
		li = root.flakes.length;
		for (i=0;i<li;++i)
			{
			if (root.flakes[i].state === -1)
				{
				root.flakeAdd(root,i,rnd(root.area[2]), 0);
				return;
				}
			}
		}
	};
this.droppedAddOneTimer = function (root, n)
	{
	var i,li;
	if (root.nd<root.ndmax)
		{
		li = root.dropped.length;
		for (i=0;i<li;++i)
			{
			if (root.dropped[i].state === -1)
				{
				root.droppedAdd(root,i,n);
				return;
				}
			}
		}
	};
this.flakeAddMouse = function (root,x,y)
	{
	var n = rnd(root.flakes.length);
	root.flakeRemove(root,n);
	root.flakeAdd(root,n,x,y);
	};
this.flakeRemove = function (root,n)
	{
	root.flakeStateSet(root,n,-1);
	--root.n;
	--root.counter[1].value;
	};
this.droppedRemove = function (root,n)
	{
	root.droppedStateSet(root,n,-1);
	--root.nd;
	--root.counter[2].value;
	};
this.flakeStateSet = function (root,n,state)
	{
	root.flakes[n].state = state;
	root.flakes[n].obj_id.style.display = state!==-1 ? "" : "none";
	};
this.droppedStateSet = function (root,n,state)
	{
	root.dropped[n].state = state;
	root.dropped[n].obj_id.style.display = state!==-1 ? "" : "none";
	};
this.flakeMove = function (root,n,x,y)
	{
//alert([x,y])
	root.flakes[n].x = x;
	root.flakes[n].y = y;
	root.flakes[n].obj_id.style.left = x + "px";
	root.flakes[n].obj_id.style.top  = y + "px";
	};
this.droppedMove = function (root,n,x,y)
	{
	root.dropped[n].x = x;
	root.dropped[n].y = y;
	root.dropped[n].obj_id.style.left = x + "px";
	root.dropped[n].obj_id.style.top  = y + "px";
	};
this.flakeMoveTraj = function (root,n)
	{
	var f,t,x,y;
	f = root.flakes[n];
	t = root.traj[f.data.traj];
	++f.state;
	if (f.state >= t.length)
		{
		f.state = 0;
		f.y0 = f.y;
		}
	x = f.x0 + t[f.state].x;
	y = f.y0 + t[f.state].y;
	root.flakes[n].state = f.state;
//alert([
//f.toSource(),
//	f.x0, t[f.state].x,
//	f.y0, t[f.state].y
//])
	if (root.dropped_line[x])
		{
		if (y<root.dropped_line[x])
			{
			root.flakeMove(root, n, x, y);
			}
		else	{	//colision bottom
			if (root.nd>root.ndmax)
				{
				root.droppedRemove(root,rnd(root.nd));
				}
			root.droppedAddOneTimer(root,n)
			root.flakeRemove(root,n);
			}
		}
	else	{
		root.flakeRemove(root,n);
		}
	};
this.flakeMoveTimer = function (root)
	{
	var i,li;
	li = root.flakes.length;
	for (i=0;i<li;++i)
		{
		if (root.flakes[i].state !== -1)
			{
			root.flakeMoveTraj(root,i);
			}
		}
	};
this.createTraj = function ()
	{
	var i,j,k,ampmin, ampmax, amp,pnamp, pn, stepmax,stepmin,step, accmin, accmax, acc, alpha, da;
	accmin  = 2;				// y acceleration
	accmax  = 3 - accmin + 1;
	ampmin  = 1;				// x amplitude
	ampmax  = 10 - ampmin + 1;
	stepmin = 10;
	stepmax = 20 - stepmin + 1;
	step    = rnd(stepmax) + stepmin;	// xy angle steps
	alpha   = 2 * Math.PI / step;		// xy angle
	for (i=0;i<20;++i)
		{
		this.traj[i] = [];
		acc = rnd(accmax) + accmin;	// y acceleration
		amp = rnd(ampmax) + ampmin;	// x amplitude
		pn = 1 - rnd(2)*2;		// x pos / neg
		pnamp = pn * amp;
		da = 0;
		for (j=0,k=acc;j<step;++j,k+=acc,da+=alpha)
			{
			this.traj[i][j] = {
				x: Math.floor(pnamp * Math.sin(da)),
				y: Math.floor(k)
				};
			}
		}
/*
	// zobraz trajektorie
	var k, j, lj, li,t,x,y,x0,y0,t,obj_out,obj;
	obj_out = objGet('snow_area');
	x = 0;
	y = 0;
	li = root.traj.length;
	for(i=0,k=0;i<li;++i)
		{
		t = root.traj[i];
		lj = t.length;
		x0 = i * 10;
		y0 = 0;
		for(j=0;j<lj;++j,++k)
			{
			x = x0 + t[j].x;
			y = y0 + t[j].y;
			obj    = creEl('DIV');
			obj.id = 'f'+k;
			obj.style.position = 'absolute';
			obj.style.width  = 1 + "px";
			obj.style.height = 1 + "px";
			obj.style.left   = x + "px";
			obj.style.top    = y + "px";
			obj.style.backgroundColor = "#000000";
			addEl(obj,obj_out);
			}
		}
	alert();
*/
	};
this.getTime = function()
	{
	return new Date().getTime() / 1000;
	};
this.init = function (root, flakes, area)
	{
	var i,li,lt,obj,obj_out, n,color;
	root.counterInit(root);
	root.area = area   ? area   : root.area;
	root.nmax = flakes ? flakes : root.nmax;
	objGet('f').value = root.nmax;
	objGet('w').value = root.area[2];
	objGet('h').value = root.area[3];
	//root.counterWrite(root);
	// area init
	obj_out = objGet('snow_area');
	obj_out.style.position = "relative";
	obj_out.style.width    = root.area[2]+"px";
	obj_out.style.height   = root.area[3]+"px";
	obj_out.style.lineHeight = '0'; //IE
	obj_out.style.fontSize   = '0'; //IE
	obj_out.style.border   = "1px solid #dddddd";
	obj_out.style.display  = "block";
	obj_out.style.overflow = "hidden";

	// mouse click
	root.area[0] = obj_out.offsetLeft;
	root.area[1] = obj_out.offsetTop;
	if (document.all)	//IE
		{
		if (document.documentElement)
			{
			obj_out.onmousedown = function()
				{
				SG.flakeAddMouse(SG, event.clientX-SG.area[0]+document.documentElement.scrollLeft, event.clientY-SG.area[1]+document.documentElement.scrollTop);
				}
			}
		if (document.body)
			{
			obj_out.onmousedown = function()
				{
				SG.flakeAddMouse(SG, event.clientX-SG.area[0]+document.body.scrollLeft, event.clientY-SG.area[1]+document.body.scrollTop);
				}
			}
		else
			{
			obj_out.onmousedown = function()
				{
				SG.flakeAddMouse(SG, event.clientX-SG.area[0], event.clientY-SG.area[1]);
				}
			}
		}
	else	{	// Moz
		obj_out.onmousedown = function(event)
			{
			SG.flakeAddMouse(SG, event.pageX-SG.area[0], event.pageY-SG.area[1]);
			}
		}

	// flakes destroy
	li = root.flakes.length;
	for(i=0;i<li;++i)
		{
		obj = root.flakes[i].obj_id;
		obj.style.display   = "none";
		obj_out.removeChild(obj);
		}
	// flakes init
	li = root.nmax;
	lt = root.traj.length;
	root.flakes = [];
	color = [
		'888888',
		'AAAAAA',
		'CCCCCC',
		'EEEEEE'
		];
	for(i=0;i<li;++i)
		{
		root.flakes[i] = new classFlake(i);
		root.flakes[i].data = {traj: rnd(lt), size: rnd(3) + 1, color: rnd(color.length)};
		root.flakes[i].data.color = "#"+color[root.flakes[i].data.color]
		obj = creEl('DIV');
		obj.id = root.flakes[i].obj_id;
		obj.style.backgroundColor = root.flakes[i].data.color;
		obj.style.display  = "none";
		obj.style.position = 'absolute';
		obj.style.width    = root.flakes[i].data.size + "px";
		obj.style.height   = root.flakes[i].data.size + "px";
		obj.style.lineHeight = '0'; //IE
		obj.style.fontSize   = '0'; //IE
		addEl(obj,obj_out);
		root.flakes[i].obj_id = objGet(root.flakes[i].obj_id);
		}
	// dropped destroy
	li = root.dropped.length;
	for(i=0;i<li;++i)
		{
		obj = root.dropped[i].obj_id;
		obj.style.display = "none";
		obj_out.removeChild(obj);
		}
	// dropped init
	li = root.ndmax;
	root.dropped = [];
	for(i=0;i<li;++i)
		{
		root.dropped[i] = new classDropped(i);
		obj = creEl('DIV');
		obj.id = root.dropped[i].obj_id;
		obj.style.display  = "none";
		obj.style.position = 'absolute';
		obj.style.width    = 0 + "px";
		obj.style.height   = 0 + "px";
		obj.style.lineHeight = '0'; //IE
		obj.style.fontSize   = '0'; //IE
		addEl(obj,obj_out);
		root.dropped[i].obj_id = objGet(root.dropped[i].obj_id);
		}
	// dropped_line init
	li = root.area[2];
	n  = root.area[3];
	root.dropped_line = [];
	for(i=0;i<li;++i)
		{
		root.dropped_line[i] = n;
		}
	// items init
	li = root.area[2];
	root.items = [];
	for(i=0;i<li;++i)
		{
		root.items[i] = [];
		}
	root.createTraj();


	root.timer_move = new classTimer2(SGTimerMove,150);
	root.timer_move.start();
	root.timer_add  = new classTimer2(SGTimerAdd,150);
	root.counter[0].time = root.getTime();
	root.timer_add.start();

	};
this.init(root,flakes,area);
}

function SGTimerMove()
	{
	var root = SG, n;
//	root.flakeAddAllTimer(root);
	root.flakeMoveTimer(root);
	n = root.getTime();
	root.counter[0].value = Math.floor((n - root.counter[0].time)*100);
	root.counter[0].time = n;
	root.counter[0].max = root.counter[0].max>root.counter[0].value ? root.counter[0].max : root.counter[0].value;
	root.timer_move.start();
	}
function SGTimerAdd()
	{
	var root = SG;
	root.flakeAddOneTimer(root);
	root.timer_add.start();
	}
function SGTimerStop()
	{
	var root = SG;
	root.timer_move.stop();
	root.timer_add.stop();
	}

function classTimer2(func,time)
{
this.id    = null;
this.state = 0;
this.start = function(func,time)
	{
	this.stop();
	this.init(func,time);	//,timernd
	this.id = setTimeout(this.func, this.time);
   	this.state = 1;
	}
this.stop = function()
	{
   	if (this.id!=null) {clearTimeout(this.id);}
   	this.state = 0;
	}
this.init = function(func,time)
	{
	this.func = typeof(func)!=='undefined' ? func : this.func;
	this.time = typeof(time)!=='undefined' ? time : this.time;
	}
this.init(func,time);
}

var SG;
function SGinit()
{
//SG = new classSnowGame(200);
SG = new classSnowGame();
}


/*


function pisNapis(vText)
{
vText = vText.split("");
var vPismenka =
	{
	"A":new Array(0.2 ,0.5 ,0.8 ,0.3),
	"h":new Array(1   ,0.5 ,0.75,0.4),
	"o":new Array(0.5 ,0.75,0.5),
	"j":new Array(0.75,0.9)
	};
var i,j,k,l,x,y,z,a,b, o,ox,fsize;
fsize = 20;
x = 100;
y = 150;
k = oBottomLine.length;
o = objGet("snowArea");
for (i in vText)
	{
	a=vText[i];
	ox=creEL(d,'DIV');
		ox.style.position   = "absolute";
		ox.style.left       = x+"px";
		ox.style.top        = y-fsize+"px";
		ox.style.fontSize   = fsize+"px";
		ox.style.lineHeight = fsize+"px";
		creaddTN(d,ox,a);
	appEL(o,ox); 
	for (j in vPismenka[a])
		{
		b = y-vPismenka[a][j]*fsize;
		for (l=0;l<3;l++)	//3x
			{oBottomLine[k] = new objText(x+j*3+l,b,y); k++;}
		}
	x+=fsize;
	}
}

//function pisObrazky()
//{
//var i,x,y,k,yy;
//x = 43;
//y = 37;
//yy= 0;
//k = oBottomLine.length; //pridam za lajnu
////for (i=0;i<70;i+=2)
//	{
//	yy = Math.floor(y-0.3*i);
//	k++;
//	oBottomLine[k] = new objText(x+i,yy,yy+5);
//	}
//for (i=70;i<140;i+=2)
////	{
////	yy = Math.floor(y-0.3*(140-i));
////	k++;
///	oBottomLine[k] = new objText(x+i,yy,yy+5);
//	}
//yy = 105;
//for (i=0;i<140;i+=2)
//	{
//	k++;
//	oBottomLine[k] = new objText(x+i,yy,yy+10);
//	}
//}

*/