/********************************************************************

  Module: TiUI

  Author: Carlo Ordonez

  Description:

    Raster 2D drawing services

  Copyright 2005 Sony Online Entertainment.  All rights reserved.

*********************************************************************/

#include "TiUI.h"
#include "SyRaster.h"
#include "SySoundDevice.h"
#include "SyDeferred2D.h"
#include "SyString.h"

//***********************************************************************
// Constructor/Destructor
//***********************************************************************

TiUI *TiUI::sm_pSingleton = NULL;

TiUI::TiUI( SyRaster* pRaster, SySoundDevice* pSoundDev, SyDictionary* pDictionary, std::map< SyResourceID, TiBitmapInfo >* pAtlasDirectory, int32 fontHandle )
{
  mpRaster          = pRaster;
  mpSoundDev        = pSoundDev;
  mpDictionary      = pDictionary;
  mpAtlasDirectory  = pAtlasDirectory;
  mpDeferred2D      = new SyDeferred2D(pRaster, pDictionary);
  mFontHandle       = fontHandle;

  sm_pSingleton = this;
  m_fFrameElapse = 0.f;
}

TiUI::~TiUI()
{
  if (mpDeferred2D != NULL)
  {
    delete mpDeferred2D;
  }
  sm_pSingleton = NULL;
}

void TiUI::Reset()
{
  mFontHandle = -1;

  if (mpDeferred2D != NULL)
  {
    delete mpDeferred2D;
  }
  mpDeferred2D = new SyDeferred2D(mpRaster, mpDictionary);  
}

//***********************************************************************
// GetTime
//***********************************************************************

SyTime TiUI::GetTime()
{
  return( mpRaster->GetTime() );
}

void TiUI::UpdateFrameElapse(SyTime time)
{
    static SyTime timeLast = 0;
    if(timeLast != 0)
    {
        float32 fDelta = ((float32)(time - timeLast)/1000.0f);
        m_fFrameElapse = fDelta;
    }
    timeLast = time;
}

//***********************************************************************
// FlushDeferred2D
//***********************************************************************

void TiUI::FlushDeferred2D()
{
  if(mpDeferred2D != NULL)
  {
    mpDeferred2D->Flush();
  }
}


//***********************************************************************
// TriangleBlit
//***********************************************************************

int32 TiUI::TriangleBlit(SyResourceID idSurface, const TiPoint *arScreenTriangleIn, const TiPoint *arSurfaceTriangleIn, SyAlphaBlendMode eBlendMode, float32 fBlendAlpha)
{
  static SyVect2I ptOffset(0, 0);
  static SyVect2I sizeSurface(0, 0);
  static int32 nSurfaceHandle = -1;
  static SyResourceID s_idLastRequested = 0;
  
  if(idSurface == 0)
    return -1;

  if(s_idLastRequested != idSurface)
  {
    if( GetBitmapInfo( idSurface, nSurfaceHandle, ptOffset, sizeSurface) < 0)
    {
      return -1;
    }

    s_idLastRequested = idSurface;
  }

  SyVect2I arScreenTriangle[3];
  SyVect2I arSurfaceTriangle[3];

  for(int i = 0; i < 3; i++)
  {
    arScreenTriangle[i].X = arScreenTriangleIn[i].x;
    arScreenTriangle[i].Y = arScreenTriangleIn[i].y;

    arSurfaceTriangle[i].X = ptOffset.X + arSurfaceTriangleIn[i].x;
    arSurfaceTriangle[i].Y = ptOffset.Y + arSurfaceTriangleIn[i].y;
  }

  return mpDeferred2D->TriangleBlit(nSurfaceHandle, arScreenTriangle, arSurfaceTriangle, sizeSurface, eBlendMode, fBlendAlpha);
}

//***********************************************************************
// Blit
//***********************************************************************

int32 TiUI::Blit( const char8* pFilename, uint32 BlitFlags, const SyVect2I& ScreenLoc, SyAlphaBlendMode BlendMode, float32 BlendAlpha )
{
  int surfaceHandle = 0;
  SyVect2I surfaceOffset;
  SyVect2I size;
  if( GetBitmapInfo( pFilename, surfaceHandle, surfaceOffset, size ) < 0 )
  {
    return( -1 );
  }

  return( mpDeferred2D->Blit( surfaceHandle, BlitFlags, ScreenLoc, surfaceOffset, size, BlendMode, BlendAlpha ) );
}

//***********************************************************************
// Blit
//***********************************************************************

