/*--------------------------------------------------------------------------
  Project:  Manual 2D Library - m2d
  File:     m2d_scrollButton.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: 1758 $
 *-------------------------------------------------------------------------*/

#include <ntmv/m2d/inlines.h>
#include <ntmv/m2d/graphicDefines.h>
#include <ntmv/m2d/Rect.h>
#include <ntmv/m2d/objectConstructor.h>
#include <ntmv/m2d/objButton.h>
#include <ntmv/m2d/scrollButton.h>
#include <ntmv/m2d/touchPanelData.h>
#include <ntmv/m2d/nlv_skin_NANR_LBLDEFS.h>

namespace ntmv
{
namespace m2d
{

namespace
{

const s16   BUTTON_WIDTH    = 51;

const s16   BUTTON_HEIGHT   = 20;

const s16   WHOLE_WIDTH     = BUTTON_WIDTH + BUTTON_WIDTH - 1;

const s16   MOVE_SPEEDY     = 2;

// Text offset for the header page button
struct ButtonData
{
    s16             posX;
    u16             cell;
};

const ButtonData sButtonDataAry[ScrollButton::UI_MAX] =
{
    {  25, NANR_nlv_skin_scroll_down_button, },
    { -25, NANR_nlv_skin_scroll_up_button,   },
};

/*---------------------------------------------------------------------------*
  Name:         GetPointedButtonIdx

  Description:  Determines if a UI element has been pressed and, if so, gets its index.
                

  Arguments:    uiElementPtrs:  Array of pointers to UI elements.
                elementNum:     Number of UI elements.
                point:          Position to check.

  Returns:      If a UI element has been pressed, returns its index.
                If one has not been pressed, returns -1.
 *---------------------------------------------------------------------------*/
s16
GetPointedButtonIdx(
    UIElement*  uiElementPtrs[],
    u16         elementNum,
    Point       point
)
{
    // Hit detection for the button
    for (s16 i = 0; i < elementNum; ++i)
    {
        if (uiElementPtrs[i]->Contains(point))
        {
            return i;
        }
    }

    return -1;  // Button has not been pressed.
}

}   // namespace

/*---------------------------------------------------------------------------*
  Name:         ScrollButton::ScrollButton

  Description:  Constructor.

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
ScrollButton::ScrollButton()
:   mPointedUIIdx(-1),
    mContentHeight(0),
    mViewHeight(0),
    mViewY(0)
{}

/*---------------------------------------------------------------------------*
  Name:         ScrollButton::Init

  Description:  Performs initialization.

  Arguments:    objectConstructor: A reference to an ObjectConstructor object.
                pObjManager:       A pointer to an ObjManager object.
                position:          Display position (center).
                viewHeight:        Height of the display area.

  Returns:      None.
 *---------------------------------------------------------------------------*/
void
ScrollButton::Init(
    const ObjectConstructor&    objectConstructor,
    ObjManager*                 pObjManager,
    Point                       position,
    s16                         viewHeight
)
{
    UIElement* elements[UI_MAX];
    for (int i = 0; i < UI_MAX; ++i)
    {
        ObjButton* pButton = objectConstructor.NewObj<ObjButton>();
        NNS_NULL_ASSERT(pButton);
        pButton->Init(
            Point(sButtonDataAry[i].posX, 0),
            Size(BUTTON_WIDTH, BUTTON_HEIGHT),
            pObjManager->CreateCellAnim(sButtonDataAry[i].cell));
        elements[i] = pButton;
    }

    Base::Init(
        objectConstructor,
        elements,
        UI_MAX,
        position,
        Size(WHOLE_WIDTH, BUTTON_HEIGHT));

    mViewHeight = viewHeight;
}

/*---------------------------------------------------------------------------*
  Name:         ScrollButton::TestTouchPanel

  Description:  Checks Touch Panel content and updates its state.

  Arguments:    pResult:  Pointer to a structure to store processing results.
                tpData:   Touch Panel data.

  Returns:      Returns TRUE if the Touch Panel was processed.
 *---------------------------------------------------------------------------*/
bool
ScrollButton::TestTouchPanel(
    ScrollButtonResult*     pResult,
    const TouchPanelData&   tpData
)
{
    bool bHandled = false;
    if (! IsVisible())
    {
        return bHandled;
    }

    pResult->eventType = SCROLLBUTTON_EVENTTYPE_NONE;

    if (tpData.bTouchOn)
    {
        if (tpData.bTouchOnTrigger)
        {
            const s16 hitBtn = GetPointedButtonIdx(mElements, mElementNum, tpData.point);
            if (hitBtn != -1)
            {
                bHandled = true;

                if (mElements[hitBtn]->IsEnabled())
                {
                    mPointedUIIdx = hitBtn; // Record the button that was pointed at
                }
            }
        }

        if (mPointedUIIdx != -1)
        {
            bHandled = true;

            if (mElements[mPointedUIIdx]->IsEnabled())    // When the button is enabled
            {
                // Is the button that was originally pressed currently being pointed at?
                mElements[mPointedUIIdx]->CheckHit(tpData.point);

                if (mElements[mPointedUIIdx]->IsPointed())
                {
                    pResult->eventType   = SCROLLBUTTON_EVENTTYPE_SCROLL;
                    pResult->bScrollUp   = mPointedUIIdx == BUTTON_UP;
                    pResult->bScrollDown = mPointedUIIdx == BUTTON_DOWN;
                }
            }
        }
    }
    else if (tpData.bTouchOffTrigger)
    {
        if (mPointedUIIdx != -1)
        {
            static_cast<ObjButton*>(mElements[mPointedUIIdx])->SetPointed(false); // clear the selection state

            mPointedUIIdx = -1; // clear the selection state
            bHandled = true;
        }
    }

    return bHandled;
}

/*---------------------------------------------------------------------------*
  Name:         ScrollButton::SetButtonState

  Description:  Sets the button state.

  Arguments:    bUpPointed:   TRUE when pointing at the Up button.
                bDownPointed: TRUE when pointing at the Down button.

  Returns:      None.
 *---------------------------------------------------------------------------*/
void
ScrollButton::SetButtonState(
    bool    bUpPointed,
    bool    bDownPointed
)
{
    mElements[BUTTON_UP  ]->SetPointed(bUpPointed);
    mElements[BUTTON_DOWN]->SetPointed(bDownPointed);
}

/*---------------------------------------------------------------------------*
  Name:         ScrollButton::Update

  Description:  Updates the state.

  Arguments:    viewY:   y-coordinate of the content's display position.

  Returns:      None.
 *---------------------------------------------------------------------------*/
void
ScrollButton::Update(
    s16     viewY
)
{
    mViewY = viewY; // Set the display position (y-coordinate) for the content.

    // Enable and disable buttons.
    mElements[BUTTON_UP  ]->SetEnabled(mViewY > 0);
    mElements[BUTTON_DOWN]->SetEnabled(mViewY + mViewHeight < mContentHeight);
}

/*---------------------------------------------------------------------------*
  Name:         ScrollButton::Animate

  Description:  Updates the animation.

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
void
ScrollButton::Animate()
{
    static_cast<ObjButton*>(mElements[BUTTON_UP  ])->Animate();
    static_cast<ObjButton*>(mElements[BUTTON_DOWN])->Animate();
}

}   // namespace m2d
}   // namespace ntmv
