//
// Generated by dtk
// Translation Unit: m_Do_machine.cpp
//

#include "m_Do/m_Do_machine.h"
#include "JSystem/JFramework/JFWSystem.h"
#include "JSystem/JKernel/JKRAram.h"
#include "JSystem/JKernel/JKRAramStream.h"
#include "JSystem/JKernel/JKRDvdAramRipper.h"
#include "JSystem/JKernel/JKRExpHeap.h"
#include "JSystem/JMath/JMath.h"
#include "JSystem/JUtility/JUTAssert.h"
#include "JSystem/JUtility/JUTConsole.h"
#include "JSystem/JUtility/JUTDbPrint.h"
#include "JSystem/JUtility/JUTException.h"
#include "JSystem/JUtility/JUTGamePad.h"
#include "JSystem/JUtility/JUTVideo.h"
#include "SSystem/SComponent/c_malloc.h"
#include "SSystem/SComponent/c_math.h"
#include "dolphin/base/PPCArch.h"
#include "dolphin/gx/GXStruct.h"
#include "dolphin/vi/vi.h"
#include "m_Do/m_Do_DVDError.h"
#include "m_do/m_Do_MemCard.h"
#include "m_Do/m_Do_Reset.h"
#include "m_Do/m_Do_dvd_thread.h"
#include "m_Do/m_Do_ext.h"
#include "m_Do/m_Do_machine_exception.h"
#include "m_Do/m_Do_main.h"
#include "m_Do/m_Do_printf.h"

namespace mDoMch {
    static u8 mDebugFill;
}

static int solidHeapErrors;
static int gameHeapErrors;
static int zeldaHeapErrors;
static int commandHeapErrors;
static int archiveHeapErrors;
static int unknownHeapErrors;
static u32 heapErrors;

/* 8000BD24-8000BEEC       .text myGetHeapTypeByString__FP7JKRHeap */
const char* myGetHeapTypeByString(JKRHeap* p_heap) {
        static char tmpString[5];

    if (p_heap == JKRHeap::getSystemHeap()) {
        return "SystemHeap";
    }

    if (p_heap == mDoExt_getZeldaHeap()) {
        return "ZeldaHeap";
    }

    if (p_heap == mDoExt_getGameHeap()) {
        return "GameHeap";
    }

    if (p_heap == mDoExt_getArchiveHeap()) {
        return "ArchiveHeap";
    }

    if (p_heap == mDoExt_getCommandHeap()) {
        return "CommandHeap";
    }

    u32 heapType = p_heap->getHeapType();
    switch (heapType) {
    case 'ASTH':
        return "ASTH";
    case 'EXPH':
        return "EXPH";
    case 'SLID':
        return "SLID";
    case 'STDH':
        return "STDH";
    case 'UNIT':
        return "UNIT";
    case 0:
        return "(Null)";
    default:
        u32 tmpType = heapType;
        char* typeStr = (char*)&tmpType;

        tmpString[0] = typeStr[0];
        tmpString[1] = typeStr[1];
        tmpString[2] = typeStr[2];
        tmpString[3] = typeStr[3];
        tmpString[4] = 0;
        return tmpString;
    }
}

/* 8000BEEC-8000C0C8       .text myMemoryErrorRoutine__FPvUli */
void myMemoryErrorRoutine(void* p_heap, u32 size, int alignment) {
    JKRHeap* heap = (JKRHeap*)p_heap;

    BOOL notSolidHeap = true;
    if (heap->getHeapType() == 'SLID') {
        notSolidHeap = false;
    }

    if (notSolidHeap) {
        OSReport_Error(
            "Error: Cannot allocate memory %d(0x%x)byte in %d byte alignment from %08x\n",
            size, size, alignment, p_heap);
    }

    u32 heapType = heap->getHeapType();
    u8* tmpString = (u8*)&heapType;
    if (notSolidHeap) {
        OSReport_Error(
            "FreeSize=%08x TotalFreeSize=%08x HeapType=%08x(%c%c%c%c) HeapSize=%08x %s\n",
            heap->getFreeSize(), heap->getTotalFreeSize(), heapType, tmpString[0], tmpString[1],
            tmpString[2], tmpString[3], heap->getHeapSize(), myGetHeapTypeByString(heap));
    }

    if (heapErrors == 0) {
        heap->dump_sort();
    }
    heapErrors++;

    if (p_heap == zeldaHeap) {
        zeldaHeapErrors++;
    } else if (p_heap == gameHeap) {
        gameHeapErrors++;
    } else if (p_heap == commandHeap) {
        commandHeapErrors++;
    } else if (p_heap == archiveHeap) {
        archiveHeapErrors++;
    } else if (heap->getHeapType() == 'SLID') {
        solidHeapErrors++;
    } else {
        unknownHeapErrors++;
    }
}

