/*---------------------------------------------------------------------------*
  Project:  NITRO-System - build - demos - mcs - file_io - nitro
  File:     main.c

  Copyright 2005 Nintendo.  All rights reserved.

  These coded instructions, statements, and computer programs contain
  proprietary information of Nintendo of America Inc. and/or Nintendo
  Company Ltd., and are protected by Federal copyright law.  They may
  not be disclosed to third parties or copied or duplicated in any form,
  in whole or in part, without the prior written consent of Nintendo.

  $Log: main.c,v $
  Revision 1.1  01/24/2005 04:13:15  kitamurs
  Initial Version

  $NoKeywords: $
 *---------------------------------------------------------------------------*/

// ============================================================================
//  Explanation of the demo:
//      This demo uses the mcs library to read and write to files
//      on the PC and to list the files that are on the PC.
//      The specific actions are explained below:
//
//        1. Reads the file below the NITRO-System root directory in
//             "build\demos\mcs\file_io\nitro\data\test.txt"
//           then inverts the content and writes it to the separate file
//             "build\demos\mcs\file_io\nitro\data\test_wr.txt"
//            
//        2. Searches for files with the ".txt" extension below the following directory.
//             "build\demos\mcs\file_io\nitro\data"
//            
//
// ============================================================================

#include <nitro.h>
#include <extras.h>

#include <nnsys/fnd.h>
#include <nnsys/mcs.h>
#include <nnsys/misc.h>

// The directory for this project
#define PROJECT_DIR "%NITROSYSTEM_ROOT%\\build\\demos\\mcs\\file_io\\nitro"

// The structure for managing the file data
typedef struct FileData FileData;
struct FileData
{
    char*   buf;
    u32     size;
};

static NNSFndHeapHandle gExpHeap;

/*---------------------------------------------------------------------------*
  Name:         VBlankIntr

  Description:  The V blank interrupt handler.

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
static void
VBlankIntr(void)
{
    OS_SetIrqCheckFlag(OS_IE_V_BLANK);

    NNS_McsVBlankInterrupt();
}

/*---------------------------------------------------------------------------*
  Name:         CartIntrFunc

  Description:  The cartridge interrupt handler.

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
static void
CartIntrFunc(void)
{
    OS_SetIrqCheckFlag(OS_IE_CARTRIDGE);

    NNS_McsCartridgeInterrupt();
}

/*---------------------------------------------------------------------------*
  Name:         InitInterrupt

  Description:  Performs the initialization related to interrupts.

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
static void
InitInterrupt()
{
    (void)OS_DisableIrq();

    // Enable V blank interrupts, and set so NNS_McsVBlankInterrupt()
    // gets called from inside VBlank interrupt.
    OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
    (void)OS_EnableIrqMask(OS_IE_V_BLANK);
    (void)GX_VBlankIntr(TRUE);

    // Enable cartridge interrupts, and set so NNS_McsCartridgeInterrupt()
    // gets called from inside cartridge interrupt
    OS_SetIrqFunction(OS_IE_CARTRIDGE, CartIntrFunc);
    (void)OS_EnableIrqMask(OS_IE_CARTRIDGE);

    (void)OS_EnableIrq();
}

/*---------------------------------------------------------------------------*
  Name:         SampleFileRead

  Description:  Reads the contents of the file.

  Arguments:    pFileData:  Pointer to the structure where the file  information is stored.

  Returns:      TRUE if the read succeeds. FALSE if it fails.
 *---------------------------------------------------------------------------*/
static BOOL
SampleFileRead(FileData* pFileData)
{
    void* pDataBuf = 0;
    BOOL bSuccess = FALSE;
    NNSMcsFile info;
    u32 errCode;
    u32 readSize;

    OS_Printf("read test.txt\n");

    // Open the file
    errCode = NNS_McsOpenFile(
        &info,
        PROJECT_DIR "\\data\\test.txt",
            NNS_MCS_FILEIO_FLAG_READ
          | NNS_MCS_FILEIO_FLAG_INCENVVAR); // Expand the PC's environment variables character string
    if (errCode)
    {
        OS_Printf("error : NNS_McsOpenFile() test.txt .\n");
        return FALSE;
    }

    // Secure a buffer for loading the entire file.
    // Entire file regarded as character string, so secure an extra 1 byte for the termination string.
    pDataBuf = NNS_FndAllocFromExpHeap(gExpHeap, NNS_McsGetFileSize(&info) + 1);
    NNS_NULL_ASSERT(pDataBuf);

    // Read the file
    errCode = NNS_McsReadFile(&info, pDataBuf, NNS_McsGetFileSize(&info), &readSize);
    if (0 == errCode)
    {
        pFileData->buf = pDataBuf;
        pFileData->size = readSize;
        pFileData->buf[readSize] = '\0';
        bSuccess = TRUE;
    }
    else
    {
        // The reading has failed, so release memory
        NNS_FndFreeToExpHeap(gExpHeap, pDataBuf);
    }

    // Close the file
    (void)NNS_McsCloseFile(&info);

    return bSuccess;
}

