#include <IO/FileStream.h>

#include <Controls/Xtreme/GUIScreen.h>
#include <Controls/Xtreme/GUIEdit.h>
#include <Controls/Xtreme/GUIButton.h>

#include "GSEdit.h"
#include "BirdiesRevenge.h"
#include "Birdie.h"



IMPLEMENT_CLONEABLE( CGSEdit, "GSEdit" )



void CGSEdit::Init()
{
  m_EditMode = EM_TILES;

  m_pSelectedUnit = NULL;

  m_dwCurLevel = 1;

  m_curFeld = Birdie2::FT_WALL;
  m_curUnit = Birdie2::UT_BIRDIE;

  m_Level.Load( GR::IO::FileStream( theApp.AppPath( Misc::Format( "data/level%1%.dat" ) << m_dwCurLevel ).c_str() ) );

  /*
  m_pScreen = new GUIScreen( 0, 0, 800, 600 );
  m_pStateScreen->Add( m_pScreen ); 

  m_pEditWidth = new GUIEdit( 0, 0, 60, 20 );
  m_pScreen->Add( m_pEditWidth );

  m_pEditHeight = new GUIEdit( 60, 0, 60, 20 );
  m_pScreen->Add( m_pEditHeight );

  GUIButton* pButton = new GUIButton( 0, 20, 60, 20, "Apply" );
  pButton->AddHandler( OET_BUTTON_PUSHED, fastdelegate::MakeDelegate( this, &CGSEdit::OnApplySize ) );
  m_pScreen->Add( pButton );

  m_pEditWidth->SetCaption( Misc::Format() << m_Level.m_Field.Width() );
  m_pEditHeight->SetCaption( Misc::Format() << m_Level.m_Field.Height() );*/
}



void CGSEdit::Exit()
{
}



void CGSEdit::Display( XRenderer& Renderer )
{
  m_Level.Display( Renderer );

  GR::tPoint      ptOffset( (int)m_Level.m_Offset.x, (int)m_Level.m_Offset.y );

  if ( m_pSelectedUnit )
  {
    GR::tRect   rcBounds( m_pSelectedUnit->MovementBounds() );

    rcBounds.offset( -ptOffset );
    Renderer.RenderRect2d( rcBounds.position(), rcBounds.size(), 0xff00ff00 );
  }

  switch ( m_EditMode )
  {
    case EM_MONSTER:
      {
        Unit*    pTempUnit = Unit::FromType( m_curUnit );
        if ( pTempUnit )
        {
          pTempUnit->m_Position = theApp.InputClass()->MousePos() + ptOffset;

          pTempUnit->m_Position -= pTempUnit->m_Position % 20;

          pTempUnit->Display( ptOffset, Renderer );

          delete pTempUnit;
        }
      }
      break;
    case EM_TILES:
      Renderer.RenderTextureSection2d( theApp.InputClass()->MouseX() - 10, theApp.InputClass()->MouseY() - 10, 
                                       theApp.Section( CMisc::printf( "Tile.%d", m_curFeld + 1 ) ) );
      break;
    case EM_EXTRA_POS:
      Renderer.RenderTextureSection2d( theApp.InputClass()->MouseX() - 10, theApp.InputClass()->MouseY() - 10, theApp.Section( "ExtraStart" ) );
      break;
    case EM_BUBBLE_TARGET_POS:
      Renderer.RenderTextureSection2d( theApp.InputClass()->MouseX() - 10, theApp.InputClass()->MouseY() - 10, theApp.Section( "BubbleTarget" ) );
      break;
    case EM_FLASH_START_POS:
      Renderer.RenderTextureSection2d( theApp.InputClass()->MouseX() - 10, theApp.InputClass()->MouseY() - 10, theApp.Section( "FlashStart" ) );
      break;
  }

  auto    it2( m_Level.m_ExtraStartPositions.begin() );
  while ( it2 != m_Level.m_ExtraStartPositions.end() )
  {
    Renderer.RenderTextureSection2d( it2->x, it2->y, theApp.Section( "ExtraStart" ) );

    ++it2;
  }

  auto    it3( m_Level.m_FlashStartPositions.begin() );
  while ( it3 != m_Level.m_FlashStartPositions.end() )
  {
    Renderer.RenderTextureSection2d( it3->x, it3->y, theApp.Section( "FlashStart" ) );

    ++it3;
  }

  Renderer.RenderTextureSection2d( m_Level.m_BubbleTargetPos.x, m_Level.m_BubbleTargetPos.y, theApp.Section( "BubbleTarget" ) );

  Renderer.RenderText2d( theApp.Font( "Font" ), 2, 2, ( Misc::Format( "Level: %1%" ) << m_dwCurLevel ).Result().c_str() );
}



