use core::ops::BitOr;

use alloc::vec::Vec;

use crate::file::PathRep;

// TODO: Get Able to document this
///
pub type SoundCardID = u8;
// TODO: Get Able to document this
///
pub type DeviceID = u8;
// TODO: Get Able to document this
///
pub type ControllerID = u8;

#[repr(u8)]
#[derive(Clone, Debug, PartialEq)]
/// Enum that specifies which abilities a program can have.
pub enum Ability {
   // TODO: Get Able to document this
   ///
   AllControllers = 0x01,
   // TODO: Get Able to document this
   ///
   AllFiles = 0x02,
   // TODO: Get Able to document this
   ///
   AllSoundCards = 0x04,
   // TODO: Get Able to document this
   ///
   Keyboard = 0x08,
   // TODO: Get Able to document this
   ///
   Mouse = 0x10,
   // TODO: Get Able to document this
   ///
   Telecomms = 0x20,
}

#[derive(Clone, Debug, Default, PartialEq)]
/// Wrapper for bit mask of Ability.
pub struct Permissions(u8);

/// The capabilities of a program. This must only be handled by kernel code.
/// Capabilities should never be set by user code, either directly or indirectly.
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Capabilities {
   perms: Permissions,
   files: Vec<PathRep>,
   controllers: Vec<ControllerID>,
   soundcards: Vec<SoundCardID>,
}

impl Capabilities {
   /// Generate a set of empty capabilities
   pub fn empty() -> Self {
      Self::default()
   }

   /// Generate a set of capabilities that allows all access
   /// to all devices
   ///
   /// # Safety
   /// This is a very dangerous function and should not be used
   /// unless you know what you are doing
   pub unsafe fn all() -> Self {
      Self {
         perms: Permissions::all(),
         ..Default::default()
      }
   }
   /// Checks if capabilities has this ability.
   pub fn has_ability(&self, ability: Ability) -> bool {
      self.perms.has_ability(ability)
   }
   /// Sets which individual files this capabilities grants access to.
   pub fn set_file_access(&mut self, files: Vec<PathRep>) {
      self.files = files;
   }
   /// Sets which individual controllers this capabilities grants access to.
   pub fn set_controller_access(&mut self, controllers: Vec<ControllerID>) {
      self.controllers = controllers;
   }
   /// Sets which individual soundcards this capabilities grants access to.
   pub fn set_soundcard_access(&mut self, soundcards: Vec<SoundCardID>) {
      self.soundcards = soundcards;
   }
}

impl Ability {
   /// Returns a bit mask with all abilities enabled.
   pub fn all() -> u8 {
      use Ability::*;
      AllControllers | AllFiles | AllSoundCards | Keyboard | Mouse | Telecomms
   }
}

impl BitOr for Ability {
   type Output = u8;
   fn bitor(self, rhs: Self) -> u8 {
      self as u8 | rhs as u8
   }
}

impl BitOr<u8> for Ability {
   type Output = u8;
   fn bitor(self, rhs: u8) -> u8 {
      self as u8 | rhs
   }
}

impl BitOr<Ability> for u8 {
   type Output = u8;
   fn bitor(self, rhs: Ability) -> u8 {
      self | rhs as u8
   }
}

impl Permissions {
   /// Returns self with all abilities enabled.
   pub fn all() -> Self {
      Self(Ability::all())
   }
   /// Checks if permissions has ability.
   pub fn has_ability(&self, ability: Ability) -> bool {
      self.0 & ability.clone() as u8 == ability as u8
   }
}