use crate::common::PaddingMethod;

use super::constants::SM4_BLOCK_SIZE as BLOCK_SIZE;
use super::{BlockCipherImpl, Operation, OperationMode, SM4};


/// SM4-ECB分组模式块式加密器（SM4-ECB Mode Block Encryptor）
///
/// # 参数（Arguments）
///
/// * key - 密钥（Key）
///
///   长度为16字节（128比特）的字节数组。\
///   A byte array of length 16 bytes (128 bits).
///
/// * padding_method - 填充方法（Method of padding）
///
///   指示实例将使用的填充方法，如不进行填充，可以传入`None`。\
///   Indicates the method of padding for the instance will use. If do not need, pass `None`.
///
/// * message - 消息（Message）
///
///   任意长度的消息。\
///   Message of any length.
///
/// # 示例（Examples）
///
/// ```rust
/// # fn main() -> Result<(), ()> {
/// use neuedu_cryptos::block_ciphers::sm4_ecb_encrypt;
///
/// const KEY: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
/// const IV: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
/// const PLAIN: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
///
/// let cipher = sm4_ecb_encrypt(KEY, None, &PLAIN)?;
///
/// assert_eq!(cipher, [
///     0x68, 0x1E, 0xDF, 0x34, 0xD2, 0x06, 0x96, 0x5E,
///     0x86, 0xB3, 0xE9, 0x4F, 0x53, 0x6E, 0x42, 0x46,
/// ]);
/// #
/// #     Ok(())
/// # }
/// ```
pub fn sm4_ecb_encrypt(key: [u8; BLOCK_SIZE as usize], padding_method: Option<PaddingMethod>, message: &[u8]) -> Result<Vec<u8>, ()> {
    let mut instance = SM4::new(key, Operation::Encrypt, Some(OperationMode::ECB), padding_method).unwrap();

    block_calculate(&mut instance, message)
}


/// SM4-ECB分组模式块式解密器（SM4-ECB Mode Block Decryptor）
///
/// # 参数（Arguments）
///
/// * key - 密钥（Key）
///
///   长度为16字节（128比特）的字节数组。\
///   A byte array of length 16 bytes (128 bits).
///
/// * padding_method - 填充方法（Method of padding）
///
///   指示实例将使用的填充方法，如不进行填充，可以传入`None`。\
///   Indicates the method of padding for the instance will use. If do not need, pass `None`.
///
/// * message - 消息（Message）
///
///   任意长度的消息。\
///   Message of any length.
///
/// # 示例（Examples）
///
/// ```rust
/// # fn main() -> Result<(), ()> {
/// use neuedu_cryptos::block_ciphers::sm4_ecb_decrypt;
///
/// const KEY: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
/// const CIPHER: [u8; 16] = [
///     0x68, 0x1E, 0xDF, 0x34, 0xD2, 0x06, 0x96, 0x5E,
///     0x86, 0xB3, 0xE9, 0x4F, 0x53, 0x6E, 0x42, 0x46,
/// ];
///
/// let plain = sm4_ecb_decrypt(KEY, None, &CIPHER)?;
///
/// assert_eq!(plain, [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ]);
/// #
/// #     Ok(())
/// # }
/// ```
pub fn sm4_ecb_decrypt(key: [u8; BLOCK_SIZE as usize], padding_method: Option<PaddingMethod>, message: &[u8]) -> Result<Vec<u8>, ()> {
    let mut instance = SM4::new(key, Operation::Decrypt, Some(OperationMode::ECB), padding_method).unwrap();

    block_calculate(&mut instance, message)
}


/// SM4-CBC分组模式块式加密器（SM4-CBC Mode Block Encryptor）
///
/// # 参数（Arguments）
///
/// * key - 密钥（Key）
///
///   长度为16字节（128比特）的字节数组。\
///   A byte array of length 16 bytes (128 bits).
///
/// * padding_method - 填充方法（Method of padding）
///
///   指示实例将使用的填充方法，如不进行填充，可以传入`None`。\
///   Indicates the method of padding for the instance will use. If do not need, pass `None`.
///
/// * message - 消息（Message）
///
///   任意长度的消息。\
///   Message of any length.
///
/// # 示例（Examples）
///
/// ```rust
/// # fn main() -> Result<(), ()> {
/// use neuedu_cryptos::block_ciphers::sm4_cbc_encrypt;
///
/// const KEY: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
/// const IV: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
/// const PLAIN: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
///
/// let cipher = sm4_cbc_encrypt(KEY, None, IV, &PLAIN)?;
///
/// assert_eq!(cipher, [
///     0x26, 0x77, 0xF4, 0x6B, 0x09, 0xC1, 0x22, 0xCC,
///     0x97, 0x55, 0x33, 0x10, 0x5B, 0xD4, 0xA2, 0x2A,
/// ]);
/// #
/// #     Ok(())
/// # }
/// ```
pub fn sm4_cbc_encrypt(key: [u8; BLOCK_SIZE as usize], padding_method: Option<PaddingMethod>, iv: [u8; BLOCK_SIZE as usize], message: &[u8]) -> Result<Vec<u8>, ()> {
    let mut instance = SM4::new(key, Operation::Encrypt, Some(OperationMode::CBC(iv.into())), padding_method).unwrap();

    block_calculate(&mut instance, message)
}


