import de.grogra.imp3d.*;
import static de.grogra.xl.util.Operators.*;
import static de.grogra.rgg.Library.*;
import static de.grogra.imp3d.shading.RGBAShader.*;
import static java.lang.Math.*;

private static final float jahr = 100;
const DatasetRef population = new DatasetRef ("Population");

private class pflanze extends Cell {
	
	public int steps;
	public boolean dead;

	public pflanze (float x, float y, float l) {
		super(x,y,0,l,0.2f,true,0);
		this.setShader(GREEN);
		steps = (int)(random(0.5,1.5) * 80*jahr);
		dead = false;
	}
}

private class vegie extends Cell {
	
	public int steps;
	public Vector2d direction;
	
	public vegie (float x, float y) {
		super(x,y,0,10f,0.2f,true,0);
		this.setShader(BLUE);
		steps = (int)(random(0.5,1.2) * 10*jahr);
		direction = new Vector2d(1,1);
	}
}

private class meatie extends Cell {
	
	public int steps;
	public Vector2d direction;

	public meatie (float x, float y) {
		super(x,y,0,10f,0.2f,true,0);
		this.setShader(RED);
		steps = (int)(random(0.7,1.5) * 10*jahr);
		direction = new Vector2d(1,1);
	}
}

public class OekoSimulation extends RGG
{
    const int memory = EDGE_0;
    const int neighbour = EDGE_1;
	const int length = 20;
	int Samen = 0;	
	float steps = 0;
	
	private void setPopulation() {
		population.addRow().set(0,(steps/jahr),count((*meatie*))).set(1,steps/jahr,count((*vegie*))).set(2,steps/jahr,16*count((*pflanze*)));
	}
	
	protected void init()
	{
		steps = 0;
		Samen = 0;
		init0 ();
		apply ();
		init1 ();
		population.clear().setColumnKey(0,"Fleischfresser").setColumnKey(1,"Pflanzenfresser").setColumnKey(2,"Pflanzen");
		chart (population, XY_PLOT);
	}
	
	private boolean getTree(int i, int j) {
		
		if (irandom(0,10)== 1) return true;
		return false;
	}
	
	private boolean getVegies(int i, int j) {
		if (irandom(0,20)== 1) return true;
		return false;
	}

	private boolean getMeaties(int i, int j) {
		if (irandom(0,200)== 1) return true;
		return false;
	}

    private void init0()
    [
        // create a 80 * 80 grid of cells
        Axiom ==>> ^
			for(int i : (0 : length)) for(int j : (0 : length))
				(
					if (getTree(i,j)) ([pflanze(i,j,20)])
					else (if (getVegies(i,j)) ([vegie(i,j)])
						if (getMeaties(i,j)) ([meatie(i,j)])
					[Cell(i,j,0,0.01f,0.2f,true,0)])
				);
    ]


    private void init1()
    [
		c1:Cell, c2:Cell, ((c1 != c2) && (c1.distanceLinf (c2) < 1.1))
		    ==>> c1 -neighbour-> c2;
    ]


    public void run()
    [
		m:meatie ::> { 
			//Bewegung auf Vektor-Berechnung
			Vector2d next = new Vector2d(irandom(-1,1),irandom(-1,1));
			m[direction] += next;
			m[direction].normalize();
			if((m[x] + round(m[direction].x))>0 && (m[x] + round(m[direction].x))<length) {
				m[x] += round(m[direction].x);
			}
			if((m[y] + round(m[direction].y))>0 && (m[y] + round(m[direction].y))<length) {
				m[y] += round(m[direction].y);
			}
			
			m[length]-=0.45;
			
			m[steps]--;
			if(m[steps]%(1*jahr) == 0) {
				[
					==>>^ for((0 : irandom(1,3))) ([meatie(m[x],m[y])]);
				]
			}
		}
		
		m:meatie ::> {
			vegie v = selectRandomly((* w:vegie, (m.distance(w)<2) *));
			if (v != null && m[length] < 5) {
				v[length]=0;	
				m[length]+=2;
			}
		}
		
		m:meatie, (m[steps]==0 || m[length]<=0) ==>> ;
			
		v:vegie ::> {
			//Bewegung auf Vektor-Berechnung
			Vector2d next = new Vector2d(irandom(-1,1),irandom(-1,1));
			v[direction] += next;
			v[direction].normalize();
			if((v[x] + round(v[direction].x))>0 && (v[x] + round(v[direction].x))<length) {
				v[x] += round(v[direction].x);
			}
			if((v[y] + round(v[direction].y))>0 && (v[y] + round(v[direction].y))<length) {
				v[y] += round(v[direction].y);
			}
			
			v[length]-=0.8;
			
			v[steps]--;
			if((v[steps]%jahr == 0)) {
				[
					==>>^ for((0 : irandom(2,6))) ([vegie(v[x],v[y])]);
				]
			}
		}
		v:vegie, (v[steps]==0 || v[length]<=0) ==>> ;
		v:vegie ::> {
			pflanze t = selectRandomly((* p:pflanze, (v.distance(p)<2) *));
			if (t != null && v[length] < 2) {
				t[length]-=0.5;	
				if (v[length]<10) v[length]++;
				if (t[length]<=0) t[dead]=true;
			}
		}
		
		//Pflanze lebt und nach 100steps samt sie aus
		t:pflanze,(t[steps]>0) ::> {
			if (t[length]<20) {
				t[length]++;
				if (t[length]>5 && t[shader]!=GREEN) {
					t.setShader(GREEN);
				}
			}
			
			t[steps]--;
			if(t[steps]%(jahr/10) == 0) Samen+=100;
		}
		
		
		//Pflanze zu alt und sie stirbt ab
		t:pflanze, (t[steps]==0) ::>	{
			t.setShader(BLACK);
			t[length]--;
			if (t[length]<=0) t[dead] = true;
		}
		
		//Pflanze stirbt ab
		t:pflanze, (t[dead]) ==> [Cell(t[x],t[y],0,0.01f,0.2f,true,0)];
		
		{	
			//neue Pflanze kann wachsen wenn Samen da
			if(Samen >0) {
				wachsen();
				Samen--;
			}
			if (steps%(1) == 0) setPopulation();
			steps++;
		}
    ]
	
	private void wachsen() [
		
		==>>
		{
			Cell c = selectRandomly((*x:Cell*));
			
			if (!empty((*x:pflanze, (c.distance(x) < 3)*))) return;
		}
		
		^[t:pflanze(c[x],c[y],2)] {t.setShader(WHITE);};
	]
}