void CGSEdit::UpdatePerDisplayFrame( const float fElapsedTime )
{
  //if ( m_pScreen->GetComponentAt( theApp.InputClass()->MousePos() ) == NULL )
  {
    GR::tPoint    ptMouse( theApp.InputClass()->MousePos() + GR::tPoint( (int)m_Level.m_Offset.x, (int)m_Level.m_Offset.y ) );

    if ( theApp.InputClass()->KeyPressed( Xtreme::MOUSE_BUTTON_1 ) )
    {
      switch ( m_EditMode )
      {
        case EM_MONSTER:
          {
            m_pSelectedUnit = NULL;

            Level::tListUnits::iterator    it( m_Level.m_Units.begin() );
            while ( it != m_Level.m_Units.end() )
            {
              Unit*    pUnit( *it );

              if ( pUnit->MovementBounds().contains( ptMouse ) )
              {
                m_pSelectedUnit = pUnit;
                break;
              }

              ++it;
            }
            if ( m_pSelectedUnit == NULL )
            {
              Unit*    pUnit = Unit::FromType( m_curUnit );
              if ( pUnit )
              {
                pUnit->m_Position = ptMouse;
                pUnit->m_Position -= pUnit->m_Position % 20;
                m_Level.m_Units.push_back( pUnit );
                m_pSelectedUnit = pUnit;
              }
            }
            else
            {
              //m_pEditWidth->SetCaption( Misc::Format( "%1x%" ) << m_pSelectedUnit->m_dwExtraData );
              //m_pEditHeight->SetCaption( Misc::Format( "%1x%" ) << m_pSelectedUnit->m_dwExtraData2 );
            }
          }
          break;
        case EM_TILES:
          m_Level.m_Field.SetField( ptMouse.x / 20, ptMouse.y / 20, m_curFeld );
          break;
        case EM_EXTRA_POS:
          if ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::MOUSE_BUTTON_1 ) )
          {
            GR::tPoint    pt( ptMouse );
            bool          foundEntry = false;

            pt -= pt % 20;


            auto it = m_Level.m_ExtraStartPositions.begin();
            while ( it != m_Level.m_ExtraStartPositions.end() )
            {
              if ( *it == pt )
              {
                foundEntry = true;
                m_Level.m_ExtraStartPositions.erase( it );
                break;
              }
              ++it;
            }
            if ( !foundEntry )
            {
              m_Level.m_ExtraStartPositions.push_back( pt );
            }
          }
          break;
        case EM_BUBBLE_TARGET_POS:
          if ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::MOUSE_BUTTON_1 ) )
          {
            GR::tPoint    pt( ptMouse );
            pt -= pt % 20;
            m_Level.m_BubbleTargetPos = pt;
          }
          break;
        case EM_FLASH_START_POS:
          if ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::MOUSE_BUTTON_1 ) )
          {
            GR::tPoint    pt( ptMouse );
            bool          foundEntry = false;

            pt -= pt % 20;


            auto it = m_Level.m_FlashStartPositions.begin();
            while ( it != m_Level.m_FlashStartPositions.end() )
            {
              if ( *it == pt )
              {
                foundEntry = true;
                m_Level.m_FlashStartPositions.erase( it );
                break;
              }
              ++it;
            }
            if ( !foundEntry )
            {
              m_Level.m_FlashStartPositions.push_back( pt );
            }
          }
          break;
      }
    }
    else if ( theApp.InputClass()->KeyPressed( Xtreme::MOUSE_BUTTON_2 ) )
    {
      m_curFeld = m_Level.m_Field.Field( ptMouse.x / 20, ptMouse.y / 20 );
    }
    if ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::KEY_1 ) )
    {
      if ( m_dwCurLevel > 1 )
      {
        m_dwCurLevel--;
        m_Level.Load( GR::IO::FileStream( theApp.AppPath( Misc::Format( "data/level%1%.dat" ) << m_dwCurLevel ).c_str() ) );

        //m_pEditWidth->SetCaption( Misc::Format() << m_Level.m_Field.Width() );
        //m_pEditHeight->SetCaption( Misc::Format() << m_Level.m_Field.Height() );
      }
    }
    if ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::KEY_2 ) )
    {
      if ( m_dwCurLevel < 999 )
      {
        m_dwCurLevel++;
        m_Level.Load( GR::IO::FileStream( theApp.AppPath( Misc::Format( "data/level%1%.dat" ) << m_dwCurLevel ).c_str() ) );

        //m_pEditWidth->SetCaption( Misc::Format() << m_Level.m_Field.Width() );
        //m_pEditHeight->SetCaption( Misc::Format() << m_Level.m_Field.Height() );
      }
    }
  }

  if ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::KEY_ESCAPE ) )
  {
    GLOBAL_QUEUE.PostEvent( "App.ChangeState", "GSMenu" );
  }


  if ( ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::KEY_NUMPAD_PLUS ) )
  ||   ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::KEY_PLUS ) ) )
  {
    if ( theApp.InputClass()->ShiftPressed() )
    {
      m_dwCurLevel++;
      m_Level.Load( GR::IO::FileStream( theApp.AppPath( Misc::Format( "data/level%1%.dat" ) << m_dwCurLevel ).c_str() ) );
    }
    else
    {
      switch ( m_EditMode )
      {
        case EM_MONSTER:
          m_curUnit = (Birdie2::eUnitTypes)( ( m_curUnit + 1 ) % Birdie2::UT_LAST_ENTRY );
          break;
        case EM_TILES:
          m_curFeld = ( Birdie2::eFeldTypes )( ( m_curFeld + 1 ) % Birdie2::FT_LAST_ENTRY );
          break;
      }
    }
  }
  if ( ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::KEY_NUMPAD_MINUS ) )
  ||   ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::KEY_MINUS ) ) )
  {
    if ( theApp.InputClass()->ShiftPressed() )
    {
      if ( m_dwCurLevel > 1 )
      {
        m_dwCurLevel--;
        m_Level.Load( GR::IO::FileStream( theApp.AppPath( Misc::Format( "data/level%1%.dat" ) << m_dwCurLevel ).c_str() ) );
      }
    }
    else
    {
      switch ( m_EditMode )
      {
        case EM_MONSTER:
          m_curUnit = ( Birdie2::eUnitTypes )( ( m_curUnit + Birdie2::UT_LAST_ENTRY - 1 ) % Birdie2::UT_LAST_ENTRY );
          break;
        case EM_TILES:
          m_curFeld = ( Birdie2::eFeldTypes )( ( m_curFeld + Birdie2::FT_LAST_ENTRY - 1 ) % Birdie2::FT_LAST_ENTRY );
          break;
      }
    }
  }
  if ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::KEY_B ) )
  {
    for ( int i = 0; i < m_Level.m_Field.Width(); ++i )
    {
      m_Level.m_Field.SetField( i, 0, m_curFeld );
      m_Level.m_Field.SetField( i, m_Level.m_Field.Height() - 1, m_curFeld );
    }
    for ( int j = 0; j < m_Level.m_Field.Height(); ++j )
    {
      m_Level.m_Field.SetField( 0, j, m_curFeld );
      m_Level.m_Field.SetField( m_Level.m_Field.Width() - 1, j, m_curFeld );
    }
  }
  if ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::KEY_F2 ) )
  {
    m_Level.Save( GR::IO::FileStream( theApp.AppPath( Misc::Format( "data/level%1%.dat" ) << m_dwCurLevel ).c_str(), IIOStream::OT_WRITE_ONLY ) );
  }
  if ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::KEY_M ) )
  {
    m_EditMode = (EditMode)( ( m_EditMode + 1 ) % EM_LAST_ENTRY );
  }
  if ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::KEY_NUMPAD_KOMMA ) )
  {
    if ( m_pSelectedUnit )
    {
      m_Level.m_Units.remove( m_pSelectedUnit );
      delete m_pSelectedUnit;
      m_pSelectedUnit = NULL;
    }
  }
  if ( theApp.InputClass()->KeyPressed( Xtreme::KEY_UP ) )
  {
    m_Level.m_Offset.y -= 320.0f * fElapsedTime;
    if ( m_Level.m_Offset.y < 0.0f )
    {
      m_Level.m_Offset.y = 0.0f;
    }
  }
  if ( theApp.InputClass()->KeyPressed( Xtreme::KEY_DOWN ) )
  {
    m_Level.m_Offset.y += 320.0f * fElapsedTime;
    if ( m_Level.m_Offset.y > m_Level.m_Field.Height() * 20.0f - 600.0f )
    {
      m_Level.m_Offset.y = m_Level.m_Field.Height() * 20.0f - 600.0f;
    }
  }
  if ( theApp.InputClass()->KeyPressed( Xtreme::KEY_LEFT ) )
  {
    m_Level.m_Offset.x -= 320.0f * fElapsedTime;
    if ( m_Level.m_Offset.x < 0.0f )
    {
      m_Level.m_Offset.x = 0.0f;
    }
  }
  if ( theApp.InputClass()->KeyPressed( Xtreme::KEY_RIGHT ) )
  {
    m_Level.m_Offset.x += 320.0f * fElapsedTime;
    if ( m_Level.m_Offset.x > m_Level.m_Field.Width() * 20.0f - 800.0f )
    {
      m_Level.m_Offset.x = m_Level.m_Field.Width() * 20.0f - 800.0f;
    }
  }
}



void CGSEdit::Update()
{

  // TODO - Update

}



bool CGSEdit::ProcessEvent( const GUI::OutputEvent& Event )
{
  switch ( Event.Type )
  {
    case OET_BUTTON_PUSHED:
      break;
  }
  return false;
}



void CGSEdit::OnApplySize( const GUI::OutputEvent& Event )
{
  /*
  if ( m_bMonsterMode )
  {
    if ( m_pSelectedUnit )
    {
      m_pSelectedUnit->m_dwExtraData = GR::Convert::ToU32( m_pEditWidth->GetCaption(), 16 );
      m_pSelectedUnit->m_dwExtraData2 = GR::Convert::ToU32( m_pEditHeight->GetCaption(), 16 );
      m_pSelectedUnit->OnLoad( m_Level );
    }
  }
  else
  {
    GR::u32     dwWidth = GR::Convert::ToU32( m_pEditWidth->GetCaption() );
    GR::u32     dwHeight = GR::Convert::ToU32( m_pEditHeight->GetCaption() );

    if ( dwWidth < 40 )
    {
      dwWidth = 40;
    }
    if ( dwHeight < 30 )
    {
      dwHeight = 30;
    }

    m_Level.m_Field.Resize( dwWidth, dwHeight );
  }*/
}

