#include "PrecompApp.h"
#include "Tweakables.h"
#include "gtVector2.h"
#include "DebugVp.h"
#include "Framework.h"
#include "gtInputDeviceTypes.h"
#include "Console.h"
#include "gtInputDeviceManager.h"


Tweakables::Tweakables()
{
  m_currentTweakable = 0;
}


Tweakables::~Tweakables()
{
  m_tweakables.DeleteAll();
}


void Tweakables::Add(Tweakable* a_tweakable)
{
  m_tweakables.Add(a_tweakable);
}


Tweakable* Tweakables::FindByName(const char* a_tweakableName)
{
  int itemCount = m_tweakables.GetSize();
  for (int i = 0; i < itemCount; i++)
  {
    if ( strcmp(m_tweakables[i]->GetName(), a_tweakableName) == 0 )
    {
      return m_tweakables[i];
    }
  }
  return 0;
}


// width must be multiple of 32
static void DrawSimpleBitmap(float x, float y, const uint32_t* bitmap, int w, int h, gtColor col)
{
  for ( int i = 0; i < w; i++ )
    for ( int j = 0; j < h; j++ )
    {
      int bits = bitmap[j*(w/32)+i/32];
      int bit = bits & (1 << (i%32));
      if ( bit )
        DebugVp::Get()->PlotRect2D(gtVector2(x + i, y + j),gtVector2(x + i + 1, y + j + 1), col);
    }
}


static void DrawButton(float x, float y, float w, float h, float border, float level)
{
  DebugVp::Get()->PlotLine2D(gtVector2(x, y - 2.f),gtVector2(x + w, y - 2.f), gtColor::s_colorWhite);

  for ( int i = 0; i < int(h); i++ )
  {
    int col = int(128+6*16-(float(i*12.f)/h)*16.f);
    DebugVp::Get()->PlotLine2D(gtVector2(x, y - 1.f + i),gtVector2(x + w, y - 1.f + i), gtColor(col, col, col, int(128+64*level) ) );
  }

  DebugVp::Get()->PlotLine2D(gtVector2(x, y + h - 3.f),gtVector2(x + w, y + h - 3.f),gtColor::s_colorWhite);

  DebugVp::Get()->PlotLine2D(gtVector2(x - 1, y - 1.f),gtVector2(x - 1, y + h - 3.f), gtColor::s_colorWhite);
  DebugVp::Get()->PlotLine2D(gtVector2(x + w, y - 1.f),gtVector2(x + w, y + h - 3.f), gtColor::s_colorWhite);

  DebugVp::Get()->PlotLine2D(gtVector2(x, y + h - 2.f),gtVector2(x + w, y + h - 2.f),gtColor::s_colorBlack);
  DebugVp::Get()->PlotLine2D(gtVector2(x + w + 1, y),gtVector2(x + w + 1, y + h - 3.f), gtColor::s_colorBlack);
}


