use super::types::*;
use bitflags::bitflags;
use serde::Serialize;

#[repr(C)]
#[derive(Debug, Clone, Copy, Serialize)]
pub struct ImageDosHeader {
    pub e_magic: u16, // Magic number 固定值 0x5A4D
    pub e_cblp: u16,
    pub e_cp: u16,
    pub e_crlc: u16,
    pub e_cparhdr: u16,
    pub e_minalloc: u16,
    pub e_maxalloc: u16,
    pub e_ss: u16,
    pub e_sp: u16,
    pub e_csum: u16,
    pub e_ip: u16,
    pub e_cs: u16,
    pub e_lfarlc: u16,
    pub e_ovno: u16,
    pub e_res: [u16; 4],
    pub e_oemid: u16,
    pub e_oeminfo: u16,
    pub e_res2: [u16; 10],
    pub e_lfanew: Offset, // File address of new exe header nt头的偏移
}

#[repr(C)]
#[derive(Debug, Clone, Copy, Serialize)]
pub struct ImageNTHeader32 {
    pub signature: u32,
    pub file_header: ImageFileHeader,
    pub optional_header: ImageOptionalHeader32,
}

#[repr(C)]
#[derive(Debug, Clone, Copy, Serialize)]
pub struct ImageNTHeader64 {
    pub signature: u32,
    pub file_header: ImageFileHeader,
    pub optional_header: ImageOptionalHeader64,
}

#[repr(C)]
#[derive(Serialize, Clone, Copy)]
#[serde(untagged)]
pub enum ImageNTHeader{
    NTHeader32(ImageNTHeader32),
    NTHeader64(ImageNTHeader64),
}

#[repr(C)]
#[derive(Serialize)]
#[serde(untagged)]
pub enum ImageNTHeaderMut<'a>{
    NTHeader32(&'a mut ImageNTHeader32),
    NTHeader64(&'a mut ImageNTHeader64),
}

impl <'a> ImageNTHeaderMut<'a>{
    pub fn get_optional_header_mut(&mut self) -> ImageOptionalHeaderMut{
        match self{
            ImageNTHeaderMut::NTHeader32(header) => ImageOptionalHeaderMut::OptionalHeader32(&mut header.optional_header),
            ImageNTHeaderMut::NTHeader64(header) => ImageOptionalHeaderMut::OptionalHeader64(&mut header.optional_header),
        }
    }
}


#[repr(C)]
#[derive(Debug, Clone, Copy, Serialize)]
pub struct ImageFileHeader {
    pub machine: u16,
    pub number_of_sections: u16,
    pub time_date_stamp: u32,
    pub pointer_to_symbol_table: Offset,
    pub number_of_symbols: u32,
    pub size_of_optional_header: u16,
    pub characteristics: FileCharacteristics,
}
impl Serialize for FileCharacteristics {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        // 直接返回bitflags的整数值
        serializer.serialize_u16(self.bits())
    }
}

impl Serialize for DLLCharacteristics {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_u16(self.bits())
    }
}

impl Serialize for SectionCharacteristics {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_u32(self.bits())
    }
}

