var threshold = 100;
var minVelocity = 3.0;
var maxVelocity = 7.0;
var craziness = 2.0;
var rConst = 1.0;
var aConst = 1.0;
var idealDist = 60.0;
var flock;
var boidInterval;
var blowInterval;
var moveInterval;

function boid_loader(container_id){
    flock = new Array();
    moveInterval = setInterval(moveBoids, 200, container_id);
    boidInterval = setInterval(addNewBoid, 1000, container_id);
    var boidText = new Text("no bugs were harmed during making of this demo", 20, "Courier", "white", new Array(-500, 300));
    setTimeout(changeText, 10000, boidText, "uh oh...", new Array(-500, 300), "white");
    setTimeout(changeText, 20000, boidText, "children, close your eyes", new Array(-500, 300), "white");
    boidText.createSVGRef(container_id);
}

function addNewBoid(container_id) {
    if(flock.length <= 25){
        var new_boid = new boid();
        flock.push(new_boid);
        drawNewBoid(flock[flock.length-1], container_id);
        var greyLevel = Math.floor(255-255*flock.length/25);
        setCanvasColor("rgb("+greyLevel+", "+greyLevel+", "+greyLevel+")");
    }
    else{
        blowIntreval = setInterval(blowBoids, 200, container_id);
        clearInterval(boidInterval);
    }
}

function blowBoids(container_id){
    if(flock.length > 0){
        var target = flock.shift();
        var tX = target.xPos;
        var tY = target.yPos;
        var kaikki = document.getElementById(container_id);
        kaikki.removeChild(kaikki.getElementsByTagName("use")[0]);
        var explo = document.createElementNS(svgNS, "use");
        explo.setAttributeNS(xlinkNS, "href", "#EXPLO");
        explo.setAttributeNS(null, "transform", "translate(" + (tX-15) + " " + (tY-15) + ")");
        kaikki.appendChild(explo);
        setTimeout(clearExplo, 200, explo, kaikki);
    }
    else{
        clearInterval(blowInterval);
    }
}

function clearExplo(e, kaikki){
    kaikki.removeChild(e);
}

function drawNewBoid(boid, container_id){
    var new_boid = document.createElementNS(svgNS, "use");
    new_boid.setAttributeNS(xlinkNS, "href", "#TUOKKO");
    new_boid.setAttributeNS(null, "transform", "translate(" + boid.xPos + " " + boid.yPos + ")" );
    document.getElementById(container_id).appendChild(new_boid);
}

function boid(){
    this.xPos = Math.random()*halfXReso*2.0;
    this.yPos = Math.random()*halfYReso*2.0;
    this.xDir = (Math.random()*(maxVelocity-minVelocity) + minVelocity)*plusOrMinusOne();
    this.yDir = (Math.random()*(maxVelocity-minVelocity) + minVelocity)*plusOrMinusOne();
}

function moveBoids(container_id){
    for(var i = 0; i < flock.length; i++){
	    moveOneBoid(flock[i]);
    	var kaikki = document.getElementById(container_id);
	    var svgRef = kaikki.getElementsByTagName("use")[i];
    	drawBoid(svgRef, flock[i]);
    }
}

function moveOneBoid(boid){
    //original direction
    var xDisp = boid.xDir;
    var yDisp = boid.yDir;
    //calculate repulsive and attractive forces affecting this boid
    var forces = calculateForces(boid);
    xDisp += forces[0]+ Math.random()*craziness*plusOrMinusOne();
    yDisp += forces[1]+ Math.random()*craziness*plusOrMinusOne();
    var dispLength = distanceFromO(xDisp, yDisp);
    
    //limit the speed between minimum and maximum velocity
    if(dispLength < minVelocity){
	xDisp = minVelocity*xDisp/dispLength;
	yDisp = minVelocity*yDisp/dispLength;
    }
    if(dispLength > maxVelocity){
        xDisp = maxVelocity*xDisp/dispLength;
        yDisp = maxVelocity*yDisp/dispLength;
    }
    //apply the calculated movement
    boid.xPos += xDisp;
    boid.yPos += yDisp;
    //if moved outside the frame, jump to the other side
    if(boid.xPos < -15.0) boid.xPos = halfXReso*2.0 + 10.0;
    if(boid.xPos > halfXReso*2.0 + 15.0) boid.xPos = - 10.0;
    if(boid.yPos < -15.0) boid.yPos = halfYReso*2.0 + 10.0;
    if(boid.yPos > halfYReso*2.0 + 15.0) boid.yPos = - 10.0;
    //save the new distance
    boid.xDir = xDisp;
    boid.yDir = yDisp;
}

function calculateForces(boid){
    //iterate over all the boids
    var disp = new Array(0, 0);
    for(var j = 0; j < flock.length; j++){
        var rand = Math.random()*5;
    	if(boid != flock[j]){
	        //are the boids naighbors?
    	    var dist = distance(boid, flock[j]);
    	    if(dist <= threshold){
    		//if distance is zero, move this boid slightly
    		if(dist == 0){
                flock[j].xPos += 0.1*plusOrMinusOne();
                flock[j].yPos += 0.1*plusOrMinusOne();
                dist = distance(boid, flock[j]);
            }
    	    //calculate the difference vector
    		var diffVector = diff(boid, flock[j]);
    	    //calculate attractive and repulsive forces
        	var att = aConst*dist*dist/(rand+idealDist);
        	var rep = -1.0*rConst*(idealDist+rand)*(idealDist+rand)/dist;
               
        	//calculate sum of the forces * unit vector parallel to the difference vector
        	if(dist == 0) log("STOP! fAtt jakaa nollalla!");
    		disp[0] += (diffVector[0]/dist)*(att + rep);
	        disp[1] += (diffVector[1]/dist)*(att + rep);
    	    }
    	}
    }
    return disp;
}

function distance(u, v){
    var x = v.xPos - u.xPos
    var y = v.yPos - u.yPos
    return Math.sqrt(x*x + y*y);
}

function distanceFromO(x,y) {
    return Math.sqrt(x*x + y*y);
}
function length(u){
    return Math.sqrt(u.xPos*u.xPos + u.yPos*u.yPos);
}

function diff(u, v){
    var result = new Array(v.xPos - u.xPos, v.yPos - u.yPos);
    return result;
}