int32 TiUI::Blit( const char8* pFilename, uint32 BlitFlags, const SyVect2I& ScreenLoc, const SyVect2I& SurfaceOffset, const SyVect2I& ScreenSize, SyAlphaBlendMode BlendMode, float32 BlendAlpha )
{
  int surfaceHandle = 0;
  SyVect2I surfaceOffset;
  SyVect2I size;
  if( GetBitmapInfo( pFilename, surfaceHandle, surfaceOffset, size ) < 0 )
  {
    return( -1 );
  }

  return( mpDeferred2D->Blit( surfaceHandle, BlitFlags, ScreenLoc, SurfaceOffset, ScreenSize, BlendMode, BlendAlpha ) );
}

int32 TiUI::Blit( int32 SurfaceHandle, uint32 BlitFlags, const SyVect2I& ScreenLoc, const SyVect2I& SurfaceOffset, const SyVect2I& ScreenSize, SyAlphaBlendMode BlendMode, float32 BlendAlpha )
{
  return( mpDeferred2D->Blit( SurfaceHandle, BlitFlags, ScreenLoc, SurfaceOffset, ScreenSize, BlendMode, BlendAlpha ) );
}

//***********************************************************************
// StrechBlit
//***********************************************************************

int32 TiUI::StretchBlit( const char8* pFilename, uint32 BlitFlags, const SyVect2I& ScreenLoc, const SyVect2I& ScreenSize, const SyVect2I& SurfaceOffset, const SyVect2I& SurfaceSize, SyAlphaBlendMode BlendMode, float32 BlendAlpha )
{
  int surfaceHandle = 0;
  SyVect2I surfaceOffset;
  SyVect2I size;
  if( GetBitmapInfo( pFilename, surfaceHandle, surfaceOffset, size ) < 0 )
  {
    return( -1 );
  }

  return( mpDeferred2D->StretchBlit( surfaceHandle, BlitFlags, ScreenLoc, ScreenSize, SurfaceOffset, SurfaceSize, BlendMode, BlendAlpha ) );
}

int32 TiUI::StretchBlit( int32 SurfaceHandle, uint32 BlitFlags, const SyVect2I& ScreenLoc, const SyVect2I& ScreenSize, const SyVect2I& SurfaceOffset, const SyVect2I& SurfaceSize, SyAlphaBlendMode BlendMode, float32 BlendAlpha )
{
  return( mpDeferred2D->StretchBlit( SurfaceHandle, BlitFlags, ScreenLoc, ScreenSize, SurfaceOffset, SurfaceSize, BlendMode, BlendAlpha ) );
}

//***********************************************************************
// Blit (float versions)
//***********************************************************************

int32 TiUI::Blit( const char8* pFilename, uint32 BlitFlags, const SyVect2& ScreenLoc, SyAlphaBlendMode BlendMode, float32 BlendAlpha )
{
  int surfaceHandle = 0;
  SyVect2I surfaceOffset;
  SyVect2I size;
  if( GetBitmapInfo( pFilename, surfaceHandle, surfaceOffset, size ) < 0 )
  {
    return( -1 );
  }

  return( mpDeferred2D->Blit( surfaceHandle, BlitFlags, ScreenLoc, surfaceOffset, size, BlendMode, BlendAlpha ) );
}

//***********************************************************************
// Blit (float versions)
//***********************************************************************

int32 TiUI::Blit( const char8* pFilename, uint32 BlitFlags, const SyVect2& ScreenLoc, const SyVect2I& SurfaceOffset, const SyVect2I& ScreenSize, SyAlphaBlendMode BlendMode, float32 BlendAlpha )
{
  int surfaceHandle = 0;
  SyVect2I surfaceOffset;
  SyVect2I size;
  if( GetBitmapInfo( pFilename, surfaceHandle, surfaceOffset, size ) < 0 )
  {
    return( -1 );
  }

  return( mpDeferred2D->Blit( surfaceHandle, BlitFlags, ScreenLoc, SurfaceOffset, ScreenSize, BlendMode, BlendAlpha ) );
}

int32 TiUI::Blit( int32 SurfaceHandle, uint32 BlitFlags, const SyVect2& ScreenLoc, const SyVect2I& SurfaceOffset, const SyVect2I& ScreenSize, SyAlphaBlendMode BlendMode, float32 BlendAlpha )
{
  return( mpDeferred2D->Blit( SurfaceHandle, BlitFlags, ScreenLoc, SurfaceOffset, ScreenSize, BlendMode, BlendAlpha ) );
}

//***********************************************************************
// StrechBlit
//***********************************************************************

int32 TiUI::StretchBlit( const char8* pFilename, uint32 BlitFlags, const SyVect2& ScreenLoc, const SyVect2& ScreenSize, const SyVect2I& SurfaceOffset, const SyVect2I& SurfaceSize, SyAlphaBlendMode BlendMode, float32 BlendAlpha )
{
  int surfaceHandle = 0;
  SyVect2I surfaceOffset;
  SyVect2I size;
  if( GetBitmapInfo( pFilename, surfaceHandle, surfaceOffset, size ) < 0 )
  {
    return( -1 );
  }

  return( mpDeferred2D->StretchBlit( surfaceHandle, BlitFlags, ScreenLoc, ScreenSize, SurfaceOffset, SurfaceSize, BlendMode, BlendAlpha ) );
}