/* 8000C0C8-8000C168       .text myHeapCheckRecursive__FP7JKRHeap */
void myHeapCheckRecursive(JKRHeap* p_heap) {
    if (!p_heap->check()) {
        const char* type = myGetHeapTypeByString(p_heap);
        OSReport_Error("error in %08x(%s)\n", p_heap, type);
    }

    JSUTree<JKRHeap>* heapTree = &p_heap->getHeapTree();
    for (JSUTree<JKRHeap>* i = heapTree->getFirstChild(); i != NULL; i = i->getNextChild()) {
        myHeapCheckRecursive(i->getObject());
    }
}

/* 8000C168-8000C18C       .text mDoMch_HeapCheckAll__Fv */
void mDoMch_HeapCheckAll() {
    myHeapCheckRecursive(JKRHeap::sRootHeap);
}

/* 8000C18C-8000C23C       .text developKeyCheck__FUlUl */
int developKeyCheck(u32 btnTrig, u32 btnHold) {
    static u8 key_link;
    static u8 key_ganon;
    static u8 key_zelda;

    if (btnHold == (CButton::L | CButton::R | CButton::Z | CButton::DPAD_DOWN) &&
        btnTrig == CButton::DPAD_DOWN) {
        if (key_link == 3 && key_ganon == 6 && key_zelda == 5) {
            mDoMain::developmentMode = 1;
        } else {
            key_link = 0;
            key_ganon = 0;
            key_zelda = 0;
        }
    }

    if (btnHold == (CButton::L | CButton::DPAD_RIGHT) && btnTrig == CButton::L) {
        key_link++;
    }

    if (btnHold == (CButton::R | CButton::DPAD_UP) && btnTrig == CButton::R) {
        key_ganon++;
    }

    if (btnHold == (CButton::Z | CButton::DPAD_LEFT) && btnTrig == CButton::Z) {
        key_zelda++;
    }

    return mDoMain::developmentMode;
}

/* 8000C23C-8000C3C0       .text myExceptionCallback__FUsP9OSContextUlUl */
void myExceptionCallback(unsigned short, OSContext*, unsigned long, unsigned long) {
    u32 btnHold;
    u32 btnTrig;

    mDoMain::sHungUpTime = OSGetTime();
    OSReportEnable();
    JUTGamePad::clearForReset();
    // "Vibration stopping & resetting to default\n"
    OSReport("振動停止＆原点復帰\n");

    JUTException* manager = JUTException::getManager();

    if (manager == NULL) {
        // "Exception Manager doesn't exist\n"
        OSReport("例外マネージャがありません\n");
        PPCHalt();
    }
    if (mDoMain::developmentMode == 0) {
        JUTGamePad pad(JUTGamePad::Port_1);
        manager->setGamePad(&pad);

        if (manager != NULL) {
            OSEnableInterrupts();
            // "Accepting Key input\n"
            OSReport("キー入力を受け付けています\n");
            while (mDoMain::developmentMode == 0) {
                manager->readPad(&btnTrig, &btnHold);
                developKeyCheck(btnTrig, btnHold);
                JUTException::waitTime(30);
                if (JUTGamePad::C3ButtonReset::sResetOccurred) {
                    OSReport("リセット受け付けています\n");
                    OSResetSystem(1,0,0);
                }
            }
            // "JUTAssertion is visible\n"
            OSReport("JUTAssertionを可視化しました\n");
            JUTAssertion::setVisible(true);
            JUTDbPrint::getManager()->setVisible(true);
            JFWSystem::getSystemConsole()->setOutput(JUTConsole::OUTPUT_OSREPORT |
                                                        JUTConsole::OUTPUT_CONSOLE);
        } else {
            PPCHalt();
        }
    } else {
        // "Wait for 3 seconds\n"
        OSReport("3秒間停止\n");
        JUTException::waitTime(3000);
    }
}

