// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include <mbedtls/aes.h>
#include <string>
#include <vector>

#include "Common/CommonTypes.h"

class CWiiSaveCrypted
{
public:
  bool static ImportWiiSave(const std::string& filename);
  bool static ExportWiiSave(u64 title_id);
  void static ExportAllSaves();

private:
  CWiiSaveCrypted(const std::string& filename, u64 title_id = 0);
  ~CWiiSaveCrypted();
  void ReadHDR();
  void ReadBKHDR();
  void WriteHDR();
  void WriteBKHDR();
  void Extract() {}
  void ImportWiiSaveFiles();
  void ExportWiiSaveFiles();
  void do_sig();
  void make_ec_cert(u8* cert, const u8* sig, const char* signer, const char* name, const u8* priv,
                    const u32 key_id);
  bool getPaths(bool for_export = false);
  void ScanForFiles(const std::string& save_directory, std::vector<std::string>& file_list,
                    u32* num_files, u32* size_files);

  static const u8 s_sd_key[16];
  static const u8 s_md5_blanker[16];
  static const u32 s_ng_id;

  mbedtls_aes_context m_aes_ctx;
  u8 m_sd_iv[0x10];
  std::vector<std::string> m_files_list;

  std::string m_encrypted_save_path;

  std::string m_wii_title_path;

  u8 m_iv[0x10];

  u32 m_files_list_size;
  u32 m_size_of_files;
  u32 m_total_size;

  u64 m_title_id;

  bool m_valid;

  enum
  {
    BLOCK_SZ = 0x40,
    HDR_SZ = 0x20,
    ICON_SZ = 0x1200,
    BNR_SZ = 0x60a0,
    FULL_BNR_MIN = 0x72a0,  // BNR_SZ + 1*ICON_SZ
    FULL_BNR_MAX = 0xF0A0,  // BNR_SZ + 8*ICON_SZ
    HEADER_SZ = 0xF0C0,     // HDR_SZ + FULL_BNR_MAX
    BK_LISTED_SZ = 0x70,    // Size before rounding to nearest block
    BK_SZ = 0x80,
    FILE_HDR_SZ = 0x80,

    SIG_SZ = 0x40,
    NG_CERT_SZ = 0x180,
    AP_CERT_SZ = 0x180,
    FULL_CERT_SZ = 0x3C0,  // SIG_SZ + NG_CERT_SZ + AP_CERT_SZ + 0x80?

    BK_HDR_MAGIC = 0x426B0001,
    FILE_HDR_MAGIC = 0x03adf17e
  };

#pragma pack(push, 1)

  struct Data_Bin_HDR  // encrypted
  {
    u64 SaveGameTitle;
    u32 BannerSize;  // (0x72A0 or 0xF0A0, also seen 0xBAA0)
    u8 Permissions;
    u8 unk1;       // maybe permissions is a be16
    u8 Md5[0x10];  // md5 of plaintext header with md5 blanker applied
    u16 unk2;
  };

  struct HEADER
  {
    Data_Bin_HDR hdr;
    u8 BNR[FULL_BNR_MAX];
  };

  struct BK_Header  // Not encrypted
  {
    u32 size;  // 0x00000070
    // u16 magic;  // 'Bk'
    // u16 magic2; // or version (0x0001)
    u32 magic;  // 0x426B0001
    u32 NGid;
    u32 numberOfFiles;
    u32 sizeOfFiles;
    u32 unk1;
    u32 unk2;
    u32 totalSize;
    u8 unk3[64];
    u64 SaveGameTitle;
    u8 MACaddress[6];
    u8 padding[0x12];
  };

  struct FileHDR  // encrypted
  {
    u32 magic;  // 0x03adf17e
    u32 size;
    u8 Permissions;
    u8 attrib;
    u8 type;  // (1=file, 2=directory)
    u8 name[0x45];
    u8 IV[0x10];
    u8 unk[0x20];
  };
#pragma pack(pop)

  HEADER m_header;
  HEADER m_encrypted_header;
  BK_Header m_bk_hdr;
};