int32 TiUI::StretchBlit( int32 SurfaceHandle, uint32 BlitFlags, const SyVect2& ScreenLoc, const SyVect2& ScreenSize, const SyVect2I& SurfaceOffset, const SyVect2I& SurfaceSize, SyAlphaBlendMode BlendMode, float32 BlendAlpha )
{
  return( mpDeferred2D->StretchBlit( SurfaceHandle, BlitFlags, ScreenLoc, ScreenSize, SurfaceOffset, SurfaceSize, BlendMode, BlendAlpha ) );
}

//***********************************************************************
// DrawString
//***********************************************************************

int32 TiUI::DrawString( const char8* pString, const SyVect2I& Location, const SyColor32F& Color, bool Shadow )
{
  if( Shadow )
  {
    SyVect2I loc = Location;
    loc.X += 2;
    loc.Y += 2;
    mpDeferred2D->DrawString( mFontHandle, loc, SyColor32F(0,0,0,Color.A), pString );
  }

  return( mpDeferred2D->DrawString( mFontHandle, Location, Color, pString ) );
}

int32 TiUI::DrawString( const wchar_t* pString, const SyVect2I& Location, const SyColor32F& Color, bool Shadow )
{
  if( Shadow )
  {
    SyVect2I loc = Location;
    loc.X += 2;
    loc.Y += 2;
    mpDeferred2D->DrawString( mFontHandle, loc, SyColor32F(0,0,0,Color.A), pString );
  }

  return( mpDeferred2D->DrawString( mFontHandle, Location, Color, pString ) );
}

//***********************************************************************
// DrawCenteredString
//***********************************************************************

int32 TiUI::DrawCenteredString( const char8* pString, const SyVect2I& Location, const SyColor32F& Color, uint32 CenterFlags, bool Shadow )
{
  if( Shadow )
  {
    SyVect2I loc = Location;
    loc.X += 2;
    loc.Y += 2;
    mpDeferred2D->DrawCenteredString( mFontHandle, loc, SyColor32F(0,0,0,Color.A), pString, CenterFlags );
  }

  return( mpDeferred2D->DrawCenteredString( mFontHandle, Location, Color, pString, CenterFlags ) );
}

int32 TiUI::DrawCenteredString( const wchar_t* pString, const SyVect2I& Location, const SyColor32F& Color, uint32 CenterFlags, bool Shadow )
{
  if( Shadow )
  {
    SyVect2I loc = Location;
    loc.X += 2;
    loc.Y += 2;
    mpDeferred2D->DrawCenteredString( mFontHandle, loc, SyColor32F(0,0,0,Color.A), pString, CenterFlags );
  }

  return( mpDeferred2D->DrawCenteredString( mFontHandle, Location, Color, pString, CenterFlags ) );
}

//***********************************************************************
// GetBitmapInfo
//  @param pFilename      [IN]    the bmp to search for
//  @param SurfaceHandle  [OUT]   handle to surface resource, if found
//  @param SurfaceOffset  [OUT]   (x,y) offset into surface, if found
//  @param Size           [OUT]   (w,h) of bmp, if found
//  @param TotalSize           [OUT]   (w,h) of atlas texture, if found (can be null)
//***********************************************************************

int32 TiUI::GetBitmapInfo( const char8* pFilename, int32& SurfaceHandle, SyVect2I& SurfaceOffset, SyVect2I& Size)
{
  SyResourceID id = SyHashResourceID( pFilename );
  return GetBitmapInfo(id, SurfaceHandle, SurfaceOffset, Size);
}

int32 TiUI::GetBitmapInfo( uint32 uHashId, int32& SurfaceHandle, SyVect2I& SurfaceOffset, SyVect2I& Size)
{
  std::map< SyResourceID, TiBitmapInfo >::const_iterator i = mpAtlasDirectory->find( uHashId );
  if( i == mpAtlasDirectory->end() )
  {
    // not found
    return( -1 );
  }

  if( mpDictionary->FindTyped( i->second.mSurfaceResourceID, SYRESOURCETYPE_SURFACE, SurfaceHandle ) == 0 )
  {
    // not found
    return( -1 );
  }

  SurfaceOffset = i->second.GetSurfaceOffset();
  Size = SyVect2I( i->second.GetWidth(), i->second.GetHeight() );

  return( 0 );
}

//***********************************************************************
// GetBitmapInfo
//***********************************************************************