/// SM4-CBC分组模式块式加密器（SM4-CBC Mode Block Encryptor）
///
/// # 参数（Arguments）
///
/// * key - 密钥（Key）
///
///   长度为16字节（128比特）的字节数组。\
///   A byte array of length 16 bytes (128 bits).
///
/// * padding_method - 填充方法（Method of padding）
///
///   指示实例将使用的填充方法，如不进行填充，可以传入`None`。\
///   Indicates the method of padding for the instance will use. If do not need, pass `None`.
///
/// * message - 消息（Message）
///
///   任意长度的消息。\
///   Message of any length.
///
/// # 示例（Examples）
///
/// ```rust
/// # fn main() -> Result<(), ()> {
/// use neuedu_cryptos::block_ciphers::sm4_cbc_decrypt;
///
/// const KEY: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
/// const IV: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
/// const CIPHER: [u8; 16] = [
///     0x26, 0x77, 0xF4, 0x6B, 0x09, 0xC1, 0x22, 0xCC,
///     0x97, 0x55, 0x33, 0x10, 0x5B, 0xD4, 0xA2, 0x2A,
/// ];
///
/// let plain = sm4_cbc_decrypt(KEY, None, IV, &CIPHER)?;
///
/// assert_eq!(plain, [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ]);
/// #
/// #     Ok(())
/// # }
/// ```
pub fn sm4_cbc_decrypt(key: [u8; BLOCK_SIZE as usize], padding_method: Option<PaddingMethod>, iv: [u8; BLOCK_SIZE as usize], message: &[u8]) -> Result<Vec<u8>, ()> {
    let mut instance = SM4::new(key, Operation::Decrypt, Some(OperationMode::CBC(iv.into())), padding_method).unwrap();

    block_calculate(&mut instance, message)
}


/// SM4-CFB分组模式块式解密器（SM4-CFB Mode Block Decryptor）
///
/// # 参数（Arguments）
///
/// * key - 密钥（Key）
///
///   长度为16字节（128比特）的字节数组。\
///   A byte array of length 16 bytes (128 bits).
///
/// * padding_method - 填充方法（Method of padding）
///
///   指示实例将使用的填充方法，如不进行填充，可以传入`None`。\
///   Indicates the method of padding for the instance will use. If do not need, pass `None`.
///
/// * message - 消息（Message）
///
///   任意长度的消息。\
///   Message of any length.
///
/// # 示例（Examples）
///
/// ```rust
/// # fn main() -> Result<(), ()> {
/// use neuedu_cryptos::block_ciphers::sm4_cfb_encrypt;
///
/// const KEY: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
/// const IV: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
/// const PLAIN: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
///
/// let cipher = sm4_cfb_encrypt(KEY, None, IV, &PLAIN)?;
///
/// assert_eq!(cipher, [
///     0x69, 0x3D, 0x9A, 0x53, 0x5B, 0xAD, 0x5B, 0xB1,
///     0x78, 0x6F, 0x53, 0xD7, 0x25, 0x3A, 0x70, 0x56,
/// ]);
/// #
/// #     Ok(())
/// # }
/// ```
pub fn sm4_cfb_encrypt(key: [u8; BLOCK_SIZE as usize], padding_method: Option<PaddingMethod>, iv: [u8; BLOCK_SIZE as usize], message: &[u8]) -> Result<Vec<u8>, ()> {
    let mut instance = SM4::new(key, Operation::Encrypt, Some(OperationMode::CFB(iv.into())), padding_method).unwrap();

    block_calculate(&mut instance, message)
}