/*---------------------------------------------------------------------------*
  Name:         SampleFileWrite

  Description:  Writes to a file.

  Arguments:    pFileData:  Pointer to the structure where the file  information is stored.

  Returns:      None.
 *---------------------------------------------------------------------------*/
static void
SampleFileWrite(FileData* pFileData)
{
    NNSMcsFile info;
    u32 errCode;

    OS_Printf("write test_wr.txt\n");

    // Open the file
    errCode = NNS_McsOpenFile(
        &info,
        PROJECT_DIR "\\data\\test_wr.txt",
            NNS_MCS_FILEIO_FLAG_WRITE       // Write mode
          | NNS_MCS_FILEIO_FLAG_FORCE       // Overwrite if file exists
          | NNS_MCS_FILEIO_FLAG_INCENVVAR); // Expand the PC's environment variables character string
    if (errCode)
    {
        OS_Printf("error : NNS_McsOpenFile() test_wr.txt .\n");
        return;
    }

    // Write to the file
    errCode = NNS_McsWriteFile(&info, pFileData->buf, pFileData->size);
    if (errCode)
    {
        OS_Printf("error : NNS_McsWriteFile().\n");
    }

    // Close the file
    (void)NNS_McsCloseFile(&info);
}

/*---------------------------------------------------------------------------*
  Name:         SampleFileIO

  Description:  Reads data from a file, inverts the contents and write
                this to a different file.

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
static void
SampleFileIO()
{
    BOOL bSuccess = FALSE;
    FileData fileData;

    // Read the file
    bSuccess = SampleFileRead(&fileData);

    if (bSuccess)
    {
        // Invert the content
        (void)strrev(fileData.buf);

        // Write to a file
        SampleFileWrite(&fileData);
        NNS_FndFreeToExpHeap(gExpHeap, fileData.buf);
    }
}

/*---------------------------------------------------------------------------*
  Name:         SampleFind

  Description:  Lists files that have the ".txt" extension.

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
static void
SampleFind()
{
    NNSMcsFile info;
    NNSMcsFileFindData findData;
    u32 errCode;

    // Search for files with the same pattern
    errCode = NNS_McsFindFirstFile(
        &info,
        &findData,
        PROJECT_DIR "\\data\\*.txt");

    // When no equivalent file can be found:
    if (errCode == NNS_MCS_FILEIO_ERROR_NOMOREFILES)
    {
        OS_Printf("not match *.txt .\n");
        return;
    }

    // Other errors:
    if (errCode != 0)
    {
        OS_Printf("error : NNS_McsFindFirstFile()\n");
        return;
    }

    // Search for the next file with the same pattern.
    // Loop until the NNS_McsFindNextFile function returns a non-zero value.
    // When there no more equivalent files, NNS_MCS_FILEIO_ERROR_NOMOREFILES
    // gets returned.
    do
    {
        OS_Printf("find filename %s %dbytes.\n", findData.name, findData.size);
        errCode = NNS_McsFindNextFile(&info, &findData);
    }while (0 == errCode);

    if (errCode != NNS_MCS_FILEIO_ERROR_NOMOREFILES)
    {
        OS_Printf("error : NNS_McsFindNextFile()\n");
    }

    (void)NNS_McsCloseFind(&info);
}

void
NitroMain(void)
{
    NNSMcsDeviceCaps deviceCaps;

    OS_Init();
    NNS_McsInit();
    InitInterrupt();

    /*
        Allocate the entire arena of main to the expanded heap
    */
    {
        void *const arenaLo = OS_GetArenaLo(OS_ARENA_MAIN);

        OS_SetArenaLo(OS_ARENA_MAIN, OS_GetArenaHi(OS_ARENA_MAIN));

        gExpHeap = NNS_FndCreateExpHeap(arenaLo, (u32)OS_GetArenaHi(OS_ARENA_MAIN) - (u32)arenaLo);
    }

    if (NNS_McsGetMaxCaps() > 0)
    {
        // Open the device
        if (NNS_McsOpen(&deviceCaps))
        {
            // When DS is communicating with IS-NITRO-UIC, there
            // may not be a connection to the mcs server, so wait
            // until a connection from the mcs server is made.
            if (! NNS_McsIsServerConnect())
            {
                OS_Printf("Waiting server connect.\n");
                do
                {
                    SVC_WaitVBlankIntr();
                }while (! NNS_McsIsServerConnect());
            }

            // Initialize the file input/output features
            NNS_McsInitFileIO();

            SampleFileIO();
            SampleFind();

            // Close the device
            (void)NNS_McsClose();
        }
        else
        {
            OS_Printf("device open fail.\n");
        }
    }
    else
    {
        OS_Printf("device not found.\n");
    }

    while (TRUE) {}
}


