#include <stdlib.h>
#include <stdio.h>

#include "gettext.h"
#include "def.h"
#include "pixmap.h"
#include "sound.h"
#include "decor.h"
#include "button.h"
#include "misc.h"
#include "event.h"


CButton::CButton()
{
    m_type            = 0;
    m_bEnable         = true;
    m_bHide           = false;
    m_state           = 0;
    m_mouseState      = 0;
    m_nbMenu          = 0;
    m_nbToolTips      = 0;
    m_selMenu         = 0;
    m_bMouseDown      = false;
    m_message         = static_cast<Uint32> (-1);
}

CButton::~CButton () {}

// Crée un nouveau bouton.

bool CButton::Create (CPixmap *pPixmap, CSound *pSound,
                      POINT pos, Sint32 type,
                      Sint32 *pMenu, Sint32 nbMenu,
                      const char **pToolTips,
                      Sint32 region, Uint32 message)
{
    POINT       iconDim;
    Sint32          i, icon;

    static Sint32 ttypes[] =
    {
        DIMBUTTONX, DIMBUTTONY,     // button00.bmp
    };

    if (type < 0 || type > 0)
        return false;

    iconDim.x  = ttypes[type * 2 + 0];
    iconDim.y  = ttypes[type * 2 + 1];

    m_pPixmap         = pPixmap;
    m_pSound          = pSound;
    m_type            = type;
    m_bEnable         = true;
    m_bHide           = false;
    m_message         = message;
    m_pos             = pos;
    m_dim             = iconDim;
    m_nbMenu          = nbMenu;
    m_selMenu         = 0;
    m_state           = 0;
    m_mouseState      = 0;
    m_bMouseDown      = false;

    m_nbToolTips = 0;
    while (pToolTips[m_nbToolTips])
        ++m_nbToolTips;

    for (i = 0 ; i < nbMenu ; i++)
    {
        icon = pMenu[i];

        if (region == 1)    // palmiers ?
        {
            if (icon ==  0)
                icon = 90;  // sol normal
            if (icon ==  1)
                icon = 91;  // sol inflammable
            if (icon ==  2)
                icon = 92;  // sol inculte
            if (icon ==  7)
                icon =  9;  // plante
            if (icon ==  8)
                icon = 10;  // arbre
        }

        if (region == 2)    // hiver ?
        {
            if (icon ==  0)
                icon = 96;  // sol normal
            if (icon ==  1)
                icon = 97;  // sol inflammable
            if (icon ==  2)
                icon = 98;  // sol inculte
            if (icon ==  8)
                icon = 99;  // arbre
        }

        if (region == 3)    // sapin ?
        {
            if (icon ==  0)
                icon = 102;  // sol normal
            if (icon ==  1)
                icon = 103;  // sol inflammable
            if (icon ==  2)
                icon = 104;  // sol inculte
            if (icon ==  8)
                icon = 105;  // arbre
        }

        m_iconMenu[i] = icon;
    }

    m_toolTips = pToolTips;

    return true;
}

// Dessine un bouton dans son état.

void CButton::Draw ()
{
    Sint32          i;
    POINT       pos;
    RECT        rect;

    if (m_bHide)    // bouton caché ?
    {
        rect.left   = m_pos.x;
        rect.right  = m_pos.x + m_dim.x;
        rect.top    = m_pos.y;
        rect.bottom = m_pos.y + m_dim.y;
        m_pPixmap->DrawPart (-1, CHBACK, m_pos, rect, 1); // dessine le fond
        return;
    }

    if (m_bEnable)    // bouton actif ?
        m_pPixmap->DrawIcon (-1, CHBUTTON + m_type, m_mouseState, m_pos);
    else
        m_pPixmap->DrawIcon (-1, CHBUTTON + m_type, 4, m_pos);

    if (m_nbMenu == 0)
        return;

    pos = m_pos;
    if (m_nbMenu > 0)
    {
        m_pPixmap->DrawIcon (-1, CHBUTTON + m_type,
                             m_iconMenu[m_selMenu] + 6, pos);
    }

    if (m_nbMenu == 1 || !m_bEnable || !m_bMouseDown)
        return;

    pos = m_pos;
    pos.x += m_dim.x + 2;
    for (i = 0 ; i < m_nbMenu ; i++)
    {
        m_pPixmap->DrawIcon (-1, CHBUTTON + m_type, i == m_selMenu ? 1 : 0, pos);
        m_pPixmap->DrawIcon (-1, CHBUTTON + m_type, m_iconMenu[i] + 6, pos);
        pos.x += m_dim.x - 1;
    }
}

Sint32 CButton::GetState ()
{
    return m_state;
}

void CButton::SetState (Sint32 state)
{
    m_state      = state;
    m_mouseState = state;
}

Sint32 CButton::GetMenu ()
{
    return m_selMenu;
}

void CButton::SetMenu (Sint32 menu)
{
    m_selMenu = menu;
}


bool CButton::GetEnable ()
{
    return m_bEnable;
}