/* 8000C3C0-8000C70C       .text fault_callback_scroll__FUsP9OSContextUlUl */
void fault_callback_scroll(u16, OSContext* p_context, u32, u32) {
    JUTException* manager = JUTException::getManager();
    JUTConsole* exConsole = manager->getConsole();

    JUTGamePad pad(JUTGamePad::Port_1);
    manager->setGamePad(&pad);

    BOOL padDisabled = manager->isEnablePad() == false;
    if (!padDisabled) {
        exConsole->print("PUSH START BUTTON TO ADDITIONAL INFOMATION\n");
        exConsole->print("--------------------------------------\n");
        JUTConsoleManager::getManager()->drawDirect(true);
        OSEnableInterrupts();
        int holdUpCount = 0;
        int holdDownCount = 0;

        while (true) {
            u32 btnHold, btnTrig;
            manager->readPad(&btnTrig, &btnHold);

            if (JUTGamePad::C3ButtonReset::sResetOccurred) {
                OSResetSystem(1, 0, 0);
            }

            bool waitRetrace = false;
            if (btnTrig == CButton::START) {
                exception_addition(exConsole);
                waitRetrace = true;
            }

            if (btnTrig == CButton::Z) {
                JUTConsole* sysConsole = JFWSystem::getSystemConsole();
                if (JUTConsoleManager::getManager()->getDirectConsole() != sysConsole) {
                    exConsole = sysConsole;
                    exConsole->setFontSize(8.0f, 6.0f);
                    exConsole->setPosition(8, 32);
                    exConsole->setHeight(23);
                    exConsole->setVisible(true);
                    exConsole->setOutput(JUTConsole::OUTPUT_CONSOLE | JUTConsole::OUTPUT_OSREPORT);
                } else {
                    exConsole = JUTException::getConsole();
                }
                JUTConsoleManager::getManager()->setDirectConsole(exConsole);
                waitRetrace = true;
            }

            if (btnTrig == CButton::A) {
                exConsole->scrollToLastLine();
                waitRetrace = true;
            }

            if (btnTrig == CButton::B) {
                exConsole->scrollToFirstLine();
                waitRetrace = true;
            }

            if (btnHold == CButton::DPAD_UP) {
                exConsole->scroll(holdUpCount < 3 ? -1 : (holdUpCount < 5 ? -2 : (holdUpCount < 7 ? -4 : -8)));
                waitRetrace = true;
                holdDownCount = 0;
                holdUpCount++;
            } else if (btnHold == CButton::DPAD_DOWN) {
                exConsole->scroll(holdDownCount < 3 ? 1 : (holdDownCount < 5 ? 2 : (holdDownCount < 7 ? 4 : 8)));
                waitRetrace = true;
                holdUpCount = 0;
                holdDownCount++;
            } else {
                holdUpCount = 0;
                holdDownCount = 0;
            }

            if (waitRetrace == true) {
                u32 count = VIGetRetraceCount();
                do {
                } while (count == VIGetRetraceCount());
                JUTConsoleManager::getManager()->drawDirect(true);
            }

            JUTException::waitTime(30);
        }
    }

    exception_addition(exConsole);
    JUTConsoleManager::getManager()->drawDirect(true);

    do {
        exConsole->scrollToFirstLine();
        JUTConsoleManager::getManager()->drawDirect(true);
        JUTException::waitTime(2000);

        do {
            for (u32 i = exConsole->getHeight(); i != 0; i--) {
                exConsole->scroll(1);
                JUTConsoleManager::getManager()->drawDirect(true);

                if ((exConsole->getUsedLine() - exConsole->getHeight()) + 1 <=
                    exConsole->getLineOffset()) {
                    break;
                }
                JUTException::waitTime(20);
            }

            JUTException::waitTime(3000);
             if ((exConsole->getUsedLine() - exConsole->getHeight()) + 1 <=
                exConsole->getLineOffset()) {
                break;
            }
        } while (true);
    } while (true);
}

#if VERSION != VERSION_PAL
GXRenderModeObj g_ntscZeldaIntDf = {
    0, 640, 480, 480, 30, 0, 660, 480, 1, 0, 0,
    {{6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6}},
    {8, 8, 10, 12, 10, 8, 8},
};
GXRenderModeObj g_ntscZeldaProg = {
    2, 640, 480, 480, 30, 0, 660, 480, 0, 0, 0,
    {{6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6}},
    {0, 0, 21, 22, 21, 0, 0},
};
#else
GXRenderModeObj g_ntscZeldaIntDf = {
    4, 640, 480, 534, 30, 20, 660, 534, 1, 0, 0,
    {{6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6}},
    {8, 8, 10, 12, 10, 8, 8},
};
GXRenderModeObj g_ntscZeldaProg = {
    20, 640, 480, 480, 30, 0, 660, 480, 1, 0, 0,
    {{6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6},
     {6, 6}},
    {8, 8, 10, 12, 10, 8, 8},
};
#endif

