
#ifndef CART_H
#define CART_H

#include <dataTypes.h>
#include <stdio.h>
#include <string>
using namespace std;

class _System;
class Bus;

class Cart
{
public:
    enum Mappers { BIOS, STANDARD, CODEMASTERS, KOREAN, KOREAN_8K, NO_BANK_SWITCHING, CUSTOM_4_PAK, NONE };
    enum Region { USA = 0, JAPAN = 1, EUROPE = 2 };

private:
    Bus& bus;
    _System* sys;

    u32 romSize;
    u32 sramSize;
    u32 cartWramSize;
    u8* rom;
    u8* sram;
    u8* cartWram;

    Mappers mapper;
    Region region;
    bool ggInSmsMode;

    bool loaded;
    string romHash;

    struct BiosInfo {
        string hash;
        Region region;
    } biosInfo[10];

    struct BackupRamInfo {
        string hash;
        unsigned sramSize;
    } backupRamInfo[23];

    struct SmsModeInfo {
        string hash;
    } smsModeInfo[27];

    struct CartWramInfo {
       string hash;
       unsigned size;
    } cartWramInfo[3];

    struct GlassesInfo {
        string hash;
    } glassesInfo[12];

    struct MapperHint {
        Mappers mapper;
        unsigned hint;
        bool operator<(const MapperHint& mh) const {
            return (hint > mh.hint);
        }
    } mapperHint[5];

    struct WramPattern {
        string hash;
        u8 value;
    } wramPattern[2];

    struct CustomMapper {
        string hash;
        Mappers mapper;
    } customMapper[2];

    unsigned mapperHintSize;
    unsigned backupRamInfoSize;
    unsigned biosInfoSize;
    unsigned glassesInfoSize;
    unsigned smsModeInfoSize;
    unsigned cartWramInfoSize;
    unsigned wramPatternSize;
    unsigned customMapperSize;

    void resetHints();
    void hintMapper(Mappers _mapper, unsigned add = 1);
    unsigned getMapperHint(Mappers _mapper);
    bool isAnyMapperHinted(unsigned limit);
    void detectMapper();
    void setMapper();
    void setRegion();
    void setSram();
    void calcHash();
    unsigned getCustomSramSize();
    bool checkForSmsMode();
    bool isBios();
    bool is3dGlasses();
    void removeNonRomHeader();
    void toLower(string& str);
    bool useCartWram();
    Mappers getCustomMapper();

public:
    void load(u8* _rom, u32 _romSize, bool _ggInSmsMode = false);

    unsigned getSramSize();
    unsigned getWramSize();
    unsigned getWramPattern();
    u8* getSram();

    void unload();
    bool isLoaded() { return loaded; }
    Mappers getMapper() {
        return mapper;
    }
    bool isGgInSmsMode() {
        return ggInSmsMode;
    }
	Cart(_System* sys, Bus& bus);
	~Cart();
};

#endif
