use atom_file::Data;
use page_store::*;

/// Set of working pages, clean and changed.
pub struct PageSet {
    wapd: AccessPagedData,
    clean: HashMap<u64, Data>,
    changed: HashMap<u64, Data>,

    /// Variable length value storage data.
    pub vvs: (u64, u64, u64),

    /// System map table. Records are fixed size, (u64,u64), root and buckets.
    pub sys_map: (u64, u64, u64),

    /// Temporary kludge, should be some kind of map that holds this.
    pub cust_hashmap: (u64, u64),

    /// Temporary kludge, should be some kind of map that holds this.
    pub cust_by_email: (u64, u64),
}

impl PageSet {
    pub fn new(wapd: AccessPagedData) -> Self {
        // If not a new database, root1 and root2 need to be read from page 0.
        let root1 = wapd.alloc_page() + 1;
        let root2 = wapd.alloc_page() + 1;
        Self {
            wapd,
            clean: HashMap::default(),
            changed: HashMap::default(),
            vvs: (0, root1, 0),
            sys_map: (0, root2, 0),
            cust_hashmap: (0, 0),
            cust_by_email: (0, 0),
        }
    }

    pub fn new_page(&self) -> u64 {
        self.wapd.alloc_page() + 1 // Add 1 so that zero can be used as null page.
    }

    pub fn free_page(&mut self, pnum: u64) {
        // println!("free_page is to do - need to figure out how to adjust clean/dirty, pnum={}", pnum);
        self.clean.remove(&pnum);
        self.changed.remove(&pnum);
        self.wapd.free_page(pnum - 1);
    }

    pub fn load(&mut self, pnum: u64) -> (Data, bool) {
        if let Some(data) = self.clean.remove(&pnum) {
            (data, false)
        } else if let Some(data) = self.changed.remove(&pnum) {
            (data, true)
        } else {
            (self.wapd.get_data(pnum - 1), false)
        }
    }

    pub fn note(&mut self, pnum: u64, data: Data, changed: bool) {
        // println!("note pnum={} data={:?}", pnum, data);
        if changed {
            self.changed.insert(pnum, data);
        } else {
            self.clean.insert(pnum, data);
        }
    }

    pub fn save(&mut self) {
        for (pnum, data) in self.changed.drain() {
            println!("Saving data pnum={} len={}", pnum, data.len());
            self.wapd.set_data(pnum - 1, data);
        }
        self.wapd.save(SaveOp::Save);
    }
}
