root 0.1.1

root is an abstract I/O free routing protocol
Documentation
use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use root::concepts::neighbour::Neighbour;
use root::concepts::packet::Packet;
use root::framework::RoutingSystem;
use root::router::{DummyMAC, NoMACSystem, Router};

#[derive(Serialize, Deserialize)]
pub struct VirtualSystem{
    pub routers: Vec<Router<VirtualSystem>>,
    pub packets: BTreeMap<String, Vec<(DummyMAC<Packet<VirtualSystem>>, i32)>>,
}

impl VirtualSystem{
    pub fn create(nodes: &[&str], links: &[(i32, &str, &str, u16)]) -> VirtualSystem{
        let routers: Vec<Router<VirtualSystem>> = nodes.iter().map(|id|{
            let mut router = Router::new(id.to_string());
            for (lid, a, b, metric) in links{
                if a == id || b == id {
                    let nid = {
                        if a == id {b} else {a}
                    };
                    router.links.insert(*lid, Neighbour{
                        addr: nid.to_string(),
                        routes: Default::default(),
                        metric: *metric,
                    });
                }
            }
            router
        }).collect();
        VirtualSystem{
            routers,
            packets: Default::default()
        }
    }

    pub fn update_edge(&mut self, edge_id: i32, metric: u16){
        for router in &mut self.routers{
            router.links.entry(edge_id).and_modify(|edge| {
                edge.metric = metric
            });
        }
    }
    
    pub fn get_node(&mut self, node: &str) -> &mut Router<Self>{
        self.routers.iter_mut().find(|r| r.address == node).unwrap()
    }
    
    pub fn get_next_hop(&self, cur: &str, src: &str) -> String{
        let router = self.routers.iter().find(|r|r.address == cur).unwrap_or_else(|| panic!("No node {cur} found"));
        router.routes.get(src).unwrap_or_else(|| panic!("No route found to {src}")).next_hop.to_string()
    }

    pub fn get_metric_to(&self, cur: &str, src: &str) -> u16{
        let router = self.routers.iter().find(|r|r.address == cur).unwrap_or_else(|| panic!("No node {cur} found"));
        router.routes.get(src).unwrap_or_else(|| panic!("No route found to {src}")).metric
    }

    pub fn get_seqno_to(&self, cur: &str, src: &str) -> u16{
        let router = self.routers.iter().find(|r|r.address == cur).unwrap_or_else(|| panic!("No node {cur} found"));
        router.routes.get(src).unwrap_or_else(|| panic!("No route found to {src}")).source.data.seqno
    }

    pub fn flush_packets(&mut self){
        for router in &mut self.routers{
            for packet in router.outbound_packets.drain(..){
                let link_packets = self.packets.entry(packet.dest).or_default();
                link_packets.push((packet.packet, packet.link));
            }
        }
    }
    
    pub fn tick(&mut self){
        for (node, packets) in &mut self.packets{
            if let Some(router) = self.routers.iter_mut().find(|x|x.address == *node){
                for (packet, link) in packets{
                    if let Some(neigh_addr) = router.links.get(link).map(|x| x.addr.clone()){
                        router.handle_packet(packet, link, &neigh_addr).unwrap();
                    }
                }
            }
        }
        self.packets.clear();
        for router in &mut self.routers{
            router.full_update();
        }
        self.flush_packets()
    }

    pub fn tick_n(&mut self, times: i32){
        for _ in 0..times{
            self.tick();
        }
    }

    pub fn freeze(&mut self) -> String{
        serde_json::to_string(&self).unwrap()
    }

    pub fn restore(state: String) -> VirtualSystem{
        serde_json::from_str(&state).unwrap()
    }
}

impl RoutingSystem for VirtualSystem{
    type NodeAddress = String;
    type Link = i32;
    type MACSystem = NoMACSystem;
}