/**
* Name: Corridor Multi-Level Architecture
* Author: Vo Duc An; Ngoc Anh; JD Zucker; A. Drogoul
* Description: This model shows how to use multi-level architecture. A corridor can capture pedestrians going from left to right side if 
*	they are inside the corridor. This will result in changing their species from pedestrian to captured_pedestrian which will not be 
*	displayed. Once they pass enought time to consider they reach the exit of the corridor, they will be released by the corridor agent 
*	as pedestrians, letting them been displayed and going to their target. 
* Tags: multi_level, agent_movement
*/
model corridor

global {
//Capture pedestrians parameter to define if wall will capture pedestrians
	bool capture_pedestrians <- false;
	int environment_width init: 8000;
	int environment_height init: 3000;
	geometry shape <- rectangle(environment_width, environment_height);

	//Pedestrians parameters
	rgb pedestrian_color <- #green;
	float pedestrian_speed <- 10.0;

	//Wall parameters
	float corridor_width <- environment_width / 1.5;
	int corridor_wall_height <- 800;
	geometry corridor_wall_0_shape <- rectangle({corridor_width, corridor_wall_height}) at_location {environment_width / 2, corridor_wall_height / 2};
	geometry corridor_wall_1_shape <- rectangle({corridor_width, corridor_wall_height}) at_location {environment_width / 2, environment_height - (corridor_wall_height / 2)};
	

	//Corridor parameters
	float corridor_left_bounds <- (location.x - (corridor_width / 2));
	float corridor_right_bounds <- (location.x + (corridor_width / 2));

	init {
		create corridor;
	}

	reflex change_color when: every(200 #cycle) {
		pedestrian_color <- rnd_color(255);
	}

	reflex generate_pedestrians when: every(4 #cycle) {
		create pedestrian number: 30 with: [color::pedestrian_color] {
			do init_location({0, rnd(environment_height)});
		}
	}
}

//Species pedestrian which will move from one side of the experiment to another and destroy itself once the other side is reached
species pedestrian skills: [moving] topology: (topology(shape - (corridor_wall_0_shape + corridor_wall_1_shape))) {
	point target_location;
	rgb color;

	action init_location (point loc) {
		location <- loc;
		target_location <- {environment_width, loc.y};
		speed <- rnd(pedestrian_speed - 5) + 5.0;
	}
	
	
	reflex change_speed when: every(rnd(200) #cycle) {
			speed <- rnd(pedestrian_speed - 5) + 5.0;
	}

	//Reflex to make the agent move to its target_location
	reflex move {
		point previous_location <- location;

		if (location.y < corridor_wall_height) and (location.x <= (environment_width / 2)) {
			do move heading: self towards {(environment_width / 2) - (corridor_width / 2), corridor_wall_height};
		} else if (location.y > environment_height - corridor_wall_height) and (location.x <= (environment_width / 2)) {
			do move heading: self towards {(environment_width / 2) - (corridor_width / 2), environment_height - corridor_wall_height};
		} else {
			do move heading: self towards target_location;
		}
		if (location.x = previous_location.x) { // No move detected
			do move heading: self towards {environment_width, world.shape.location.y};
		}
	}

	reflex arrived when: location.x >= target_location.x {
		do die;
	}

}

//Species which represents the corridor
species corridor {
	geometry shape <- ((rectangle({corridor_width, environment_height})) at_location world.location) - (corridor_wall_0_shape + corridor_wall_1_shape);

	//Subspecies for the multi-level architectures : captured pedestrians in this case
	species captured_pedestrian parent: pedestrian schedules: [] {
		float release_time;
	}

	//Reflex to capture pedestrians if the parameter is checked
	reflex aggregate when: capture_pedestrians {
	//If we have pedestrians inside the corridor, we capture them
	//We update the time during which a pedestrian is captured according to the time the pedestrian
	// should need to pass through the corridor if it wasn't captured
		capture (pedestrian where (p: p.location.x between (corridor_left_bounds, corridor_right_bounds))) as: captured_pedestrian {
			release_time <- time + ((corridor_width - (location.x - ((environment_width / 2) - (corridor_width / 2)))) / (pedestrian_speed - 2.5));
		} }

		//Reflex to release pedestrians which have already passed enough time in the corridor
	// which means if they weren't captured by the corridor, they would have finish passing through it
	reflex disaggregate {
		list tobe_released_pedestrians <- captured_pedestrian where (time >= each.release_time);
		if !(empty(tobe_released_pedestrians)) {
			release tobe_released_pedestrians as: pedestrian in: world {
				location <- {((environment_width / 2) + (corridor_width / 2)), (location).y};
			}

		}
	}
}

experiment "Corridor" type: gui autorun: true {
	point button_location;
	bool button_hover;
	geometry corridor_wall_0_display <- rectangle({corridor_width-30, corridor_wall_height-30}) at_location {environment_width / 2, corridor_wall_height / 2};
	geometry corridor_wall_1_display <- rectangle({corridor_width-30, corridor_wall_height-30}) at_location {environment_width / 2, environment_height - (corridor_wall_height / 2)};
	
	init {
		button_location <- {simulation.corridor_left_bounds + 100, 100};  
	}
	output {
		display defaut_display type: java2D background: #black fullscreen: true toolbar: false {
			graphics back {
				draw shape color: #black wireframe: false;
				draw corridor_wall_0_display color: #gray wireframe: true;
				draw corridor_wall_1_display color: #gray wireframe: true ;
			}

			species corridor {
				draw shape color: #black;
			}
			
			agents "Captured" value: list(corridor(0).captured_pedestrian) transparency: 0.5 {
				draw square(30) wireframe: false color: #white;
			}

			species pedestrian {
				draw square(20) wireframe: false color: color;
			}

			graphics front {
				draw (capture_pedestrians ? "Capturing":"Not capturing") anchor: #left_center at: {corridor_left_bounds + 200, 100} color: !capture_pedestrians ? #darkred : #darkgreen font: font("Helvetica", 20 * #zoom, 0);
				draw ("Captured: " + length(corridor(0).captured_pedestrian)) anchor: #left_center at: {corridor_left_bounds + 200, 250} color: #white font: font("Helvetica", 20 * #zoom, 0);
				draw ("Pedestrians: " + length(pedestrian)) anchor: #left_center at: {corridor_left_bounds + 200, 400} color: #white font: font("Helvetica", 20 * #zoom, 0);
				draw ("Step duration (ms): " + (duration copy_between (0, 4))) anchor: #left_center at: {corridor_left_bounds + 200, 550} color: #white font: font("Helvetica", 20 * #zoom, 0);
			}

			graphics button {
				draw circle(50) color: #darkgray at: button_location;
				draw circle(40) color: !capture_pedestrians ? (button_hover ? #yellow : #red) : (button_hover ? #lightgreen : #darkgreen) at:  button_location;
			}

			event mouse_down {
				if (button_location distance_to #user_location <= 50) {
					capture_pedestrians <- !capture_pedestrians;
				}
			}
			event mouse_move {
				button_hover <- (button_location distance_to #user_location <= 50);
			}
		}
	}

}