use crate::*;

#[derive(
    Clone,
    Debug,
    Default,
    Hash,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    serde::Serialize,
    serde::Deserialize,
)]
/// Generic value.
pub enum Value {
    #[default]
    Empty,
    Int(i64),
    String(LString),
    Binary(LVec<u8>),
    List(LVec<Value>),
    Enum(usize, LBox<Value>),
    VarVal(u64, u64),
    IList(LVec<i64>),
    DataType(DataType),
    TabInfo(TabInfo),
}

impl Value {
    // Get mut reference to List LVec ( Value must be List )
    pub fn list_mut(&mut self) -> &mut LVec<Value> {
        match self {
            Value::List(list) => list,
            _ => panic!("list expected"),
        }
    }

    // Get reference to List LVec ( Value must be List )
    pub fn list(&self) -> &LVec<Value> {
        match self {
            Value::List(list) => list,
            _ => panic!("list expected"),
        }
    }

    pub fn en_mut(&mut self) -> (&usize, &mut Value) {
        match self {
            Value::Enum(tag, bx) => (tag, &mut **bx),
            _ => panic!("enum expected"),
        }
    }

    pub fn en(&self) -> (&usize, &Value) {
        match self {
            Value::Enum(tag, bx) => (tag, &**bx),
            _ => panic!("enum expected"),
        }
    }

    /// Get reference to IList LVec ( Value must be IList )
    pub fn ilist(&self) -> &LVec<i64> {
        match self {
            Value::IList(list) => list,
            _ => panic!("ilist expected"),
        }
    }

    /// Get mut reference to IList LVec ( Value must be IList )
    pub fn ilist_mut(&mut self) -> &mut LVec<i64> {
        match self {
            Value::IList(list) => list,
            _ => panic!("ilist expected"),
        }
    }

    /// Get reference to LString ( Value must be String )
    pub fn string(&self) -> &LString {
        match self {
            Value::String(s) => s,
            _ => panic!("string expected"),
        }
    }

    /// Get reference to LVec ( Value must be Binary )
    pub fn binary(&self) -> &LVec<u8> {
        match self {
            Value::Binary(b) => b,
            _ => panic!("binary expected"),
        }
    }

    pub fn int(&self) -> i64 {
        match self {
            Value::Int(x) => *x,
            _ => panic!("int expected"),
        }
    }

    /// Get reference to DataType ( Value must be DataType )
    pub fn datatype(&self) -> &DataType {
        match self {
            Value::DataType(dt) => dt,
            _ => panic!("datatype expected"),
        }
    }

    pub fn datatype_mut(&mut self) -> &mut DataType {
        match self {
            Value::DataType(dt) => dt,
            _ => panic!("datatype expected"),
        }
    }

    pub fn tabinfo(&self) -> &TabInfo {
        match self {
            Value::TabInfo(x) => x,
            _ => panic!("tabinfo expected"),
        }
    }

    pub fn tabinfo_mut(&mut self) -> &mut TabInfo {
        match self {
            Value::TabInfo(x) => x,
            _ => panic!("tabinfo expected"),
        }
    }
}