void CButton::SetEnable (bool bEnable)
{
    m_bEnable = bEnable;
}

bool CButton::GetHide ()
{
    return m_bHide;
}

void CButton::SetHide (bool bHide)
{
    m_bHide = bHide;
}

// Traitement d'un événement.

bool CButton::TreatEvent (const SDL_Event &event)
{
    POINT       pos;

    if (m_bHide || !m_bEnable)
        return false;

    //pos = ConvLongToPos(lParam);

    switch (event.type)
    {
    case SDL_MOUSEBUTTONDOWN:
        if (event.button.button != SDL_BUTTON_LEFT
            && event.button.button != SDL_BUTTON_RIGHT)
            break;

        pos.x = event.button.x;
        pos.y = event.button.y;
        if (MouseDown (pos))
            return true;
        break;

    case SDL_MOUSEMOTION:
        pos.x = event.motion.x;
        pos.y = event.motion.y;
        if (MouseMove (pos))
            return true;
        break;

    case SDL_MOUSEBUTTONUP:
        if (event.button.button != SDL_BUTTON_LEFT
            && event.button.button != SDL_BUTTON_RIGHT)
            break;

        pos.x = event.button.x;
        pos.y = event.button.y;
        if (MouseUp (pos))
            return false;  // (*)
        break;
    }

    return false;
}

// (*) Tous les boutons doivent recevoir l'événement BUTTONUP !

// Indique si la souris est sur ce bouton.

bool CButton::MouseOnButton (POINT pos)
{
    return Detect (pos);
}

// Retourne le tooltips pour un bouton, en fonction
// de la position de la souris.

const char *CButton::GetToolTips (POINT pos)
{
    Sint32      width = m_dim.x;
    Sint32      rank;

    if (m_bHide || !m_bEnable)
        return nullptr;

    if (m_nbMenu > 1 && m_bMouseDown)    // sous-menu déroulé ?
        width += 2 + (m_dim.x - 1) * m_nbMenu;

    if (pos.x < m_pos.x
        || pos.x > m_pos.x + width
        || pos.y < m_pos.y
        || pos.y > m_pos.y + m_dim.y)
        return nullptr;

    rank = (pos.x - (m_pos.x + 2 + 1)) / (m_dim.x - 1);
    if (rank < 0)
        rank = 0;
    if (rank > m_nbToolTips)
        return nullptr;

    if (m_nbMenu > 1)
    {
        if (m_bMouseDown && rank > 0)
            rank --;
        else
            rank = m_selMenu;
    }

    return gettext (m_toolTips[rank]);
}

// Détecte si la souris est dans le bouton.

bool CButton::Detect (POINT pos)
{
    Sint32      width = m_dim.x;

    if (m_bHide || !m_bEnable)
        return false;

    if (m_nbMenu > 1 && m_bMouseDown)    // sous-menu déroulé ?
        width += 2 + (m_dim.x - 1) * m_nbMenu;

    if (pos.x < m_pos.x         ||
        pos.x > m_pos.x + width   ||
        pos.y < m_pos.y         ||
        pos.y > m_pos.y + m_dim.y)
        return false;

    return true;
}

// Bouton de la souris pressé.

bool CButton::MouseDown (POINT pos)
{
    if (!Detect (pos))
        return false;

    m_mouseState = 1;
    m_bMouseDown = true;

    CEvent::PushUserEvent (WM_UPDATE);

    m_pSound->PlayImage (SOUND_CLICK, pos);
    return true;
}

// Souris déplacés.

bool CButton::MouseMove (POINT pos)
{
    bool    bDetect;
    Sint32      iState, iMenu;

    iState = m_mouseState;
    iMenu  = m_selMenu;

    bDetect = Detect (pos);

    if (m_bMouseDown)
    {
        if (bDetect)
            m_mouseState = 1;  // pressé
        else
            m_mouseState = m_state;
    }
    else
    {
        if (bDetect)
            m_mouseState = m_state + 2; // survollé
        else
            m_mouseState = m_state;
    }

    if (m_nbMenu > 1 &&
        m_bMouseDown &&
        pos.x > m_pos.x + m_dim.x + 2) // dans sous-menu ?
    {
        m_selMenu = (pos.x - (m_pos.x + m_dim.x + 2)) / (m_dim.x - 1);
        if (m_selMenu >= m_nbMenu)
            m_selMenu = m_nbMenu - 1;
    }

    if (iState != m_mouseState ||
        iMenu  != m_selMenu)
        CEvent::PushUserEvent (WM_UPDATE);

    return m_bMouseDown;
}

// Bouton de la souris relâché.

bool CButton::MouseUp (POINT pos)
{
    bool    bDetect;

    bDetect = Detect (pos);

    m_mouseState = m_state;
    m_bMouseDown = false;

    if (!bDetect)
        return false;

    if (m_message != static_cast<Uint32> (-1))
        CEvent::PushUserEvent (m_message);

    return true;
}