/// SM4-CFB分组模式块式解密器（SM4-CFB Mode Block Decryptor）
///
/// # 参数（Arguments）
///
/// * key - 密钥（Key）
///
///   长度为16字节（128比特）的字节数组。\
///   A byte array of length 16 bytes (128 bits).
///
/// * padding_method - 填充方法（Method of padding）
///
///   指示实例将使用的填充方法，如不进行填充，可以传入`None`。\
///   Indicates the method of padding for the instance will use. If do not need, pass `None`.
///
/// * message - 消息（Message）
///
///   任意长度的消息。\
///   Message of any length.
///
/// # 示例（Examples）
///
/// ```rust
/// # fn main() -> Result<(), ()> {
/// use neuedu_cryptos::block_ciphers::sm4_cfb_decrypt;
///
/// const KEY: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
/// const IV: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
/// const CIPHER: [u8; 16] = [
///     0x69, 0x3D, 0x9A, 0x53, 0x5B, 0xAD, 0x5B, 0xB1,
///     0x78, 0x6F, 0x53, 0xD7, 0x25, 0x3A, 0x70, 0x56,
/// ];
///
/// let plain = sm4_cfb_decrypt(KEY, None, IV, &CIPHER)?;
///
/// assert_eq!(plain, [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ]);
/// #
/// #     Ok(())
/// # }
/// ```
pub fn sm4_cfb_decrypt(key: [u8; BLOCK_SIZE as usize], padding_method: Option<PaddingMethod>, iv: [u8; BLOCK_SIZE as usize], message: &[u8]) -> Result<Vec<u8>, ()> {
    let mut instance = SM4::new(key, Operation::Decrypt, Some(OperationMode::CFB(iv.into())), padding_method).unwrap();

    block_calculate(&mut instance, message)
}


/// SM4-OFB分组模式块式解密器（SM4-OFB Mode Block Decryptor）
///
/// # 参数（Arguments）
///
/// * key - 密钥（Key）
///
///   长度为16字节（128比特）的字节数组。\
///   A byte array of length 16 bytes (128 bits).
///
/// * padding_method - 填充方法（Method of padding）
///
///   指示实例将使用的填充方法，如不进行填充，可以传入`None`。\
///   Indicates the method of padding for the instance will use. If do not need, pass `None`.
///
/// * message - 消息（Message）
///
///   任意长度的消息。\
///   Message of any length.
///
/// # 示例（Examples）
///
/// ```rust
/// # fn main() -> Result<(), ()> {
/// use neuedu_cryptos::block_ciphers::sm4_ofb_encrypt;
///
/// const KEY: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
/// const IV: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
/// const PLAIN: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
///
/// let cipher = sm4_ofb_encrypt(KEY, None, IV, &PLAIN)?;
///
/// assert_eq!(cipher, [
///     0x69, 0x3D, 0x9A, 0x53, 0x5B, 0xAD, 0x5B, 0xB1,
///     0x78, 0x6F, 0x53, 0xD7, 0x25, 0x3A, 0x70, 0x56,
/// ]);
/// #
/// #     Ok(())
/// # }
/// ```
pub fn sm4_ofb_encrypt(key: [u8; BLOCK_SIZE as usize], padding_method: Option<PaddingMethod>, iv: [u8; BLOCK_SIZE as usize], message: &[u8]) -> Result<Vec<u8>, ()> {
    let mut instance = SM4::new(key, Operation::Encrypt, Some(OperationMode::OFB(iv.into())), padding_method).unwrap();

    block_calculate(&mut instance, message)
}


/// SM4-OFB分组模式块式解密器（SM4-OFB Mode Block Decryptor）
///
/// # 参数（Arguments）
///
/// * key - 密钥（Key）
///
///   长度为16字节（128比特）的字节数组。\
///   A byte array of length 16 bytes (128 bits).
///
/// * padding_method - 填充方法（Method of padding）
///
///   指示实例将使用的填充方法，如不进行填充，可以传入`None`。\
///   Indicates the method of padding for the instance will use. If do not need, pass `None`.
///
/// * message - 消息（Message）
///
///   任意长度的消息。\
///   Message of any length.
///
/// # 示例（Examples）
///
/// ```rust
/// # fn main() -> Result<(), ()> {
/// use neuedu_cryptos::block_ciphers::sm4_ofb_decrypt;
///
/// const KEY: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
/// const IV: [u8; 16] = [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ];
/// const CIPHER: [u8; 16] = [
///     0x69, 0x3D, 0x9A, 0x53, 0x5B, 0xAD, 0x5B, 0xB1,
///     0x78, 0x6F, 0x53, 0xD7, 0x25, 0x3A, 0x70, 0x56,
/// ];
///
/// let plain = sm4_ofb_decrypt(KEY, None, IV, &CIPHER)?;
///
/// assert_eq!(plain, [
///     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
///     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
/// ]);
/// #
/// #     Ok(())
/// # }
/// ```
pub fn sm4_ofb_decrypt(key: [u8; BLOCK_SIZE as usize], padding_method: Option<PaddingMethod>, iv: [u8; BLOCK_SIZE as usize], message: &[u8]) -> Result<Vec<u8>, ()> {
    let mut instance = SM4::new(key, Operation::Decrypt, Some(OperationMode::OFB(iv.into())), padding_method).unwrap();

    block_calculate(&mut instance, message)
}


fn block_calculate(instance: &mut SM4, message: &[u8]) -> Result<Vec<u8>, ()> {
    let mut result = Vec::<u8>::with_capacity(message.len() + BLOCK_SIZE as usize * 2);
    result.append(&mut instance.update(message).unwrap());
    result.append(&mut instance.r#final().unwrap());

    Ok(result)
}