int32 TiUI::GetBitmapInfo( const char8* pFilename, SyVect2I& SurfaceOffset, SyVect2I& Size )
{
  int unused = 0;
  return( GetBitmapInfo( pFilename, unused, SurfaceOffset, Size ) );
}

int32 TiUI::GetBitmapInfo( uint32 uHashId, SyVect2I& SurfaceOffset, SyVect2I& Size )
{
  int unused = 0;
  return( GetBitmapInfo( uHashId, unused, SurfaceOffset, Size ) );
}

//***********************************************************************
// GetFontHeight
//***********************************************************************

int32 TiUI::GetFontHeight(int32 nFontHandle) const
{
  return mpRaster->GetFontHeight(nFontHandle);
}

int32 TiUI::GetFontHeight() const
{
  return( mpRaster->GetFontHeight( mFontHandle ) );
}

//***********************************************************************
// GetStringWidth
//***********************************************************************

int32 TiUI::GetStringWidth( const char8* pString )
{
  return( mpRaster->GetStringWidth( mFontHandle, pString ) );
}

int32 TiUI::GetStringWidth( const wchar_t* pString )
{
  return( mpRaster->GetStringWidth( mFontHandle, pString ) );
}

//***********************************************************************
// GetDisplaySize
//***********************************************************************

void TiUI::GetDisplaySize( int32* pWidth, int32* pHeight ) const
{
  if( pWidth )
  {
    *pWidth = mDisplaySize.X;
  }

  if( pHeight )
  {
    *pHeight = mDisplaySize.Y;
  }
}

//***********************************************************************
// SetDisplaySize
//***********************************************************************

void TiUI::SetDisplaySize( int32 Width, int32 Height )
{
  mDisplaySize.X = Width;
  mDisplaySize.Y = Height;
}

//***********************************************************************
// GetCenter
//***********************************************************************

const SyVect2I TiUI::GetCenter() const
{
  return( SyVect2I( mDisplaySize.X>>1, mDisplaySize.Y>>1 ) );
}

//***********************************************************************
// FillRectangle
//***********************************************************************

void TiUI::FillRectangle( const SyVect2I& UL, const SyVect2I& LR, const SyColor32F& Color )
{
  mpDeferred2D->FillRect(SyRect(UL, LR), Color);
}

//***********************************************************************
// PlaySound
//***********************************************************************

int32 TiUI::PlaySound( const char8* pFilename )
{
  SyResourceType type;
  int32 handle;
  SyString full("R:\\PS3\\ULPS3\\game_assets\\UI\\audio\\" ); // yuck, full pathnames needed for hash
  full += pFilename;

  if( mpDictionary->Find( SyHashResourceID(full.AsChar()), type, handle ) != 0 )
  {
    if( mpSoundDev )
    {
      mpSoundDev->Play( handle, 127, SySoundDevice::kSoundClassUi );
    }
    return( 0 );
  }
  else
  {
    // not found
    return( -1 );
  }
}

int32 TiUI::PlaySound( Sound sound )
{
  SyString filename;
  switch( sound )
  {
  case kSoundBack:
    filename = "UI_back.wav";
  	break;
  case kSoundCancel:
    filename = "UI_cancel.wav";
    break;
  case kSoundEquip:
    filename = "UI_equip.wav";
    break;
  case kSoundHealthUp:
    filename = "UI_health_up.wav";
    break;
  case kSoundLevelUp:
    filename = "UI_level_up.wav";
    break;
  case kSoundLootDrop:
    filename = "UI_loot_drop.wav";
    break;
  case kSoundLowMana:
    filename = "UI_low_mana.wav";
    break;
  case kSoundName:
    filename = "UI_name.wav";
    break;
  case kSoundNegative:
    filename = "UI_negative.wav";
    break;
  case kSoundNotice:
    filename = "UI_notice.wav";
    break;
  case kSoundPage:
    filename = "UI_page.wav";
    break;
  case kSoundPickup:
    filename = "UI_pickup.wav";
    break;
  case kSoundSelect:
    filename = "UI_select.wav";
    break;
  case kSoundSpellSelect:
    filename = "UI_spell_select.wav";
    break;
  case kSoundTick:
    filename = "UI_tick.wav";
    break;
  case kSoundUnequip:
    filename = "UI_unequip.wav";
    break;
  case kSoundWarning:
    filename = "UI_warning.wav";
    break;
  case kSoundWindowEvoke:
    filename = "UI_menu_screen_up.wav";
    break;
  case kSoundWindowClose:
    filename = "UI_menu_screen_down.wav";
    break;
  default:
    SyAssertf( 0, "Unknown sound" );
    return( -1 );
  }

  return( PlaySound( filename.AsChar() ) );
}

int32 TiUI::GetFontHandle(const char8 * /*pszFont*/) const
{
  // for now, there is only one font, so ignore pszFont parameter
  return mFontHandle;
}
