/*--------------------------------------------------------------------------
  Project:  Manual 2D Library - m2d
  File:     types.h

  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: 1.47 $
 *-------------------------------------------------------------------------*/

#ifndef NTMV_M2D_TYPES_H_
#define NTMV_M2D_TYPES_H_

#if _MSC_VER > 1000 || defined(__CWCC__)
#pragma once
#endif

#include <nitro/types.h>
#include <nnsys/misc.h>
#include <cstddef>

namespace ntmv
{
namespace m2d
{

namespace detail
{

/* ------------------------------------------------------------------------
        Tag character
   ------------------------------------------------------------------------ */

const u8        TAGCHAR_IMG     =   0x01;   // <img>

const u8        TAGCHAR_COLOR   =   0x02;   // <color>

const u8        TAGCHAR_HSPACER =   0x03;   // Space in the horizontal direction

/* ------------------------------------------------------------------------
        Size-related
   ------------------------------------------------------------------------ */

const int       HEADER_TEXT_DRAW_WIDTH      = 156;   // Rendering width (in pixels) of the header text
const int       CHAPTER_TEXT_DRAW_WIDTH     = 180;   // Rendering width (in pixels) of the section text

const int       PAGEITEM_TEXT_HSPACE        = 0;    // Character spacing (in pixels) for header and section text

const int       CHAPTER_ITEM_DISP_MAX       = 7;    // Maximum number of sections that are displayed at once


/* ------------------------------------------------------------------------
        Alignment value
   ------------------------------------------------------------------------ */

const int       UI_RES_ALIGN    = 32;


template <typename T>
inline
void
SetBit(
    T*      pBits,
    int     pos,
    bool    val
)
{
    const T mask = T(~(1 << pos));

    *pBits &= mask;
    *pBits |= (val ? 1: 0) << pos;
}

template <typename T>
inline
bool
TestBit(
    T       bits,
    int     pos
)
{
    const T mask = T(1 << pos);

    return 0 != (bits & mask);
}

template <typename T>
inline
void
SetBits(
    T*      pBits,
    int     pos,
    int     len,
    T       val
)
{
    NNS_ASSERT(len <= 32);
    const u32 MaxValue = 0xFFFFFFFFU >> (32 - len);
    NNS_ASSERT(val <= MaxValue);

    const T mask = T(~(MaxValue << pos));

    *pBits &= mask;
    *pBits |= val << pos;
}

template <typename T>
inline
T
GetBits(
    T       bits,
    int     pos,
    int     len
)
{
    NNS_ASSERT(len <= 32);
    const u32 mask = ~(0xFFFFFFFFU << len);

    return T((bits >> pos) & mask);
}

template<typename T>
inline
const T*
ConvertOffsToPtr(const void* baseAddress, unsigned int offset)
{
    return
        reinterpret_cast<const T*>(
            static_cast<const u8*>(baseAddress) + offset
        );
}

template<typename T>
inline
T*
ConvertOffsToPtr(void* baseAddress, unsigned int offset)
{
    return
        reinterpret_cast<T*>(
            static_cast<u8*>(baseAddress) + offset
        );
}

#if defined(SWAP_ENDIAN)

    inline
    u16
    SwapInt(u16 val)
    {
        return u16((val << 8) | (val >> 8));
    }

    inline
    s16
    SwapInt(s16 val)
    {
        const u16 ret= SwapInt(*reinterpret_cast<const u16*>(&val));
        return *reinterpret_cast<const s16*>(&ret);
    }

    inline
    u32
    SwapInt(u32 val)
    {
        return (val << 24) | ((val << 8) & 0x00FF0000) | ((val >> 8) & 0x0000FF00) | (val >> 24);
    }

    inline
    s32
    SwapInt(s32 val)
    {
        const u32 ret= SwapInt(*reinterpret_cast<const u32*>(&val));
        return *reinterpret_cast<const s32*>(&ret);
    }

    template<typename T>
    class ResNum
    {
    public:
                ResNum() {}                                                             // The default constructor.

                ResNum(const ResNum& other) : bits(other.bits) {}                       // Copy constructor

                ResNum(const T val)         : bits(detail::SwapInt(val)) {}             // Construct from T

        void    operator = (const ResNum& other)    { bits = other.bits; }              // Assignment operator

                operator T () const                 { return detail::SwapInt(bits); }   // Conversion operator to T

        void    operator = (T val)                  { bits = detail::SwapInt(val);  }   // Set from T

    private:
        T       bits;
    };

    typedef ResNum<s16> ResS16;
    typedef ResNum<u16> ResU16;
    typedef ResNum<s32> ResS32;
    typedef ResNum<u32> ResU32;

#else   // #if defined(SWAP_ENDIAN)

    typedef s16         ResS16;
    typedef u16         ResU16;
    typedef s32         ResS32;
    typedef u32         ResU32;

#endif  // #if defined(SWAP_ENDIAN)

}   // namespace detail

struct Point
{
                        Point()
                            : x(0), y(0)
                        {}
                        Point(s16 aX, s16 aY)
                            : x(aX), y(aY)
                        {}
                        Point(const Point& other)
                            : x(other.x), y(other.y)
                        {}

    void                Set(s16 aX, s16 aY)     { x = aX; y = aY; }

    void                Move(s16 dx, s16 dy)
    {
        x += dx;
        y += dy;
    }

    void                Move(Point dPt) { Move(dPt.x, dPt.y); }

    s16                 operator [] (int idx) const { return (&x)[idx]; }
    s16&                operator [] (int idx)       { return (&x)[idx]; }

