/*--------------------------------------------------------------------------
  Project:  Manual 2D Library - m2d
  File:     manualTableOfContents.cpp

  Copyright (C)2007-2009 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.

  $Revision: 1930 $
 *-------------------------------------------------------------------------*/

#include <ntmv/m2d/debug.h>
#include <ntmv/m2d/manualTocResource.h>
#include <ntmv/m2d/common.h>
#include <ntmv/m2d/objectConstructor.h>
#include <ntmv/m2d/arcResourceAccessor.h>
#include <ntmv/m2d/manualTableOfContents.h>

namespace ntmv
{
namespace m2d
{

/*---------------------------------------------------------------------------*
  Name:         ManualHeader::ManualHeader

  Description:  Constructor.

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
ManualHeader::ManualHeader()
:   mHeaderFileName(0),
    mHeaderText(0),
    mHeaderFullText(0),
    mChapterFileNames(0),
    mChapters(0),
    mChapterNum(0)
{}

/*---------------------------------------------------------------------------*
  Name:         ManualHeader::Finalize

  Description:  Performs shutdown.

  Arguments:    objectConstructor:  A reference to an ObjectConstructor object.

  Returns:      None.
 *---------------------------------------------------------------------------*/
void
ManualHeader::Finalize(const ObjectConstructor& objectConstructor)
{
    objectConstructor.DeletePrimArray(mChapterFileNames);
    objectConstructor.DeletePrimArray(mChapters);
}

/*---------------------------------------------------------------------------*
  Name:         ManualHeader::Init

  Description:  Initializes header information from a resource.

  Arguments:    pManualHeader:      A pointer to a res::ManualHeader object.
                pNameBlock:         A pointer to a res::NameBlock object.
                objectConstructor:  A reference to an ObjectConstructor object.

  Returns:      None.
 *---------------------------------------------------------------------------*/
void
ManualHeader::Init(
    const res::ManualHeader*    pManualHeader,
    const res::NameBlock*       pNameBlock,
    const res::TextBlock*       pTextBlock,
    const ObjectConstructor&    objectConstructor
)
{
    NNS_NULL_ASSERT(pManualHeader);
    NNS_NULL_ASSERT(pNameBlock);
    NNS_NULL_ASSERT(pTextBlock);

    if (pManualHeader->headerFileNameIdx != static_cast<u16>(-1))
    {
        mHeaderFileName = detail::GetNamePoolStr(pNameBlock->offsets, pManualHeader->headerFileNameIdx);
    }
    else
    {
        mHeaderFileName = 0;    // There is no predetermined page
    }
    mHeaderText = detail::GetTextPoolStr(pTextBlock->offsets, pManualHeader->headerTextIdx);
    mHeaderFullText = detail::GetTextPoolStr(pTextBlock->offsets, pManualHeader->headerFullTextIdx);

    mChapterNum = pManualHeader->chapterNum;
    mChapterFileNames = objectConstructor.NewArray<const char*>(mChapterNum);
    NNS_NULL_ASSERT(mChapterFileNames);
    mChapters = objectConstructor.NewArray<const wchar_t*>(mChapterNum);
    NNS_NULL_ASSERT(mChapters);

    int nameIdx = pManualHeader->chapterFileNameStartIdx;
    for (int i = 0; i < mChapterNum; ++i, ++nameIdx)
    {
        mChapterFileNames[i] = detail::GetNamePoolStr(pNameBlock->offsets, nameIdx);
    }

    int textIdx = pManualHeader->chapterTextStartIdx;
    for (int i = 0; i < mChapterNum; ++i, ++textIdx)
    {
        mChapters[i] = detail::GetTextPoolStr(pTextBlock->offsets, textIdx);
    }
}

/*---------------------------------------------------------------------------*
  Name:         ManualTableOfContents::ManualTableOfContents

  Description:  Constructor.

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
ManualTableOfContents::ManualTableOfContents()
:   mHeaders(0),
    mHeaderNum(0)
{}

/*---------------------------------------------------------------------------*
  Name:         ManualTableOfContents::Finalize

  Description:  Performs shutdown.

  Arguments:    objectConstructor:  A reference to an ObjectConstructor object.

  Returns:      None.
 *---------------------------------------------------------------------------*/
void
ManualTableOfContents::Finalize(const ObjectConstructor& objectConstructor)
{
    objectConstructor.DeleteArray(mHeaders, mHeaderNum);
}

/*---------------------------------------------------------------------------*
  Name:         ManualTableOfContents::LoadFile

  Description:  Loads the Contents file.

  Arguments:    fileName:  filename

  Returns:      Returns TRUE if loading was successful.
 *---------------------------------------------------------------------------*/
bool
ManualTableOfContents::LoadFile(
    const char*                 fileName,
    ResourceAccessor*           pResAcsr,
    const ObjectConstructor&    objectConstructor
)
{
    // Load the layout resource
    const void* resBuf = pResAcsr->GetLocalizeResource(res::RESOURCETYPE_MANUALTOC, fileName);
    if (! resBuf)
    {
        return false;
    }

    return LoadFileImpl(resBuf, objectConstructor);
}

/*---------------------------------------------------------------------------*
  Name:         ManualTableOfContents::LoadFileImpl

  Description:  Implementation to load a Contents file.

  Arguments:    resBuf:  Pointer to resource data.

  Returns:      Returns TRUE on success.
 *---------------------------------------------------------------------------*/
bool
ManualTableOfContents::LoadFileImpl(
    const void*                 resBuf,
    const ObjectConstructor&    objectConstructor
)
{
    const res::BinaryFileHeader *const pFileHead = static_cast<const res::BinaryFileHeader*>(resBuf);

    if (! detail::TestFileHeader(*pFileHead, res::FILESIGNATURE_NTMC))
    {
        NTMV_WARNING(false, "not manual TOC file.");
        return false;
    }

    if (! detail::TestFileVersion(*pFileHead))
    {
        return false;
    }

    const void* dataPtr = static_cast<const u8*>(resBuf) + pFileHead->headerSize;
    const res::NameBlock* pNameBlock = 0;
    const res::TextBlock* pTextBlock = 0;

    for (int i = 0; i < pFileHead->dataBlocks; ++i)
    {
        const res::DataBlockHeader* pDataBlockHead = static_cast<const res::DataBlockHeader*>(dataPtr);
        switch (detail::GetSignatureInt(pDataBlockHead->kind))
        {
        case res::DATABLOCKKIND_NAMEPOOL:
            pNameBlock = static_cast<const res::NameBlock*>(dataPtr);
            break;

        case res::DATABLOCKKIND_TEXTPOOL:
            pTextBlock = static_cast<const res::TextBlock*>(dataPtr);
            break;

        case res::DATABLOCKKIND_MANUALTOC:
            {
                const res::ManualTableOfContents* pResManToc = static_cast<const res::ManualTableOfContents*>(dataPtr);
                // OS_Printf("manual header num %d\n", pResManToc->headerNum);
                mHeaderNum = pResManToc->headerNum;
                mHeaders = objectConstructor.NewArray<ManualHeader>(mHeaderNum);
                NNS_NULL_ASSERT(mHeaders);

                for (int i = 0; i < mHeaderNum; ++i)
                {
                    mHeaders[i].Init(&pResManToc->headers[i], pNameBlock, pTextBlock, objectConstructor);
                }
            }
            break;
        }

        dataPtr = static_cast<const u8*>(dataPtr) + pDataBlockHead->size;    // Move to the next block position
    }

    return true;
}

}   // namespace m2d
}   // namespace ntmv
