//! Burritos stores a data structure associating object ids with
//! their references. The ObjAddr struct
//! allows to maintain this data structure.

use std::{collections::HashMap, cell::RefCell, rc::Rc};

use crate::kernel::{synch::{ Semaphore, Lock }, thread::Thread};

/// Brief Definition of object identifiers:
/// 
/// The struct stores the list of created objects (Semaphore, Lock, ...) and for each of them
/// associates an object identifier than can be passed to subsequent
/// system calls on the object.
/// 
/// A method allows to detect of an object corresponding to a given
/// identifier exists; this is used to check the parameters of system
/// calls.
#[derive(PartialEq)]
pub struct ObjAddr {
    last_id: i32,
    semaphores: HashMap<i32, Semaphore>,
    locks: HashMap<i32, Lock>,
    threads: HashMap<i32, Rc<RefCell<Thread>>>,
}

impl ObjAddr {
    
    /// Initializes and returns a ObjAddr struct
    pub fn init() -> Self {
        Self {
            last_id: 3,
            semaphores: HashMap::<i32, Semaphore>::new(),
            locks: HashMap::<i32, Lock>::new(),
            threads: HashMap::<i32, Rc<RefCell<Thread>>>::new(),
        }
    }

    /// Adds the **obj** Semaphore to self
    pub fn add_semaphore(&mut self, obj: Semaphore) -> i32 {
        self.last_id += 1;
        self.semaphores.insert(self.last_id, obj);
        self.last_id
    }

    /// Adds the **obj** Lock to self
    pub fn add_lock(&mut self, obj: Lock) -> i32 {
        self.last_id += 1;
        self.locks.insert(self.last_id, obj);
        self.last_id
    }

    /// Adds the **obj** Lock to self
    pub fn add_thread(&mut self, obj: Rc<RefCell<Thread>>) -> i32 {
        self.last_id +=1;
        self.threads.insert(self.last_id, obj);
        self.last_id
    }

    /// Searches for a semaphore of id **id** in self
    pub fn search_semaphore(&mut self, id: i32) -> Option<&mut Semaphore> {
        self.semaphores.get_mut(&id)
    }

    /// Searches for a lock of id **id** in self
    pub fn search_lock(&mut self, id:i32) -> Option<&mut Lock> {
        self.locks.get_mut(&id)
    }

    /// Update lock at given id
    pub fn update_lock(&mut self, id: i32, lock: Lock) {
        self.locks.insert(id, lock);
    }

    /// Searches for a lock of id **id** in self
    pub fn search_thread(&mut self, id: i32) -> Option<&Rc<RefCell<Thread>>> {
        self.threads.get(&id)
    }

    /// Removes the object of id **id** from self if it exists
    pub fn remove_semaphore(&mut self, id: i32) -> Option<Semaphore> {
        self.semaphores.remove(&id)
    }

    /// Remove the object of id **id** from self if it exists
    pub fn remove_lock(&mut self, id:i32) -> Option<Lock> {
        self.locks.remove(&id)
    }

    /// Remove the object of id **id** from self if it exists
    pub fn remove_thread(&mut self, id: i32) -> Option<Rc<RefCell<Thread>>> {
        self.threads.remove(&id)
    }


}