from nsz.Fs.File import File
from enum import IntEnum
from nsz.nut import Print
# Some of this may have changed in 7.x.x+


class NacpLanguageType(IntEnum):
    AmericanEnglish = 0
    BritishEnglish = 1
    Japanese = 2
    French = 3
    German = 4
    LatinAmericanSpanish = 5
    Spanish = 6
    Italian = 7
    Dutch = 8
    CanadianFrench = 9
    Portuguese = 10
    Russian = 11
    Korean = 12
    TraditionalChinese = 13
    SimplifiedChinese = 14


class NacpLanguage:
    def __init__(self):
        self.name = None
        self.publisher = None


class OrganizationType(IntEnum):
    CERO = 0
    GRACGCRB = 1
    GSRMR = 2
    ESRB = 3
    ClassInd = 4
    USK = 5
    PEGI = 6
    PEGIPortugal = 7
    PEGIBBFC = 8
    Russian = 9
    ACB = 10
    OFLC = 11


class RatingAge:
    def __init__(self):
        self.age = None


class Nacp(File):
    def __init__(
        self, path=None, mode=None, cryptoType=-1, cryptoKey=-1, cryptoCounter=-1
    ):
        super(Nacp, self).__init__(path, mode, cryptoType, cryptoKey, cryptoCounter)

        self.languages = []

        for i in range(15):
            self.languages.append(NacpLanguage())

        self.isbn = None
        self.startupUserAccount = None
        self.userAccountSwitchLock = None
        self.addOnContentRegistrationType = None
        self.attribute = None
        self.parentalControl = None
        self.screenshot = None
        self.videoCapture = None
        self.dataLossConfirmation = None
        self.playLogPolicy = None
        self.presenceGroupId = None

        self.ages = []

        for i in range(12):
            self.ages.append(RatingAge())

        self.displayVersion = None
        self.addOnContentBaseId = None
        self.saveDataOwnerId = None
        self.userAccountSaveDataSize = None
        self.userAccountSaveDataJournalSize = None
        self.deviceSaveDataSize = None
        self.deviceSaveDataJournalSize = None
        self.bcatDeliveryCacheStorageSize = None
        self.applicationErrorCodeCategory = None
        self.localCommunicationId = None
        self.logoType = None
        self.logoHandling = None
        self.runtimeAddOnContentInstall = None
        self.crashReport = None
        self.hdcp = None
        self.seedForPseudoDeviceId = None
        self.bcatPassphrase = None
        self.userAccountSaveDataSizeMax = None
        self.userAccountSaveDataJournalSizeMax = None
        self.deviceSaveDataSizeMax = None
        self.deviceSaveDataJournalSizeMax = None
        self.temporaryStorageSize = None
        self.cacheStorageSize = None
        self.cacheStorageJournalSize = None
        self.cacheStorageDataAndJournalSizeMax = None
        self.cacheStorageIndexMax = None
        self.playLogQueryableApplicationId = None
        self.playLogQueryCapability = None
        self.repair = None
        self.programIndex = None
        self.requiredNetworkServiceLicenseOnLaunch = None

    def getName(self, i):
        self.seek(i * 0x300)
        self.languages[i].name = self.read(0x200)
        self.languages[i].name = (
            self.languages[i].name.split(b"\0", 1)[0].decode("utf-8")
        )
        return self.languages[i].name

    def getPublisher(self, i):
        self.seek(i * 0x300 + 0x200)
        self.languages[i].publisher = self.read(0x100)
        self.languages[i].publisher = (
            self.languages[i].publisher.split(b"\0", 1)[0].decode("utf-8")
        )
        return self.languages[i].publisher

    def getIsbn(self):
        self.seek(0x3000)
        self.isbn = self.read(0x24).split(b"\0", 1)[0].decode("utf-8")
        return self.isbn

    def getStartupUserAccount(self):
        self.seek(0x3025)
        b = self.readInt8("little")
        if b == 0:
            self.startupUserAccount = "None"
        elif b == 1:
            self.startupUserAccount = "Required"
        elif b == 2:
            self.startupUserAccount = "RequiredWithNetworkServiceAccountAvailable"
        else:
            self.startupUserAccount = "Unknown"
        return self.startupUserAccount

    def getUserAccountSwitchLock(self):
        self.seek(0x3026)
        b = self.readInt8("little")
        if b == 0:
            self.userAccountSwitchLock = "Disable"
        elif b == 1:
            self.userAccountSwitchLock = "Enable"
        else:
            self.userAccountSwitchLock = "Unknown"
        return self.userAccountSwitchLock

    def getAddOnContentRegistrationType(self):
        self.seek(0x3027)
        b = self.readInt8("little")
        if b == 0:
            self.addOnContentRegistrationType = "AllOnLaunch"
        elif b == 1:
            self.addOnContentRegistrationType = "OnDemand"
        else:
            self.addOnContentRegistrationType = "Unknown"
        return self.addOnContentRegistrationType

    def getAttribute(self):
        self.seek(0x3028)
        b = self.readInt8("little")
        if b == 0:
            self.attribute = "None"
        elif b == 1:
            self.attribute = "Demo"
        elif b == 2:
            self.attribute = "RetailInteractiveDisplay"
        else:
            self.attribute = "Unknown"
        return self.attribute

    def getParentalControl(self):
        self.seek(0x3030)
        b = self.readInt8("little")
        if b == 0:
            self.parentalControl = "None"
        elif b == 1:
            self.parentalControl = "FreeCommunication"
        else:
            self.parentalControl = "Unknown"
        return self.parentalControl

    def getScreenshot(self):
        self.seek(0x3034)
        b = self.readInt8("little")
        if b == 0:
            self.screenshot = "Allow"
        elif b == 1:
            self.screenshot = "Deny"
        else:
            self.screenshot = "Unknown"
        return self.screenshot

    def getVideoCapture(self):
        self.seek(0x3035)
        b = self.readInt8("little")
        if b == 0:
            self.videoCapture = "Disable"
        elif b == 1:
            self.videoCapture = "Manual"
        elif b == 2:
            self.videoCapture = "Enable"
        else:
            self.videoCapture = "Unknown"
        return self.videoCapture

    def getDataLossConfirmation(self):
        self.seek(0x3036)
        b = self.readInt8("little")
        if b == 0:
            self.dataLossConfirmation = "None"
        elif b == 1:
            self.dataLossConfirmation = "Required"
        else:
            self.dataLossConfirmation = "Unknown"
        return self.dataLossConfirmation

    def getPlayLogPolicy(self):
        self.seek(0x3037)
        b = self.readInt8("little")
        if b == 0:
            self.playLogPolicy = "All"
        elif b == 1:
            self.playLogPolicy = "LogOnly"
        elif b == 2:
            self.playLogPolicy = "None"
        else:
            self.playLogPolicy = "Unknown"
        return self.playLogPolicy

    def getPresenceGroupId(self):
        self.seek(0x3038)
        self.presenceGroupId = self.readInt64("little")
        return self.presenceGroupId

    def getRatingAge(self, i):
        self.seek(i + 0x3040)
        b = self.readInt8("little")
        if b == 0:
            self.ages[i].age = "0"
        elif b == 3:
            self.ages[i].age = "3"
        elif b == 4:
            self.ages[i].age = "4"
        elif b == 6:
            self.ages[i].age = "6"
        elif b == 7:
            self.ages[i].age = "7"
        elif b == 8:
            self.ages[i].age = "8"
        elif b == 10:
            self.ages[i].age = "10"
        elif b == 12:
            self.ages[i].age = "12"
        elif b == 13:
            self.ages[i].age = "13"
        elif b == 14:
            self.ages[i].age = "14"
        elif b == 15:
            self.ages[i].age = "15"
        elif b == 16:
            self.ages[i].age = "16"
        elif b == 17:
            self.ages[i].age = "17"
        elif b == 18:
            self.ages[i].age = "18"
        else:
            self.ages[i].age = "Unknown"
        return self.ages[i].age

    def getDisplayVersion(self):
        self.seek(0x3060)
        self.displayVersion = self.read(0xF)
        self.displayVersion = self.displayVersion.split(b"\0", 1)[0].decode("utf-8")
        return self.displayVersion

    def getAddOnContentBaseId(self):
        self.seek(0x3070)
        self.addOnContentBaseId = self.readInt64("little")
        return self.addOnContentBaseId

    def getSaveDataOwnerId(self):
        self.seek(0x3078)
        self.saveDataOwnerId = self.readInt64("little")
        return self.saveDataOwnerId

    def getUserAccountSaveDataSize(self):
        self.seek(0x3080)
        self.userAccountSaveDataSize = self.readInt64("little")
        return self.userAccountSaveDataSize

    def getUserAccountSaveDataJournalSize(self):
        self.seek(0x3088)
        self.userAccountSaveDataJournalSize = self.readInt64("little")
        return self.userAccountSaveDataJournalSize

    def getDeviceSaveDataSize(self):
        self.seek(0x3090)
        self.deviceSaveDataSize = self.readInt64("little")
        return self.deviceSaveDataSize

    def getDeviceSaveDataJournalSize(self):
        self.seek(0x3098)
        self.deviceSaveDataJournalSize = self.readInt64("little")
        return self.deviceSaveDataJournalSize

    def getBcatDeliveryCacheStorageSize(self):
        self.seek(0x30A0)
        self.bcatDeliveryCacheStorageSize = self.readInt64("little")
        return self.bcatDeliveryCacheStorageSize

    def getApplicationErrorCodeCategory(self):
        self.seek(0x30A8)
        self.applicationErrorCodeCategory = (
            self.read(0x7).split(b"\0", 1)[0].decode("utf-8")
        )
        return self.applicationErrorCodeCategory

    def getLocalCommunicationId(self):
        self.seek(0x30B0)
        self.localCommunicationId = self.readInt64("little")
        return self.localCommunicationId

    def getLogoType(self):
        self.seek(0x30F0)
        b = self.readInt8("little")
        if b == 0:
            self.logoType = "LicensedByNintendo"
        elif b == 2:
            self.logoType = "Nintendo"
        else:
            self.logoType = "Unknown"
        return self.logoType

    def getLogoHandling(self):
        self.seek(0x30F1)
        b = self.readInt8("little")
        if b == 0:
            self.logoHandling = "Auto"
        elif b == 1:
            self.logoHandling = "Manual"
        else:
            self.logoHandling = "Unknown"
        return self.logoHandling

    def getRuntimeAddOnContentInstall(self):
        self.seek(0x30F2)
        b = self.readInt8("little")
        if b == 0:
            self.runtimeAddOnContentInstall = "Deny"
        elif b == 1:
            self.runtimeAddOnContentInstall = "AllowAppend"
        else:
            self.runtimeAddOnContentInstall = "Unknown"
        return self.runtimeAddOnContentInstall

    def getCrashReport(self):
        self.seek(0x30F6)
        b = self.readInt8("little")
        if b == 0:
            self.crashReport = "Deny"
        elif b == 1:
            self.crashReport = "Allow"
        else:
            self.crashReport = "Unknown"
        return self.crashReport

    def getHdcp(self):
        self.seek(0x30F7)
        b = self.readInt8("little")
        if b == 0:
            self.hdcp = "None"
        elif b == 1:
            self.hdcp = "Required"
        else:
            self.hdcp = "Unknown"
        return self.hdcp

    def getSeedForPseudoDeviceId(self):
        self.seek(0x30F8)
        self.seedForPseudoDeviceId = self.readInt64("little")
        return self.seedForPseudoDeviceId

    def getBcatPassphrase(self):
        self.seek(0x3100)
        self.bcatPassphrase = self.read(0x40).split(b"\0", 1)[0].decode("utf-8")
        return self.bcatPassphrase

    def getUserAccountSaveDataSizeMax(self):
        self.seek(0x3148)
        self.userAccountSaveDataSizeMax = self.readInt64("little")
        return self.userAccountSaveDataSizeMax

    def getUserAccountSaveDataJournalSizeMax(self):
        self.seek(0x3150)
        self.userAccountSaveDataJournalSizeMax = self.readInt64("little")
        return self.userAccountSaveDataJournalSizeMax

    def getDeviceSaveDataSizeMax(self):
        self.seek(0x3158)
        self.deviceSaveDataSizeMax = self.readInt64("little")
        return self.deviceSaveDataSizeMax

    def getDeviceSaveDataJournalSizeMax(self):
        self.seek(0x3160)
        self.deviceSaveDataJournalSizeMax = self.readInt64("little")
        return self.deviceSaveDataJournalSizeMax

    def getTemporaryStorageSize(self):
        self.seek(0x3168)
        self.temporaryStorageSize = self.readInt64("little")
        return self.temporaryStorageSize

    def getCacheStorageSize(self):
        self.seek(0x3170)
        self.cacheStorageSize = self.readInt64("little")
        return self.cacheStorageSize

    def getCacheStorageJournalSize(self):
        self.seek(0x3178)
        self.cacheStorageJournalSize = self.readInt64("little")
        return self.cacheStorageJournalSize

    def getCacheStorageDataAndJournalSizeMax(self):
        self.seek(0x3180)
        self.cacheStorageDataAndJournalSizeMax = self.readInt32("little")
        return self.cacheStorageDataAndJournalSizeMax

    def getCacheStorageIndexMax(self):
        self.seek(0x3188)
        self.cacheStorageIndexMax = self.readInt16("little")
        return self.cacheStorageIndexMax

    def getPlayLogQueryableApplicationId(self):
        self.seek(0x3190)
        self.playLogQueryableApplicationId = self.readInt64("little")
        return self.playLogQueryableApplicationId

    def getPlayLogQueryCapability(self):
        self.seek(0x3210)
        b = self.readInt8("little")
        if b == 0:
            self.playLogQueryCapability = "None"
        elif b == 1:
            self.playLogQueryCapability = "WhiteList"
        elif b == 2:
            self.playLogQueryCapability = "All"
        else:
            self.playLogQueryCapability = "Unknown"
        return self.playLogQueryCapability

    def getRepair(self):
        self.seek(0x3211)
        b = self.readInt8("little")
        if b == 0:
            self.repair = "None"
        elif b == 1:
            self.repair = "SuppressGameCardAccess"
        else:
            self.repair = "Unknown"
        return self.repair

    def getProgramIndex(self):
        self.seek(0x3212)
        self.programIndex = self.readInt8("little")
        return self.programIndex

    def getRequiredNetworkServiceLicenseOnLaunch(self):
        self.seek(0x3213)
        b = self.readInt8("little")
        if b == 0:
            self.requiredNetworkServiceLicenseOnLaunch = "None"
        elif b == 1:
            self.requiredNetworkServiceLicenseOnLaunch = "Common"
        else:
            self.requiredNetworkServiceLicenseOnLaunch = "Unknown"
        return self.requiredNetworkServiceLicenseOnLaunch

    def printInfo(self, indent=0):
        tabs = "\t" * indent
        Print.info("\n%sNintendo Application Control Property (NACP)\n" % (tabs))
        super(Nacp, self).printInfo(indent)

        for i in range(15):
            if self.getName(i) == "":
                pass
            else:
                Print.info("Title:")
                Print.info(
                    "  Language: "
                    + str(NacpLanguageType(i)).replace("NacpLanguageType.", "")
                )
                Print.info("  Name = {0}".format(self.getName(i)))
                Print.info("  Publisher = {0}".format(self.getPublisher(i)))

        if str(self.getIsbn()) == "":
            pass
        else:
            Print.info("Isbn = {0}".format(str(self.getIsbn())))

        Print.info(
            "AddOnContentRegistrationType = {0}".format(
                str(self.getAddOnContentRegistrationType())
            )
        )
        Print.info("StartupUserAccount = {0}".format(str(self.getStartupUserAccount())))
        Print.info(
            "UserAccountSwitchLock = {0}".format(str(self.getUserAccountSwitchLock()))
        )
        Print.info("Attribute = {0}".format(str(self.getAttribute())))
        Print.info("ParentalControl = {0}".format(str(self.getParentalControl())))
        Print.info("Screenshot = {0}".format(str(self.getScreenshot())))
        Print.info("VideoCapture = {0}".format(str(self.getVideoCapture())))
        Print.info(
            "DataLossConfirmation = {0}".format(str(self.getDataLossConfirmation()))
        )
        Print.info("PlayLogPolicy = {0}".format(str(self.getPlayLogPolicy())))
        Print.info(
            "PresenceGroupId = 0x{0}".format(
                hex(self.getPresenceGroupId()).replace("0x", "").zfill(16)
            )
        )

        for i in range(12):
            if str(self.getRatingAge(i)) == "Unknown":
                pass
            else:
                Print.info("Rating:")
                Print.info(
                    "  Organization: "
                    + str(OrganizationType(i)).replace("OrganizationType.", "")
                )
                Print.info("  Age = {0}".format(str(self.getRatingAge(i))))

        Print.info("DisplayVersion = {0}".format(str(self.getDisplayVersion())))
        Print.info(
            "AddOnContentBaseId = 0x{0}".format(
                hex(self.getAddOnContentBaseId()).replace("0x", "").zfill(16)
            )
        )
        Print.info(
            "SaveDataOwnerId = 0x{0}".format(
                hex(self.getSaveDataOwnerId()).replace("0x", "").zfill(16)
            )
        )
        Print.info(
            "UserAccountSaveDataSize = 0x{0}".format(
                hex(self.getUserAccountSaveDataSize()).replace("0x", "").zfill(16)
            )
        )
        Print.info(
            "UserAccountSaveDataJournalSize = 0x{0}".format(
                hex(self.getUserAccountSaveDataJournalSize())
                .replace("0x", "")
                .zfill(16)
            )
        )
        Print.info(
            "DeviceSaveDataSize = 0x{0}".format(
                hex(self.getDeviceSaveDataSize()).replace("0x", "").zfill(16)
            )
        )
        Print.info(
            "DeviceSaveDataJournalSize = 0x{0}".format(
                hex(self.getDeviceSaveDataJournalSize()).replace("0x", "").zfill(16)
            )
        )

        if (
            hex(self.getBcatDeliveryCacheStorageSize()).replace("0x", "").zfill(16)
            == "0000000000000000"
        ):
            pass
        else:
            Print.info(
                "BcatDeliveryCacheStorageSize = 0x{0}".format(
                    hex(self.getBcatDeliveryCacheStorageSize())
                    .replace("0x", "")
                    .zfill(16)
                )
            )

        if str(self.getApplicationErrorCodeCategory()) == "":
            pass
        else:
            Print.info(
                "ApplicationErrorCodeCategory = "
                + str(self.getApplicationErrorCodeCategory())
            )

        Print.info(
            "LocalCommunicationId = 0x{0}".format(
                hex(self.getLocalCommunicationId()).replace("0x", "").zfill(16)
            )
        )
        Print.info("LogoType = " + str(self.getLogoType()))
        Print.info("LogoHandling = " + str(self.getLogoHandling()))
        Print.info(
            "RuntimeAddOnContentInstall = {0}".format(
                str(self.getRuntimeAddOnContentInstall())
            )
        )
        Print.info("CrashReport = " + str(self.getCrashReport()))
        Print.info("Hdcp = " + str(self.getHdcp()))
        Print.info(
            "SeedForPseudoDeviceId = 0x{0}".format(
                hex(self.getSeedForPseudoDeviceId()).replace("0x", "").zfill(16)
            )
        )

        if (
            str(self.getBcatPassphrase())
            == "0000000000000000000000000000000000000000000000000000000000000000"
        ):
            pass
        elif str(self.getBcatPassphrase()) == "":
            pass
        else:
            Print.info("BcatPassphrase = {0}".format(str(self.getBcatPassphrase())))

        Print.info(
            "UserAccountSaveDataSizeMax = 0x{0}".format(
                hex(self.getUserAccountSaveDataSizeMax()).replace("0x", "").zfill(16)
            )
        )
        Print.info(
            "UserAccountSaveDataJournalSizeMax = 0x{0}".format(
                hex(self.getUserAccountSaveDataJournalSizeMax())
                .replace("0x", "")
                .zfill(16)
            )
        )
        Print.info(
            "DeviceSaveDataSizeMax = 0x{0}".format(
                hex(self.getDeviceSaveDataSizeMax()).replace("0x", "").zfill(16)
            )
        )
        Print.info(
            "DeviceSaveDataJournalSizeMax = 0x{0}".format(
                hex(self.getDeviceSaveDataJournalSizeMax()).replace("0x", "").zfill(16)
            )
        )
        Print.info(
            "TemporaryStorageSize = 0x{0}".format(
                hex(self.getTemporaryStorageSize()).replace("0x", "").zfill(16)
            )
        )
        Print.info(
            "CacheStorageSize = 0x{0}".format(
                hex(self.getCacheStorageSize()).replace("0x", "").zfill(16)
            )
        )
        Print.info(
            "CacheStorageJournalSize = 0x{0}".format(
                hex(self.getCacheStorageJournalSize()).replace("0x", "").zfill(16)
            )
        )
        Print.info(
            "CacheStorageDataAndJournalSizeMax = 0x{0}".format(
                hex(self.getCacheStorageDataAndJournalSizeMax())
                .replace("0x", "")
                .zfill(8)
            )
        )
        Print.info(
            "CacheStorageIndexMax = 0x{0}".format(
                hex(self.getCacheStorageIndexMax()).replace("0x", "").zfill(4)
            )
        )
        Print.info(
            "PlayLogQueryableApplicationId = 0x{0}".format(
                hex(self.getPlayLogQueryableApplicationId()).replace("0x", "").zfill(16)
            )
        )
        Print.info(
            "PlayLogQueryableApplicationId = 0x{0}".format(
                hex(self.getPlayLogQueryableApplicationId()).replace("0x", "").zfill(16)
            )
        )
        Print.info(
            "PlayLogQueryCapability = {0}".format(str(self.getPlayLogQueryCapability()))
        )
        Print.info("Repair = {0}".format(str(self.getRepair())))
        Print.info("ProgramIndex = {0}".format(str(self.getProgramIndex())))
        Print.info(
            "RequiredNetworkServiceLicenseOnLaunch = {0}".format(
                str(self.getRequiredNetworkServiceLicenseOnLaunch())
            )
        )
