use crate::DecodedKey;

#[derive(Debug, Clone, Copy)]
pub enum LayoutEntryKind {
    Regular,
    Numlockable,
    Capslockable,
}

impl Default for LayoutEntryKind {
    fn default() -> Self {
        Self::Regular
    }
}

#[derive(Debug, Clone, Copy, Default)]
pub struct LayoutEntry {
    pub kind: LayoutEntryKind,
    pub unshifted: Option<DecodedKey>,
    pub shifted: Option<DecodedKey>,
    pub locked: Option<DecodedKey>,
    pub locked_shifted: Option<DecodedKey>,
    pub altgr: Option<DecodedKey>,
    pub raw_unicode: Option<DecodedKey>,
}

impl LayoutEntry {
    #[must_use]
    pub fn regular() -> Self {
        Self {
            kind: LayoutEntryKind::Regular,
            ..Default::default()
        }
    }

    #[must_use]
    pub fn numpad() -> Self {
        Self {
            kind: LayoutEntryKind::Numlockable,
            ..Default::default()
        }
    }

    #[must_use]
    pub fn alphabet() -> Self {
        Self {
            kind: LayoutEntryKind::Capslockable,
            ..Default::default()
        }
    }

    #[must_use]
    pub fn unshifted(mut self, c: impl Into<DecodedKey>) -> Self {
        self.unshifted = Some(c.into());
        self
    }

    #[must_use]
    pub fn shifted(mut self, c: impl Into<DecodedKey>) -> Self {
        self.shifted = Some(c.into());
        self
    }

    #[must_use]
    pub fn altgr(mut self, c: impl Into<DecodedKey>) -> Self {
        self.altgr = Some(c.into());
        self
    }

    #[must_use]
    pub fn raw_unicode(mut self, c: impl Into<DecodedKey>) -> Self {
        self.raw_unicode = Some(c.into());
        self
    }

    #[must_use]
    pub fn locked(mut self, c: impl Into<DecodedKey>) -> Self {
        self.locked = Some(c.into());
        self
    }

    #[must_use]
    pub fn locked_shifted(mut self, c: impl Into<DecodedKey>) -> Self {
        self.locked_shifted = Some(c.into());
        self
    }

    #[must_use]
    pub fn common(self, c: impl Into<DecodedKey> + Clone) -> Self {
        self.unshifted(c.clone())
            .shifted(c.clone())
            .locked(c.clone())
            .locked_shifted(c)
    }

    #[must_use]
    pub fn low(self, c: impl Into<DecodedKey> + Clone) -> Self {
        self.unshifted(c.clone()).locked_shifted(c)
    }

    #[must_use]
    pub fn high(self, c: impl Into<DecodedKey> + Clone) -> Self {
        self.shifted(c.clone()).locked(c)
    }

    #[must_use]
    pub fn all(self, c: impl Into<DecodedKey> + Clone) -> Self {
        self.unshifted(c.clone())
            .shifted(c.clone())
            .locked(c.clone())
            .locked_shifted(c.clone())
            .altgr(c.clone())
            .raw_unicode(c)
    }
}