    detail::ResS16      x;
    detail::ResS16      y;
};

inline Point
operator + (const Point& a, const Point& b)
{
    return Point(static_cast<s16>(a.x + b.x), static_cast<s16>(a.y + b.y));
}

inline Point
operator - (const Point& a, const Point& b)
{
    return Point(static_cast<s16>(a.x - b.x), static_cast<s16>(a.y - b.y));
}

struct Size
{
                        Size()
                            : width(0), height(0)
                        {}
                        Size(s16 aWidth, s16 aHeight)
                            : width(aWidth), height(aHeight)
                        {}
                        Size(const Size& other)
                            : width(other.width), height(other.height)
                        {}

    void                Set(s16 aWidth, s16 aHeight)    { width = aWidth; height = aHeight; }

    s16                 operator [] (int idx) const { return (&width)[idx]; }
    s16&                operator [] (int idx)       { return (&width)[idx]; }

    detail::ResS16      width;
    detail::ResS16      height;
};

inline bool
operator == (const Size& a, const Size& b)
{
    return a.width == b.width && a.height == b.height;
}

struct VRegion
{
                        VRegion()
                            : top(0), bottom(0)
                        {}

                        VRegion(s16 aTop, s16 aBottom)
                            : top(aTop), bottom(aBottom)
                        {}

                        VRegion(const VRegion& other)
                            : top(other.top), bottom(other.bottom)
                        {}

    void                Set(s16 aTop, s16 aBottom)      { top = aTop; bottom = aBottom; }

    s16                 GetHeight() const   { return static_cast<s16>(bottom - top); }

    detail::ResS16      top;
    detail::ResS16      bottom;
};


/*
    Margin
*/
struct Margin
{
    detail::ResS16      l;
    detail::ResS16      r;
    detail::ResS16      t;
    detail::ResS16      b;
};

struct ImageHeader
{
    detail::ResU16      width;
    detail::ResU16      height;

    u8                  texelFormat;
    u8                  bHasAlphaPal;
    detail::ResU16      paletteEntryNum;

    u8                  padding[8];
};

/*
    Structure to save rendering information for a single line of text
*/
struct TextLine
{
                        TextLine()
                        :   charStartY(0),
                            bytes(0)
                        {}

    void                Set(
                            Size    Asize,
                            s16     AcharStartY,
                            u16     Abytes
                        )
    {
        size       = Asize;
        charStartY = AcharStartY;
        bytes      = Abytes;
    }

    Size                size;           // Size of the text rectangle
    detail::ResS16      charStartY;     // Offset from the top of the text rectangle to the starting y position for rendering characters
                                        // 
    detail::ResU16      bytes;          // Number of bytes of text to process for this TextLine
};

struct ImageTagData
{
    detail::ResU16      size;           // Size of this structure
    detail::ResU16      texIdx;         // Texture index (+1)
};

struct ColorTagData
{
    detail::ResU16      size;           // Size of this structure
    detail::ResU16      color;          // Text color (direct color)
};

struct SpacerTagData
{
    detail::ResU16      size;           // Size of this structure
    detail::ResU16      value;          // Space value
};

enum
{
    DISPTYPE_UP,
    DISPTYPE_DOWN,

    DISPTYPE_MAX
};

enum
{
    TEXTUREFLIP_NONE,
    TEXTUREFLIP_FLIPH,
    TEXTUREFLIP_FLIPV,
    TEXTUREFLIP_ROTATE90,
    TEXTUREFLIP_ROTATE180,
    TEXTUREFLIP_ROTATE270,

    TEXTUREFLIP_MAX
};

/*
    Horizontal base position
*/
enum
{
    HORIZONTALPOSITION_LEFT,
    HORIZONTALPOSITION_CENTER,
    HORIZONTALPOSITION_RIGHT,

    HORIZONTALPOSITION_MAX
};

/*
    Vertical base position
*/
enum
{
    VERTICALPOSITION_TOP,
    VERTICALPOSITION_CENTER,
    VERTICALPOSITION_BOTTOM,

    VERTICALPOSITION_MAX
};

/*
    Text placement
*/
enum
{
    TEXTALIGNMENT_SYNCHRONOUS,
    TEXTALIGNMENT_LEFT,
    TEXTALIGNMENT_CENTER,
    TEXTALIGNMENT_RIGHT,

    TEXTALIGNMENT_MAX
};

enum
{
    WINDOWFRAME_LT,
    WINDOWFRAME_RT,
    WINDOWFRAME_LB,
    WINDOWFRAME_RB,
    WINDOWFRAME_L,
    WINDOWFRAME_R,
    WINDOWFRAME_T,
    WINDOWFRAME_B,

    WINDOWFRAME_MAX
};

/*
    Font size
*/
enum
{
    FONTSIZE_16,
    FONTSIZE_12,
    FONTSIZE_10,

    FONTSIZE_MAX
};

/*
    Button state
*/
enum
{
    BUTTONSTATE_NORMAL,         // No activity
    BUTTONSTATE_POINTED,        // Pointed at
    BUTTONSTATE_DISABLED,       // Disabled
    BUTTONSTATE_CHECKED,        // Selected

    BUTTONSTATE_MAX
};

/*
    Language type
*/
enum
{
    LANGKIND_JAPANESE,
    LANGKIND_ENGLISH,
    LANGKIND_FRENCH,
    LANGKIND_SPANISH,
    LANGKIND_GERMAN,
    LANGKIND_ITALIAN,
    LANGKIND_DUTCH,

    LANGKIND_MAX
};

}   // namespace m2d
}   // namespace ntmv

/* NTMV_M2D_TYPES_H_ */
#endif