bitflags! {
    #[repr(C)]
    #[derive(Debug, Clone, Copy)]
    pub struct FileCharacteristics: u16 {
        const RELOCS_STRIPPED         = 0x0001;
        const EXECUTABLE_IMAGE        = 0x0002;
        const LINE_NUMS_STRIPPED      = 0x0004;
        const LOCAL_SYMS_STRIPPED     = 0x0008;
        const AGGRESSIVE_WS_TRIM      = 0x0010;
        const LARGE_ADDRESS_AWARE     = 0x0020;
        const BYTES_REVERSED_LO       = 0x0080;
        const MACHINE_32BIT           = 0x0100;
        const DEBUG_STRIPPED          = 0x0200;
        const REMOVABLE_RUN_FROM_SWAP = 0x0400;
        const NET_RUN_FROM_SWAP       = 0x0800;
        const SYSTEM                  = 0x1000;
        const DLL                     = 0x2000;
        const UP_SYSTEM_ONLY          = 0x4000;
        const BYTES_REVERSED_HI       = 0x8000;
    }
    #[repr(C)]
    #[derive(Debug, Clone, Copy)]
    pub struct DLLCharacteristics: u16 {
        const RESERVED1             = 0x0001;
        const RESERVED2             = 0x0002;
        const RESERVED4             = 0x0004;
        const RESERVED8             = 0x0008;
        const HIGH_ENTROPY_VA       = 0x0020;
        const DYNAMIC_BASE          = 0x0040;
        const FORCE_INTEGRITY       = 0x0080;
        const NX_COMPAT             = 0x0100;
        const NO_ISOLATION          = 0x0200;
        const NO_SEH                = 0x0400;
        const NO_BIND               = 0x0800;
        const APPCONTAINER          = 0x1000;
        const WDM_DRIVER            = 0x2000;
        const GUARD_CF              = 0x4000;
        const TERMINAL_SERVER_AWARE = 0x8000;
    }
    #[repr(C)]
    #[derive(Debug, Clone, Copy)]
    pub struct SectionCharacteristics: u32 {
        /// Reserved for future use.
        const TYPE_REG               = 0x00000000;
        /// Reserved for future use.
        const TYPE_DSECT             = 0x00000001;
        /// Reserved for future use.
        const TYPE_NOLOAD            = 0x00000002;
        /// Reserved for future use.
        const TYPE_GROUP             = 0x00000004;
        /// The section should not be padded to the next boundary.
        /// This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES.
        /// This is valid only for object files.
        const TYPE_NO_PAD            = 0x00000008;
        /// Reserved for future use.
        const TYPE_COPY              = 0x00000010;
        /// The section contains executable code.
        const CNT_CODE               = 0x00000020;
        /// The section contains initialized data.
        const CNT_INITIALIZED_DATA   = 0x00000040;
        /// The section contains uninitialized data.
        const CNT_UNINITIALIZED_DATA = 0x00000080;
        /// Reserved for future use.
        const LNK_OTHER              = 0x00000100;
        /// The section contains comments or other information.
        /// The .drectve section has this type. This is valid for object files only.
        const LNK_INFO               = 0x00000200;
        /// Reserved for future use.
        const TYPE_OVER              = 0x00000400;
        /// The section will not become part of the image.
        /// This is valid only for object files.
        const LNK_REMOVE             = 0x00000800;
        /// The section contains COMDAT data. This is valid only for object files.
        const LNK_COMDAT             = 0x00001000;
        /// Unknown/Reserved.
        const RESERVED               = 0x00002000;
        /// Unknown flag.
        const MEM_PROTECTED          = 0x00004000;
        /// Unknown flag.
        const NO_DEFER_SPEC_EXC      = 0x00004000;
        /// The section contains data referenced through the global pointer (GP).
        const GPREL                  = 0x00008000;
        /// Reserved for future use.
        const MEM_FARDATA            = 0x00008000;
        /// Reserved for future use.
        const MEM_SYSHEAP            = 0x00010000;
        /// Reserved for future use.
        const MEM_PURGEABLE          = 0x00020000;
        /// Reserved for future use.
        const MEM_16BIT              = 0x00020000;
        /// Reserved for future use.
        const MEM_LOCKED             = 0x00040000;
        /// Reserved for future use.
        const MEM_PRELOAD            = 0x00080000;
        /// Align data on a 1-byte boundary. Valid only for object files.
        const ALIGN_1BYTES           = 0x00100000;
        /// Align data on a 2-byte boundary. Valid only for object files.
        const ALIGN_2BYTES           = 0x00200000;
        /// Align data on a 4-byte boundary. Valid only for object files.
        const ALIGN_4BYTES           = 0x00300000;
        /// Align data on an 8-byte boundary. Valid only for object files.
        const ALIGN_8BYTES           = 0x00400000;
        /// Align data on a 16-byte boundary. Valid only for object files.
        const ALIGN_16BYTES          = 0x00500000;
        /// Align data on a 32-byte boundary. Valid only for object files.
        const ALIGN_32BYTES          = 0x00600000;
        /// Align data on a 64-byte boundary. Valid only for object files.
        const ALIGN_64BYTES          = 0x00700000;
        /// Align data on a 128-byte boundary. Valid only for object files.
        const ALIGN_128BYTES         = 0x00800000;
        /// Align data on a 256-byte boundary. Valid only for object files.
        const ALIGN_256BYTES         = 0x00900000;
        /// Align data on a 512-byte boundary. Valid only for object files.
        const ALIGN_512BYTES         = 0x00A00000;
        /// Align data on a 1024-byte boundary. Valid only for object files.
        const ALIGN_1024BYTES        = 0x00B00000;
        /// Align data on a 2048-byte boundary. Valid only for object files.
        const ALIGN_2048BYTES        = 0x00C00000;
        /// Align data on a 4096-byte boundary. Valid only for object files.
        const ALIGN_4096BYTES        = 0x00D00000;
        /// Align data on an 8192-byte boundary. Valid only for object files.
        const ALIGN_8192BYTES        = 0x00E00000;
        /// Mask for alignment.
        const ALIGN_MASK             = 0x00F00000;
        /// The section contains extended relocations.
        const LNK_NRELOC_OVFL        = 0x01000000;
        /// The section can be discarded as needed.
        const MEM_DISCARDABLE        = 0x02000000;
        /// The section cannot be cached.
        const MEM_NOT_CACHED         = 0x04000000;
        /// The section is not pageable.
        const MEM_NOT_PAGED          = 0x08000000;
        /// The section can be shared in memory.
        const MEM_SHARED             = 0x10000000;
        /// The section can be executed as code.
        const MEM_EXECUTE            = 0x20000000;
        /// The section can be read.
        const MEM_READ               = 0x40000000;
        /// The section can be written to.
        const MEM_WRITE              = 0x80000000;
    }
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Serialize)]
pub struct ImageOptionalHeader32 {
    pub magic: u16,
    pub major_linker_version: u8,
    pub minor_linker_version: u8,
    pub size_of_code: u32,
    pub size_of_initialized_data: u32,
    pub size_of_uninitialized_data: u32,
    pub address_of_entry_point: u32,
    pub base_of_code: u32,
    pub base_of_data: u32,
    pub image_base: u32,
    pub section_alignment: u32,
    pub file_alignment: u32,
    pub major_operating_system_version: u16,
    pub minor_operating_system_version: u16,
    pub major_image_version: u16,
    pub minor_image_version: u16,
    pub major_subsystem_version: u16,
    pub minor_subsystem_version: u16,
    pub win32_version_value: u32,
    pub size_of_image: u32,
    pub size_of_headers: u32,
    pub checksum: u32,
    pub subsystem: u16,
    pub dll_characteristics: DLLCharacteristics,
    pub size_of_stack_reserve: u32,
    pub size_of_stack_commit: u32,
    pub size_of_heap_reserve: u32,
    pub size_of_heap_commit: u32,
    pub loader_flags: u32,
    pub number_of_rva_and_sizes: u32,
}

