use crate::{
    keyboard::EXTENDED_KEY_CODE, DecodeState, Error, KeyCode, KeyEvent, KeyState, ScancodeSet,
};

pub struct CustomScancodeSet {
    single_byte: [Option<KeyCode>; 256],
    extended: [Option<KeyCode>; 256],
}

impl Default for CustomScancodeSet {
    fn default() -> Self {
        Self::scancode_set1()
    }
}

impl CustomScancodeSet {
    pub fn scancode_set1() -> Self {
        let mut scancode_set = Self {
            single_byte: [None; 256],
            extended: [None; 256],
        };

        scancode_set.single_byte[0x01] = Some(KeyCode::Escape); // 01
        scancode_set.single_byte[0x02] = Some(KeyCode::Key1); // 02
        scancode_set.single_byte[0x03] = Some(KeyCode::Key2); // 03
        scancode_set.single_byte[0x04] = Some(KeyCode::Key3); // 04
        scancode_set.single_byte[0x05] = Some(KeyCode::Key4); // 05
        scancode_set.single_byte[0x06] = Some(KeyCode::Key5); // 06
        scancode_set.single_byte[0x07] = Some(KeyCode::Key6); // 07
        scancode_set.single_byte[0x08] = Some(KeyCode::Key7); // 08
        scancode_set.single_byte[0x09] = Some(KeyCode::Key8); // 09
        scancode_set.single_byte[0x0A] = Some(KeyCode::Key9); // 0A
        scancode_set.single_byte[0x0B] = Some(KeyCode::Key0); // 0B
        scancode_set.single_byte[0x0C] = Some(KeyCode::Minus); // 0C
        scancode_set.single_byte[0x0D] = Some(KeyCode::Equals); // 0D
        scancode_set.single_byte[0x0E] = Some(KeyCode::Backspace); // 0E
        scancode_set.single_byte[0x0F] = Some(KeyCode::Tab); // 0F
        scancode_set.single_byte[0x10] = Some(KeyCode::Q); // 10
        scancode_set.single_byte[0x11] = Some(KeyCode::W); // 11
        scancode_set.single_byte[0x12] = Some(KeyCode::E); // 12
        scancode_set.single_byte[0x13] = Some(KeyCode::R); // 13
        scancode_set.single_byte[0x14] = Some(KeyCode::T); // 14
        scancode_set.single_byte[0x15] = Some(KeyCode::Y); // 15
        scancode_set.single_byte[0x16] = Some(KeyCode::U); // 16
        scancode_set.single_byte[0x17] = Some(KeyCode::I); // 17
        scancode_set.single_byte[0x18] = Some(KeyCode::O); // 18
        scancode_set.single_byte[0x19] = Some(KeyCode::P); // 19
        scancode_set.single_byte[0x1A] = Some(KeyCode::BracketSquareLeft); // 1A
        scancode_set.single_byte[0x1B] = Some(KeyCode::BracketSquareRight); // 1B
        scancode_set.single_byte[0x1C] = Some(KeyCode::Enter); // 1C
        scancode_set.single_byte[0x1D] = Some(KeyCode::ControlLeft); // 1D
        scancode_set.single_byte[0x1E] = Some(KeyCode::A); // 1E
        scancode_set.single_byte[0x1F] = Some(KeyCode::S); // 1F
        scancode_set.single_byte[0x20] = Some(KeyCode::D); // 20
        scancode_set.single_byte[0x21] = Some(KeyCode::F); // 21
        scancode_set.single_byte[0x22] = Some(KeyCode::G); // 22
        scancode_set.single_byte[0x23] = Some(KeyCode::H); // 23
        scancode_set.single_byte[0x24] = Some(KeyCode::J); // 24
        scancode_set.single_byte[0x25] = Some(KeyCode::K); // 25
        scancode_set.single_byte[0x26] = Some(KeyCode::L); // 26
        scancode_set.single_byte[0x27] = Some(KeyCode::SemiColon); // 27
        scancode_set.single_byte[0x28] = Some(KeyCode::Quote); // 28
        scancode_set.single_byte[0x29] = Some(KeyCode::BackTick); // 29
        scancode_set.single_byte[0x2A] = Some(KeyCode::ShiftLeft); // 2A
        scancode_set.single_byte[0x2B] = Some(KeyCode::BackSlash); // 2B
        scancode_set.single_byte[0x2C] = Some(KeyCode::Z); // 2C
        scancode_set.single_byte[0x2D] = Some(KeyCode::X); // 2D
        scancode_set.single_byte[0x2E] = Some(KeyCode::C); // 2E
        scancode_set.single_byte[0x2F] = Some(KeyCode::V); // 2F
        scancode_set.single_byte[0x30] = Some(KeyCode::B); // 30
        scancode_set.single_byte[0x31] = Some(KeyCode::N); // 31
        scancode_set.single_byte[0x32] = Some(KeyCode::M); // 32
        scancode_set.single_byte[0x33] = Some(KeyCode::Comma); // 33
        scancode_set.single_byte[0x34] = Some(KeyCode::Fullstop); // 34
        scancode_set.single_byte[0x35] = Some(KeyCode::Slash); // 35
        scancode_set.single_byte[0x36] = Some(KeyCode::ShiftRight); // 36
        scancode_set.single_byte[0x37] = Some(KeyCode::NumpadStar); // 37
        scancode_set.single_byte[0x38] = Some(KeyCode::AltLeft); // 38
        scancode_set.single_byte[0x39] = Some(KeyCode::Spacebar); // 39
        scancode_set.single_byte[0x3A] = Some(KeyCode::CapsLock); // 3A
        scancode_set.single_byte[0x3B] = Some(KeyCode::F1); // 3B
        scancode_set.single_byte[0x3C] = Some(KeyCode::F2); // 3C
        scancode_set.single_byte[0x3D] = Some(KeyCode::F3); // 3D
        scancode_set.single_byte[0x3E] = Some(KeyCode::F4); // 3E
        scancode_set.single_byte[0x3F] = Some(KeyCode::F5); // 3F
        scancode_set.single_byte[0x40] = Some(KeyCode::F6); // 40
        scancode_set.single_byte[0x41] = Some(KeyCode::F7); // 41
        scancode_set.single_byte[0x42] = Some(KeyCode::F8); // 42
        scancode_set.single_byte[0x43] = Some(KeyCode::F9); // 43
        scancode_set.single_byte[0x44] = Some(KeyCode::F10); // 44
        scancode_set.single_byte[0x45] = Some(KeyCode::NumpadLock); // 45
        scancode_set.single_byte[0x46] = Some(KeyCode::ScrollLock); // 46
        scancode_set.single_byte[0x47] = Some(KeyCode::Numpad7); // 47
        scancode_set.single_byte[0x48] = Some(KeyCode::Numpad8); // 48
        scancode_set.single_byte[0x49] = Some(KeyCode::Numpad9); // 49
        scancode_set.single_byte[0x4A] = Some(KeyCode::NumpadMinus); // 4A
        scancode_set.single_byte[0x4B] = Some(KeyCode::Numpad4); // 4B
        scancode_set.single_byte[0x4C] = Some(KeyCode::Numpad5); // 4C
        scancode_set.single_byte[0x4D] = Some(KeyCode::Numpad6); // 4D
        scancode_set.single_byte[0x4E] = Some(KeyCode::NumpadPlus); // 4E
        scancode_set.single_byte[0x4F] = Some(KeyCode::Numpad1); // 4F
        scancode_set.single_byte[0x50] = Some(KeyCode::Numpad2); // 50
        scancode_set.single_byte[0x51] = Some(KeyCode::Numpad3); // 51
        scancode_set.single_byte[0x52] = Some(KeyCode::Numpad0); // 52
        scancode_set.single_byte[0x53] = Some(KeyCode::NumpadPeriod); // 53
                                                                      // 0x54
                                                                      // 0x55
                                                                      // 0x56
        scancode_set.single_byte[0x57] = Some(KeyCode::F11); // 57
        scancode_set.single_byte[0x58] = Some(KeyCode::F12); // 58
        for i in 0x81..=0xD8 {
            scancode_set.single_byte[i] = scancode_set.single_byte[i - 0x80];
        }
        scancode_set.extended[0x10] = Some(KeyCode::PrevTrack); // E010
                                                                //0x11
                                                                //0x12
                                                                //0x13
                                                                //0x14
                                                                //0x15
                                                                //0x16
                                                                //0x17
                                                                //0x18
        scancode_set.extended[0x19] = Some(KeyCode::NextTrack); // E019
                                                                //0x1A
                                                                //0x1B
        scancode_set.extended[0x1C] = Some(KeyCode::NumpadEnter); // E01C
        scancode_set.extended[0x1D] = Some(KeyCode::ControlRight); // E01D
                                                                   //0x1E
                                                                   //0x1F
        scancode_set.extended[0x20] = Some(KeyCode::Mute); // E020
        scancode_set.extended[0x21] = Some(KeyCode::Calculator); // E021
        scancode_set.extended[0x22] = Some(KeyCode::Play); // E022
                                                           //0x23
        scancode_set.extended[0x24] = Some(KeyCode::Stop); // E024
                                                           //0x25
                                                           //0x26
                                                           //0x27
                                                           //0x28
                                                           //0x29
                                                           //0x2A
                                                           //0x2B
                                                           //0x2C
                                                           //0x2D
        scancode_set.extended[0x2E] = Some(KeyCode::VolumeDown); // E02E
                                                                 //0x2F
        scancode_set.extended[0x30] = Some(KeyCode::VolumeUp); // E030
                                                               //0x31
        scancode_set.extended[0x32] = Some(KeyCode::WWWHome); // E032
                                                              //0x33
                                                              //0x34
        scancode_set.extended[0x35] = Some(KeyCode::NumpadSlash); // E035
                                                                  //0x36
                                                                  //0x37
        scancode_set.extended[0x38] = Some(KeyCode::AltRight); // E038
                                                               //0x39
                                                               //0x3A
                                                               //0x3B
                                                               //0x3C
                                                               //0x3D
                                                               //0x3E
                                                               //0x3F
                                                               //0x40
                                                               //0x41
                                                               //0x42
                                                               //0x43
                                                               //0x44
                                                               //0x45
                                                               //0x46
        scancode_set.extended[0x47] = Some(KeyCode::Home); // E047
        scancode_set.extended[0x48] = Some(KeyCode::ArrowUp); // E048
        scancode_set.extended[0x49] = Some(KeyCode::PageUp); // E049
                                                             //0x4A
        scancode_set.extended[0x4B] = Some(KeyCode::ArrowLeft); // E04B
                                                                //0x4C
        scancode_set.extended[0x4D] = Some(KeyCode::ArrowRight); // E04D
                                                                 //0x4E
        scancode_set.extended[0x4F] = Some(KeyCode::End); // E04F
        scancode_set.extended[0x50] = Some(KeyCode::ArrowDown); // E050
        scancode_set.extended[0x51] = Some(KeyCode::PageDown); // E051
        scancode_set.extended[0x52] = Some(KeyCode::Insert); // E052
        scancode_set.extended[0x53] = Some(KeyCode::Delete); // E053
        for i in 0x90..=0xED {
            scancode_set.extended[i] = scancode_set.extended[i - 0x80];
        }
        scancode_set
    }