/* 8000C70C-8000CB48       .text mDoMch_Create__Fv */
bool mDoMch_Create() {
    if (mDoMain::developmentMode == 0 || !(OSGetConsoleType() & 0x10000000)) {
        OSReportDisable();
    }

    JKRHeap::setDefaultDebugFill(mDoMch::mDebugFill);
    JFWSystem::setMaxStdHeap(1);

    u32 arenaHi = (u32)OSGetArenaHi();
    u32 arenaLo = (u32)OSGetArenaLo();
    if (arenaHi > 0x81800000 && arenaHi - 0x1800000 > arenaLo) {
        OSSetArenaHi((void*)(arenaHi - 0x1800000));
    }

    u32 arenaSize = ((u32)OSGetArenaHi() - (u32)OSGetArenaLo()) - 0xF0;
#if VERSION != VERSION_PAL
    if (OSGetConsoleSimulatedMemSize() >= 0x3000000) {
        arenaSize -= 0x1000000;
    }
#endif

    if (mDoMain::memMargin != -1) {
        arenaSize += mDoMain::memMargin;
    }

#if VERSION == VERSION_JPN
    JFWSystem::setSysHeapSize(arenaSize - 0xD0E000);
    JFWSystem::setFifoBufSize(0x80000);
#else
    JFWSystem::setSysHeapSize(arenaSize - 0xD20C00);
    JFWSystem::setFifoBufSize(0xA0000);
#endif
    JFWSystem::setAramAudioBufSize(0xA00000);
    JFWSystem::setAramGraphBufSize(0x5CE000);
#if VERSION == VERSION_PAL
    if (OSGetResetCode() - 0x80000000 == 0 && OSGetEuRgb60Mode() == 1) {
        mDoMch_render_c::setProgressiveMode();
    }
#endif
    JFWSystem::setRenderMode(mDoMch_render_c::getRenderModeObj());
    JFWSystem::init();

    if (mDoMain::developmentMode == 0) {
        JUTAssertion::setVisible(false);
        JUTDbPrint::getManager()->setVisible(false);
    }

    JKRHeap::setErrorHandler(myMemoryErrorRoutine);
    JKRHeap::getRootHeap()->setErrorFlag(true);
    JFWSystem::getSystemHeap()->setErrorFlag(true);

    JKRHeap* rootHeap = JKRHeap::getRootHeap();
#if VERSION == VERSION_JPN
    rootHeap->dump_sort();
#endif
    // Command Heap size: 4 KB
    mDoExt_createCommandHeap(0x1000, rootHeap);
#if VERSION == VERSION_JPN
    rootHeap->dump_sort();
#endif

#if VERSION == VERSION_JPN
    mDoExt_createArchiveHeap(0xA3F000, rootHeap);
    mDoExt_createGameHeap(0x2CE000, rootHeap);
#else
    // Archive Heap size: 10565 KB
    mDoExt_createArchiveHeap(0xA51400, rootHeap);

    // Game Heap size: 2874 KB
    mDoExt_createGameHeap(0x2CE800, rootHeap);
#endif


    JKRHeap* sysHeap = JKRHeap::getSystemHeap();
    s32 size = sysHeap->getFreeSize() - 0x10000;
    JUT_ASSERT(VERSION_SELECT(996, 1104, 1143), size > 0);
    JKRHeap* zeldaHeap = mDoExt_createZeldaHeap(size, sysHeap);
    zeldaHeap->becomeCurrentHeap();

    JKRAramStream::setTransBuffer(NULL, 0x2000, JKRHeap::getSystemHeap());
    JKRAram::setSzpBufferSize(0x2000);
    JKRDvdAramRipper::setSzpBufferSize(0x2000);
    JKRDvdRipper::setSzpBufferSize(0x2000);
    JKRThreadSwitch::createManager(NULL);
    JKRThread* thread = new JKRThread(OSGetCurrentThread(), 0);

    JUTConsole* sysConsole = JFWSystem::getSystemConsole();
    sysConsole->setOutput(JUTConsole::OUTPUT_CONSOLE | JUTConsole::OUTPUT_OSREPORT);
    sysConsole->setPosition(16, 42);

    JUTException::appendMapFile("/maps/framework.map");
    JUTException::setPreUserCallback(myExceptionCallback);
    JUTException::setPostUserCallback(fault_callback_scroll);
    JMANewSinTable(0xc);

    cMl::init(mDoExt_getZeldaHeap());
    cM_initRnd(100, 100, 100);
    mDoDvdThd::create(OSGetThreadPriority(OSGetCurrentThread()) - 2);
    mDoDvdErr_ThdInit();
    mDoMemCd_ThdInit();
    return true;
}

GXRenderModeObj* mDoMch_render_c::mRenderModeObj = &g_ntscZeldaIntDf;