void Tweakables::Print(float x, float y, float w, float h)
{
  const float itemHeight = 17.f;
  unsigned maxItemCount =  unsigned(h / itemHeight);
  unsigned itemCount = m_tweakables.GetSize();
  unsigned viewableItemCount = ( itemCount > maxItemCount ) ? maxItemCount : itemCount;
  unsigned middleOffset = viewableItemCount / 2;
  unsigned viewItemOffset = 0;
  bool upIndicatorOn = false;
  bool downIndicatorOn = false;

  h = viewableItemCount * itemHeight;
  
  if ( (itemCount > maxItemCount) && (m_currentTweakable > middleOffset) )
  {
    if ( m_currentTweakable >= (itemCount - middleOffset) )
    {
      viewItemOffset = itemCount - viewableItemCount;
    }
    else
    {
      viewItemOffset = (m_currentTweakable - middleOffset);
    }
  }

  if ( (viewItemOffset + maxItemCount) < itemCount )
  {
    downIndicatorOn = true;
  }
  if ( viewItemOffset )
    upIndicatorOn = true;

  float nameWidth = 200.f;

  DrawButton(x-1.f, y-1.f - 17.f, w+3.f, h + 1.f + 33.f, 0.f, 0.3f);
  
  for (unsigned currentElement = viewItemOffset; currentElement < (viewItemOffset+viewableItemCount); ++currentElement)
  {
    const char* val = m_tweakables[currentElement]->GetValue();
    const char* name = m_tweakables[currentElement]->GetName();
    if (currentElement == m_currentTweakable)
    {
      DrawButton(x, y, w, itemHeight - 1.f, 0.f, 1.0f);
      DebugVp::Get()->Printf(gtColor(250, 250, 250, 250), x + 7.f, y+2.f, "%s :", name);
      DebugVp::Get()->Printf(gtColor(250, 250, 250, 250), x + 7.f + nameWidth, y+2.f, "%s",val);
    }
    else
    {
      DebugVp::Get()->Printf(gtColor(215, 250, 250, 200), x + 8.f, y+3.f, "%s :", name);
      DebugVp::Get()->Printf(gtColor(215, 250, 250, 200), x + 8.f + nameWidth, y+3.f, "%s",val);
    }
    delete[] val;
    y += itemHeight;
  }

  const uint32_t upBitmap[] =
  {
    0x00000000,
    0x00018000,
    0x0003c000,
    0x0007e000,
    0x000ff000,
    0x001ff800,
    0x003ffc00,
    0x007ffe00,
    0x00ffff00,
    0x01ffff80,
    0x03ffffc0,
    0x00000000,
  };

  const uint32_t downBitmap[] =
  {
    0x00000000,
    0x03ffffc0,
    0x01ffff80,
    0x00ffff00,
    0x007ffe00,
    0x003ffc00,
    0x001ff800,
    0x000ff000,
    0x0007e000,
    0x0003c000,
    0x00018000,
    0x00000000,
  };

  DrawSimpleBitmap(x + w / 2.f - 3.f, y-h-16.f, upBitmap, 32, 12, ( upIndicatorOn )   ? gtColor::s_colorWhite : gtColor(32,32,32,128) );
  DrawSimpleBitmap(x + w / 2.f - 3.f,  y-1.f, downBitmap, 32, 12, ( downIndicatorOn ) ? gtColor::s_colorWhite : gtColor(32,32,32,128) );
}


void Tweakables::UpdateInput()
{
  if (!(Console::Get() && Console::Get()->IsActive()))
  {
    for (int currentElement = 0; currentElement < m_tweakables.GetSize(); ++currentElement)
    {
      if (currentElement == m_currentTweakable)
      {
        if ( m_tweakables[currentElement]->AutoRepeat() )
        {
          if (Framework::GetInput()->GetButtonDown(GT_INPUT_DEVICE_KEYBOARD, GT_KEY_RIGHT))
            m_tweakables[currentElement]->Increment();

          if (Framework::GetInput()->GetButtonDown(GT_INPUT_DEVICE_KEYBOARD, GT_KEY_LEFT))
            m_tweakables[currentElement]->Decrement();
        }
        else
        {
          if (Framework::GetInput()->GetButtonPressed(GT_INPUT_DEVICE_KEYBOARD, GT_KEY_RIGHT))
            m_tweakables[currentElement]->Increment();

          if (Framework::GetInput()->GetButtonPressed(GT_INPUT_DEVICE_KEYBOARD, GT_KEY_LEFT))
            m_tweakables[currentElement]->Decrement();
        }

        if (Framework::GetInput()->GetButtonPressed(GT_INPUT_DEVICE_KEYBOARD, GT_KEY_RETURN))
          m_tweakables[currentElement]->Select();
      }
    }

    if (Framework::GetInput()->GetButtonPressed(GT_INPUT_DEVICE_KEYBOARD, GT_KEY_UP) && m_currentTweakable > 0)
      m_currentTweakable--;

    if (Framework::GetInput()->GetButtonPressed(GT_INPUT_DEVICE_KEYBOARD, GT_KEY_DOWN) && m_currentTweakable < uint32_t(m_tweakables.GetSize()-1))
      m_currentTweakable++;
  }
}