#[repr(C)]
#[derive(Copy, Clone, Debug, Serialize)]
pub struct ImageOptionalHeader64 {
    pub magic: u16,
    pub major_linker_version: u8,
    pub minor_linker_version: u8,
    pub size_of_code: u32,
    pub size_of_initialized_data: u32,
    pub size_of_uninitialized_data: u32,
    pub address_of_entry_point: u32,
    pub base_of_code: u32,
    pub image_base: u64,
    pub section_alignment: u32,
    pub file_alignment: u32,
    pub major_operating_system_version: u16,
    pub minor_operating_system_version: u16,
    pub major_image_version: u16,
    pub minor_image_version: u16,
    pub major_subsystem_version: u16,
    pub minor_subsystem_version: u16,
    pub win32_version_value: u32,
    pub size_of_image: u32,
    pub size_of_headers: u32,
    pub checksum: u32,
    pub subsystem: u16,
    pub dll_characteristics: DLLCharacteristics,
    pub size_of_stack_reserve: u64,
    pub size_of_stack_commit: u64,
    pub size_of_heap_reserve: u64,
    pub size_of_heap_commit: u64,
    pub loader_flags: u32,
    pub number_of_rva_and_sizes: u32,
}
#[repr(C)]
#[derive(Serialize, Clone, Copy)]
#[serde(untagged)]
pub enum ImageOptionalHeader {
    OptionalHeader32(ImageOptionalHeader32),
    OptionalHeader64(ImageOptionalHeader64),
}

#[repr(C)]
#[derive(Copy, Clone, Eq, PartialEq, Default, Debug)]
pub struct ImageDataDirectory {
    pub virtual_address: u32,
    pub size: u32,
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum ImageDirectoryEntry {
    Export         = 0,
    Import         = 1,
    Resource       = 2,
    Exception      = 3,
    Security       = 4,
    BaseReloc      = 5,
    Debug          = 6,
    Architecture   = 7,
    GlobalPTR      = 8,
    TLS            = 9,
    LoadConfig     = 10,
    BoundImport    = 11,
    IAT            = 12,
    DelayImport    = 13,
    COMDescriptor  = 14,
    Reserved       = 15,
}

#[repr(C)]
#[derive(Serialize)]
#[serde(untagged)]
pub enum ImageOptionalHeaderMut<'a> {
    OptionalHeader32(&'a mut ImageOptionalHeader32),
    OptionalHeader64(&'a mut ImageOptionalHeader64),
}

impl ImageOptionalHeader {
    pub fn get_size_of_headers(&self) -> u32 {
        match self {
            ImageOptionalHeader::OptionalHeader32(header) => header.size_of_headers,
            ImageOptionalHeader::OptionalHeader64(header) => header.size_of_headers,
        }
    }

    pub fn get_size_of_image(&self) -> u32 {
        match self {
            ImageOptionalHeader::OptionalHeader32(header) => header.size_of_image,
            ImageOptionalHeader::OptionalHeader64(header) => header.size_of_image,
        }
    }
}


#[repr(C)]
#[derive(Debug, Clone, Copy, Serialize)]
pub struct ImageSectionHeader {
    pub name: [u8; 8],
    pub virtual_size: u32,
    pub virtual_address: u32,
    pub size_of_raw_data: u32,
    pub pointer_to_raw_data: u32,
    pub pointer_to_relocations: u32,
    pub pointer_to_linenumbers: u32,
    pub number_of_relocations: u16,
    pub number_of_linenumbers: u16,
    pub characteristics: SectionCharacteristics,
}
