/**
* Name: Multi-Level Architecture with Preys and Predators
* Author: 
* Description: This model shows how to use multi-level architecture. In this model, prey and predators agents move randomly 
*	 in the environment. When a prey agent perceive a predator, it flees trying to go to the closest shelters while the predator 
* 	 agent chases it. The shelters capture the prey agents fleeing, changing them into prey_in_shelter species, that predator 
* 	can't chase during a certain time. They are released after that time in an invisible state so that they can wander in the  
* 	environment without being chase by the predator, but also, for a certain time.
* Tags: multi_level, agent_movement
*/

model preys_predators_shelters

global { 
	//Parameters for the prey species
	rgb prey_color <- #green const: true;
	float prey_perception <- 20.0;
	float prey_size <- 2.0 const: true;
	float prey_speed <- 1.0;
	rgb prey_flee_color <- #orange;
	float prey_invisible_speed <- 3 * prey_speed;
	rgb prey_invisible_color <- #darkgray;  
	int prey_in_shelter_max_time min: 1 init: 200;
	int prey_invisible_max_time min: 1 max: 100 init: 70; 
	int number_of_preys min: 1 max: 1000 init: 500;
	
	//Parameters for the predator species
	rgb predator_color <- #red const: true;
	float predator_perception <- 3.0;
	float predator_size <- 4.0;
	float predator_speed <- 1.5;
	int number_of_predators min: 1 max: 100 init: 30; 
	geometry shape <- square(400);
	
	rgb predator_in_shelter_color <- #yellow const: true;
	 
	//Parameters for the shelter species
	rgb shelter_color <- #blue const: true; 
	float shelter_speed <- 1.5 const: true;
	geometry shelter_shape <- square (50.0);
	int number_of_shelter <- 2 const: true;
	
	
	init {
		create prey number: number_of_preys;
		create predator number: number_of_predators; 
		create shelter number: number_of_shelter {
			shape <- shelter_shape at_location any_point_in(world);
		}
	}
}
//Species prey which can move using the skill moving and its operators
species prey skills: [moving] control: fsm {
	geometry shape <- square (prey_size);
	rgb color <- prey_color;
	
	//List of all predators inside the perception of the prey
	list nearby_predators update:  predator overlapping (shape + prey_perception) ;
	int invisible_time min: 1 <- int(time);

	shelter nearest_shelter;		

	//State to make the prey move randomly when there isn't any predator, if so, change the state to flee
	state move_around initial: true {
		enter {
			color <- prey_color;
		}
		do wander speed: prey_speed; 
		
		transition to: flee_predator when: !(empty (nearby_predators)); 
	}
	
	//State to make the prey move to the closest shelter to flee from the predator, if no predator are perceived, change the state to move aroung
	state flee_predator {
		enter {
			color <- prey_flee_color;
			nearest_shelter <- shelter closest_to self;
		}
		if !(empty (nearby_predators)) { do move heading: (self) towards (nearest_shelter) speed: prey_speed;}
		
		transition to: move_around when: (empty (nearby_predators));
	}
	//State to make the prey invisible during a certain time when it is released by the shelters
	state invisible {
		enter {
			color <- prey_invisible_color;
			invisible_time <- int(time);
			heading <- rnd (360.0) ;
		}

		do move speed:prey_invisible_speed heading: heading ;
		transition to: move_around when: ( (time - invisible_time) > prey_invisible_max_time );
	}
	
	aspect default {
		draw  shape color: color;
	}
}

//Species predator which can move using the skill moving
species predator skills: [moving] schedules: shuffle (list (predator)) {
	geometry shape <- square (predator_size);
	prey target_prey update: self.choose_target_prey();
	
	//Change the target prey according to the prey who aren't fleeing if it doesn't have any yet
	action choose_target_prey type: prey {
		if ( (target_prey = nil) or (dead (target_prey) ) ) {
			return one_of ( (list (prey)) where (each.state = 'move_around') );
		}
		
		return target_prey;
	}
	//Reflex to move randomly when no prey are perceived
	reflex move_around when: (target_prey = nil) { do wander speed: predator_speed; }
	
	//Reflex to make the predator chase a prey
	reflex chase_prey when: (target_prey != nil) { do move heading: self towards target_prey speed: predator_speed;}
	
	aspect default {
		draw shape color: predator_color;
	} 
} 

//Species shelter that will capture prey agents
species shelter skills: [moving]  frequency: 2 {
	geometry shape <- (square (50.0)) at_location {250, 250};
	
	//List of all preys which are being chased and inside the shelter but not captured yet
	list chased_preys update: (prey) where ( (each.shape intersects shape) and (each.state = 'flee_predator') );
	
	//Capture all the chased preys inside the shelter and change their species to prey_in_shelter
	reflex capture_chased_preys when: !(empty (chased_preys)) { 
		capture chased_preys as: prey_in_shelter {
			state <- 'in_shelter'; 
			shape <- ( triangle (4.0) ) at_location location;
		}
	}
	
	//Release all the prey_in_shelter after a certain time and change their state to invisible after making their species returned to prey
	reflex release_member_preys {
		list to_be_released <- (prey_in_shelter) where ( (time - each.in_shelter_time) > prey_in_shelter_max_time );
		 
		release to_be_released in: world as: prey { 
			state <- 'invisible';
			shape <-  at_location (square (prey_size), self.location);   
		}
	} 
	
	//Subspecies prey_in_shelter that will represent the prey agents captured by the shelter
	species prey_in_shelter parent: prey frequency: 2 schedules: ( ( int ( (length (prey_in_shelter)) / 2 ) ) among (list (prey_in_shelter)) ) {
		int in_shelter_time <- int(time);
		
		state in_shelter {
			do wander speed: shelter_speed;
		}
		
		aspect default {
			draw  shape color: predator_in_shelter_color;
		} 
	}
	
	aspect default {
		draw shape color: shelter_color;
		draw (string (length ((members)))) color: rgb ('white') size: 6 at: location anchor: #center font: font("Helvetica", 12*#zoom, #bold);
	}
}

experiment default_experiment type: gui {
	output {
		display default_display background: #black{
			species prey aspect: default;
			species predator transparency: 0.5 aspect: default;
			species shelter transparency: 0.5 aspect: default { 
				species prey_in_shelter aspect: default;
			}
		}
	}
}