    pub fn scancode_set2() -> Self {
        Self {
            single_byte: [None; 256],
            extended: [None; 256],
        }
    }
}

impl ScancodeSet for CustomScancodeSet {
    fn advance_state(&self, state: &mut DecodeState, code: u8) -> Result<Option<KeyEvent>, Error> {
        match *state {
            DecodeState::Start => {
                match code {
                    EXTENDED_KEY_CODE => {
                        *state = DecodeState::Extended;
                        Ok(None)
                    }
                    0x80..=0xFF => {
                        // Release codes
                        Ok(Some(KeyEvent::new(
                            self.map_scancode(code - 0x80)?,
                            KeyState::Up,
                        )))
                    }
                    _ => {
                        // Normal codes
                        Ok(Some(KeyEvent::new(
                            self.map_scancode(code)?,
                            KeyState::Down,
                        )))
                    }
                }
            }
            DecodeState::Extended => {
                *state = DecodeState::Start;
                match code {
                    0x80..=0xFF => {
                        // Extended Release codes
                        Ok(Some(KeyEvent::new(
                            self.map_extended_scancode(code - 0x80)?,
                            KeyState::Up,
                        )))
                    }
                    _ => {
                        // Normal release codes
                        Ok(Some(KeyEvent::new(
                            self.map_extended_scancode(code)?,
                            KeyState::Down,
                        )))
                    }
                }
            }
            _ => {
                // Can't get in to this state
                unimplemented!();
            }
        }
    }

    fn map_scancode(&self, code: u8) -> Result<KeyCode, Error> {
        if let Some(kc) = self.single_byte[code as usize] {
            Ok(kc)
        } else {
            Err(Error::UnknownKeyCode)
        }
    }

    fn map_extended_scancode(&self, code: u8) -> Result<KeyCode, Error> {
        if let Some(kc) = self.extended[code as usize] {
            Ok(kc)
        } else {
            Err(Error::UnknownKeyCode)
        }
    }
}
