use crate::world_view::{
self,
Dirn,
ElevatorBehaviour,
ElevatorContainer,
WorldView
};
use crate::print;
use crate::network;
use std::collections::HashMap;
use std::sync::Mutex;
use std::time::{Duration, Instant};
use std::sync::LazyLock;
static HALL_INSTANTS: LazyLock<Mutex<[[Instant; 2]; 4]>> = LazyLock::new(|| {
Mutex::new(std::array::from_fn(|_| {
std::array::from_fn(|_| Instant::now())
}))
});
pub fn join_wv_from_udp(
my_wv: &mut WorldView,
master_wv: &mut WorldView
) -> bool
{
let my_self_index = world_view::get_index_to_container(network::read_self_id() , my_wv);
let master_self_index = world_view::get_index_to_container(network::read_self_id() , master_wv);
if let (Some(i_org), Some(i_new)) = (my_self_index, master_self_index)
{
let my_view = &my_wv.elevator_containers[i_org];
let master_view = &mut master_wv.elevator_containers[i_new];
master_view.dirn = my_view.dirn;
master_view.behaviour = my_view.behaviour;
master_view.obstruction = my_view.obstruction;
master_view.last_floor_sensor = my_view.last_floor_sensor;
master_view.unsent_hall_request = my_view.unsent_hall_request.clone();
master_view.cab_requests = my_view.cab_requests.clone();
} else if let Some(i_org) = my_self_index
{
master_wv.add_elev(my_wv.elevator_containers[i_org].clone());
}
*my_wv = master_wv.clone();
true
}
pub fn abort_network(
wv: &mut WorldView
) -> bool
{
wv.elevator_containers.retain(|elevator| elevator.elevator_id == network::read_self_id());
wv.set_num_elev(wv.elevator_containers.len() as u8);
wv.master_id = network::read_self_id();
wv.hall_request = merge_hall_requests(&wv.hall_request, &wv.elevator_containers[0].tasks);
true
}
pub async fn join_wv_from_container(
wv: &mut WorldView,
container: &ElevatorContainer
) -> bool
{
if None == wv.elevator_containers.iter().position(|x| x.elevator_id == container.elevator_id)
{
wv.add_elev(container.clone());
}
let self_idx = world_view::get_index_to_container(container.elevator_id, &wv);
if let Some(i) = self_idx
{
for (row1, row2) in wv.hall_request.iter_mut().zip(container.unsent_hall_request.iter())
{
for (val1, val2) in row1.iter_mut().zip(row2.iter())
{
if !*val1 && *val2
{
*val1 = true;
}
}
}
if wv.elevator_containers[i].behaviour != ElevatorBehaviour::ObstructionError || wv.elevator_containers[i].behaviour != ElevatorBehaviour::TravelError
{
wv.hall_request = merge_hall_requests(&wv.hall_request, &wv.elevator_containers[i].tasks);
}
if world_view::is_master(wv)
{
wv.elevator_containers[i].unsent_hall_request = vec![[false; 2]; wv.elevator_containers[i].num_floors as usize];
}
wv.elevator_containers[i].cab_requests = container.cab_requests.clone();
wv.elevator_containers[i].elevator_id = container.elevator_id;
wv.elevator_containers[i].last_floor_sensor = container.last_floor_sensor;
wv.elevator_containers[i].num_floors = container.num_floors;
wv.elevator_containers[i].obstruction = container.obstruction;
wv.elevator_containers[i].dirn = container.dirn;
wv.elevator_containers[i].behaviour = container.behaviour;
wv.elevator_containers[i].last_behaviour = container.last_behaviour;
for (idx, [up, down]) in wv.hall_request.iter_mut().enumerate()
{
if (wv.elevator_containers[i].behaviour == ElevatorBehaviour::DoorOpen) && (wv.elevator_containers[i].last_floor_sensor == (idx as u8))
{
let floor = wv.elevator_containers[i].last_floor_sensor as usize;
let dirn = match wv.elevator_containers[i].dirn
{
Dirn::Down => Some(1),
Dirn::Up => Some(0),
Dirn::Stop => None,
};
if wv.elevator_containers[i].last_behaviour != ElevatorBehaviour::DoorOpen
{
update_hall_instants(floor, Some(0));
update_hall_instants(floor, Some(1));
}
if wv.elevator_containers[i].dirn == Dirn::Up && time_since_hall_instants(floor, dirn) > Duration::from_secs(3)
{
*up = false;
} else if wv.elevator_containers[i].dirn == Dirn::Down && time_since_hall_instants(floor, dirn) > Duration::from_secs(3)
{
*down = false;
}
}
}
update_cab_request_backup(&mut wv.cab_requests_backup, wv.elevator_containers[i].clone());
return true;
} else
{
print::cosmic_err("The elevator does not exist join_wv_from_conatiner()".to_string());
return false;
}
}
pub fn remove_container(
wv: &mut WorldView,
id: u8
) -> bool
{
wv.remove_elev(id);
true
}
pub fn clear_from_sent_data(
wv: &mut WorldView,
tcp_container: ElevatorContainer
) -> bool
{
let self_idx = world_view::get_index_to_container(network::read_self_id() , &wv);
if let Some(i) = self_idx
{
for (row1, row2) in wv.elevator_containers[i].unsent_hall_request
.iter_mut()
.zip(tcp_container.unsent_hall_request.iter())
{
for (val1, val2) in row1
.iter_mut()
.zip(row2.iter())
{
if *val1 && *val2
{
*val1 = false;
}
}
}
return true;
} else
{
print::cosmic_err("The elevator does not exist clear_sent_container_stuff()".to_string());
return false;
}
}
pub fn distribute_tasks(
wv: &mut WorldView,
map: HashMap<u8, Vec<[bool; 2]>>
) -> bool
{
for elev in wv.elevator_containers.iter_mut()
{
if let Some(tasks) = map.get(&elev.elevator_id)
{
elev.tasks = tasks.clone();
}
}
true
}
pub fn update_elev_states(
wv: &mut WorldView,
container: ElevatorContainer
) -> bool
{
let idx = world_view::get_index_to_container(container.elevator_id, wv);
if let Some(i) = idx
{
wv.elevator_containers[i].cab_requests = container.cab_requests;
wv.elevator_containers[i].dirn = container.dirn;
wv.elevator_containers[i].obstruction = container.obstruction;
wv.elevator_containers[i].behaviour = container.behaviour;
wv.elevator_containers[i].last_behaviour = container.last_behaviour;
wv.elevator_containers[i].last_floor_sensor = container.last_floor_sensor;
wv.elevator_containers[i].unsent_hall_request = container.unsent_hall_request;
}
true
}
pub fn merge_wv_after_offline(
my_wv: &mut WorldView,
read_wv: &mut WorldView)
{
if my_wv.master_id < read_wv.master_id
{
read_wv.hall_request = merge_hall_requests(&read_wv.hall_request, &my_wv.hall_request);
read_wv.master_id = my_wv.master_id;
let my_wv_elevs: Vec<ElevatorContainer> = my_wv.elevator_containers.clone();
let existing_ids: std::collections::HashSet<u8> = read_wv
.elevator_containers
.iter()
.map(|e| e.elevator_id)
.collect();
for elev in my_wv_elevs
{
if !existing_ids.contains(&elev.elevator_id)
{
read_wv.elevator_containers.push(elev);
}
}
} else
{
read_wv.hall_request = merge_hall_requests(&read_wv.hall_request, &my_wv.hall_request);
}
*my_wv = read_wv.clone();
}
fn update_hall_instants(
floor: usize,
direction: Option<usize>
)
{
if let Some(dirn) = direction
{
let mut lock = HALL_INSTANTS.lock().unwrap();
lock[floor][dirn] = Instant::now();
}
}
fn time_since_hall_instants(
floor: usize,
direction: Option<usize>
) -> std::time::Duration
{
if let Some(dirn) = direction
{
let lock = HALL_INSTANTS.lock().unwrap();
return lock[floor][dirn].elapsed()
}
return Instant::now().elapsed();
}
fn update_cab_request_backup(
backup: &mut HashMap<u8, Vec<bool>>,
container: ElevatorContainer
)
{
backup.insert(container.elevator_id, container.cab_requests);
}
fn merge_hall_requests(
hall_req_1: &Vec<[bool; 2]>,
hall_req_2: &Vec<[bool; 2]>
) -> Vec<[bool; 2]>
{
let mut merged_hall_req = hall_req_1.clone();
merged_hall_req
.iter_mut()
.zip(hall_req_2)
.for_each(|(read, my)| {
read[0] |= my[0];
read[1] |= my[1];
});
if hall_req_2.len() > hall_req_1.len()
{
merged_hall_req
.extend_from_slice(&hall_req_2[hall_req_1.len()..]);
}
merged_hall_req
}