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

  Module: TiCharacterWindow

  Author: Carlo Ordonez

  Description:

    Character window (inventory, stats, skills, quests)

  Copyright 2005 Sony Online Entertainment.  All rights reserved.

*********************************************************************/
#include "SyScene.h"
#include "SyCSprite.h"
#include "TiCharacterWindow.h"
#include "TiCharacterData.h"
#include "TiEquipWindow.h"
#include "TiEnhancementsWindow.h"
#include "TiStatsWindow.h"
#include "TiSkillsWindow.h"
#include "TiQuestWindow.h"
#include "TiUIControl.h"
#include "TiFocusMessage.h"
#include "InputConsole.h"
#include "TiUI.h"
#include "TitanUI.h"
#include "TiUILayout.h"
#include "Titan.h"
#include "TitanInputHandler.h"
#include "graphic.h"
#include "gameobj.h"


const int32 c_nFirstTabX = 41;
const int32 c_nTabSpacing = 80;
const TiSize c_sizeCharacterPane(480, 720); // 2 panes in the character window

/**********************************************************
 * Constructor
 **********************************************************/
TiCharacterWindow::TiCharacterWindow( TiWindow* pParent, TiCharacterData* pData )
: TiWindow( pParent )
{
  mpData = pData;
  mnPlayerCount = 1;
  miPaperDollPlayer = -1;

  for( int32 i = 0; i < c_nMaxLocalPlayers; i++ )
  {
    mpCtrl[i]              = SyNew TiUIControl();
    mePage[i]               = kEquipment;

    mpPages[i][kEquipment] = SyNew TiEquipWindow( this, pData, i );
    mpPages[i][kEnhancements] = SyNew TiEnhancementsWindow( this, pData, i );
    mpPages[i][kStats]     = SyNew TiStatsWindow( this, pData, i );
    mpPages[i][kSkills]    = SyNew TiSkillsWindow( this, pData, i );
    mpPages[i][kQuests]    = SyNew TiQuestWindow( this, pData, i );
  }

  mSprPillar.SetInfo("menu_pillar.tga");
  mSprPaperDollBG.SetInfo("menu_paperdoll_frame.tga");
  mSprPersonaTabs.SetInfo("menu_tabs_frame.tga");
  mSprTabs[kEquipment].SetInfo("menu_tablet_tab_equip.tga");
  mSprTabs[kEnhancements].SetInfo("menu_tablet_tab_inventory.tga");
  mSprTabs[kStats].SetInfo("menu_tablet_tab_stats.tga");
  mSprTabs[kSkills].SetInfo("menu_tablet_tab_skills.tga");
  mSprTabs[kQuests].SetInfo("menu_tablet_tab_quests.tga");

  /*
   * No Paper Doll to beging with
   */
  mPaperDollSprite = -1;

  m_bReturningFromDialog = false;

}

/**********************************************************
 * Destructor
 **********************************************************/
TiCharacterWindow::~TiCharacterWindow()
{
  for( int32 i = 0; i < c_nMaxLocalPlayers; i++ )
  {
    delete mpCtrl[i];
  }
}

/**********************************************************
 * Init
 **********************************************************/
int32 TiCharacterWindow::Init( int32 nPlayerCount, int32 iPlayer )
{
  TiSize sizeDisplay;
  TiPoint ptPaneTL;

  /*
   * Get the commonly used Titan, TitanUI, Scene, and Raster pointers
   */
  mpTitan =   (Titan*) mpData->GetTitanInterface();
  mpTitanUI = (TitanUI*) mpTitan->GetTitanUI();
  mpScene =   mpTitanUI->GetScene();
  mpRaster =  mpScene->GetRasterDev();

  /*
   *  Update page & layout info
   */
  TiUI::Instance()->GetDisplaySize( &sizeDisplay.cx, &sizeDisplay.cy );

  ptPaneTL.x = (sizeDisplay.cx - c_sizeCharacterPane.cx * 2) / 2;
  ptPaneTL.y = (sizeDisplay.cy - c_sizeCharacterPane.cy) / 2;

  mnPlayerCount = nPlayerCount;
  for( int32 i = 0; i < c_nMaxLocalPlayers; i++ )
  {
    mbOpen[i] = false;
    for( int32 iPage = 0; iPage < kMaxPages; iPage++ )
    {
      mpPages[i][iPage]->Show( false );

      TiRect rectPage(ptPaneTL, c_sizeCharacterPane);
      // subtract tabs
      rectPage.top += mSprPersonaTabs.GetSize().cy;

      mpPages[i][iPage]->Move( rectPage );
      mfTabOpacity[i][iPage] = 0.f;
    }
    mptPageLoc[i] = ptPaneTL;

    // tricky code follows (using ! as a toggle between 0 and 1... remember C?)
    mrectPaperDolls[!i].SetRect(ptPaneTL, c_sizeCharacterPane);

    ptPaneTL.x += c_sizeCharacterPane.cx;
  }

  mbOpen[iPlayer] = true;
  InitPaperDoll(iPlayer);

  mpPages[iPlayer][kEquipment]->Show( true );
  mePage[iPlayer] = kEquipment;

  TiUI::Instance()->PlaySound(TiUI::kSoundWindowEvoke);

  m_bReturningFromDialog = false;

  return( 0 );
}

/**********************************************************
 * DrawTabs
 **********************************************************/
void TiCharacterWindow::DrawTabs()
{
  TiPoint pt = mptPageLoc[0];
  pt.x -= mSprPillar.GetSize().cx;
  mSprPillar.Draw(pt);

  pt = mptPageLoc[1];
  pt.x += c_sizeCharacterPane.cx;
  mSprPillar.Draw(pt);

  for(int i = 0; i < mnPlayerCount; i++)
  {
    if(!mbOpen[i])
      continue;

    pt = mptPageLoc[i];
    mSprPersonaTabs.Draw(pt);

    pt.x += c_nFirstTabX;

    for(int iTab = 0; iTab < kMaxPages; iTab++)
    {
      if(iTab == mePage[i])
      {
        mfTabOpacity[i][iTab] = SY_MIN(1.f, mfTabOpacity[i][iTab] + 6.f * TiUI::Instance()->GetFrameElapse());
      }
      else
      {
        mfTabOpacity[i][iTab] = SY_MAX(0.f, mfTabOpacity[i][iTab] - 4.f * TiUI::Instance()->GetFrameElapse());
      }
      mSprTabs[iTab].Draw(pt, c_rectPS3Screen, mfTabOpacity[i][iTab]);
      pt.x += c_nTabSpacing;
    }
  }
}

/**********************************************************
 * DrawSelf
 **********************************************************/
void TiCharacterWindow::DrawSelf()
{
  DrawTabs();
  for(int i = 0; i < c_nMaxLocalPlayers; i++)
  {
    if(!mbOpen[i])
    {
      mSprPaperDollBG.Draw(mrectPaperDolls[miPaperDollPlayer].TopLeft());

      if(i < mnPlayerCount)
      {
        // prompt for opening inventory
//        const char8* pText = "|xEnter Inventory";
//        int32 w = mpCtrl[i]->GetTextWidth( pText );
      }
    }
  }
}

/**********************************************************
 * ProcessButtonDown
 **********************************************************/
bool TiCharacterWindow::ProcessButtonDown( int32 iDeviceId, int32 nButtonId )
{
  // process by player (device) ID
  TiWindow* pPage = mpPages[iDeviceId][mePage[iDeviceId]];
  TiButtonMap::Button button = TiWindow::GetButton( nButtonId );

  /*
   * Check to see if window is open or closed
   */
  if( mbOpen[iDeviceId] == false )
  {
    /*
     * Closed. If X button pressed, open it. 
     */
    if( button == TiButtonMap::kX )
    {
      Open( iDeviceId );
      ClosePaperDoll();
    }
    return( true );
  }
  else 
  {
    /*
     * Window is open, we process the button press.
     */
    if (mePage[iDeviceId] == kEquipment)
    {
      /*
       * If its the Equipment Window, we need to pass in paper doll
       * info for it to be able to update the paper doll.
       */
      TiEquipWindow * pEquipWindow = (TiEquipWindow*)pPage;
      pEquipWindow->SetPaperDollSpriteHandle (mPaperDollSprite);
    }

    int result = pPage->ProcessButtonDown( iDeviceId, nButtonId );
    if (result == 0)
    {
      switch( button )
      {
      case TiButtonMap::kCircle:
      case TiButtonMap::kSelect:
        Close( iDeviceId );
        //CloseWindow();
        return( true );
        
      case TiButtonMap::kL1:
        PrevPage( iDeviceId );
        return( true );
        
      case TiButtonMap::kR1:
        NextPage( iDeviceId );
        return( true );
        
      default:
        return( false );
      }
    }
    else
    {
      return( true );
    }
  }
}

/**********************************************************
 * ProcessButtonUp
 **********************************************************/
bool TiCharacterWindow::ProcessButtonUp( int32 iDeviceId, int32 nButtonId )
{
  TiWindow* pPage = mpPages[iDeviceId][mePage[iDeviceId]];
  if( !pPage->ProcessButtonUp( iDeviceId, nButtonId ) )
  {
    // default
    return( true );
  }
  else
  {
    // handled
    return( true );
  }
}

/**********************************************************
 * ProcessMessage
 **********************************************************/
void TiCharacterWindow::ProcessMessage( TiWindowMessage* pMessage )
{
	switch( pMessage->GetMessageId() )
	{
		case TIWINDOW_SETFOCUS:
		{
			if( pMessage->GetSender() != this )
			{
				m_bReturningFromDialog = true;
				TiWindow::SetFocus();
				return;
			}
			else if( !m_bReturningFromDialog )
			{
				// just gained focus
				for( int32 i = 0; i < c_nMaxLocalPlayers; i++ )
				{
					for( int32 j = 0; j < kMaxPages; j++ )
					{
						mpPages[i][j]->Init();
					}
					mePage[i] = kEquipment;
					mpCtrl[i]->Close( true );
					mpCtrl[i]->Open( true );
				}
			}
			else
			{
				m_bReturningFromDialog = false;
			}
		}
		return;
	}
	TiWindow::ProcessMessage( pMessage );
}

/**********************************************************
 * ProcessReloadLayout
 **********************************************************/
void TiCharacterWindow::ProcessReloadLayout()
{
}

/**********************************************************
 * NextPage
 **********************************************************/
void TiCharacterWindow::NextPage( int Player )
{
  TiUI::Instance()->PlaySound(TiUI::kSoundPage);
  mpPages[Player][mePage[Player]]->Show(false);
  mePage[Player] = (mePage[Player] >= kMaxPages-1) ? kEquipment : ECharacterPage(mePage[Player]+1);
  mpPages[Player][mePage[Player]]->Show(true);
}

/**********************************************************
 * PrevPage
 **********************************************************/
void TiCharacterWindow::PrevPage( int Player )
{
  TiUI::Instance()->PlaySound(TiUI::kSoundPage);
  mpPages[Player][mePage[Player]]->Show(false);
  mePage[Player] = (mePage[Player] <= 0) ? kQuests : ECharacterPage(mePage[Player]-1);
  mpPages[Player][mePage[Player]]->Show(true);
}

/**********************************************************
 * Close
 **********************************************************/
void TiCharacterWindow::Close( int32 Player )
{
  TiUI::Instance()->PlaySound(TiUI::kSoundWindowClose);
  mbOpen[Player] = false;
  mpPages[Player][mePage[Player]]->Show(false);

  if( !mbOpen[0] && !mbOpen[1])
  {
    CloseWindow();
    ClosePaperDoll();
  }
  else if(mbOpen[0] && !mbOpen[1])
  {
    InitPaperDoll(0);
  }
  else if(mbOpen[1] && !mbOpen[0])
  {
    InitPaperDoll(1);
  }
}

/**********************************************************
 * Open
 **********************************************************/
void TiCharacterWindow::Open( int32 Player )
{
  TiUI::Instance()->PlaySound(TiUI::kSoundWindowEvoke);
  mbOpen[Player] = true;
  mpPages[Player][mePage[Player]]->Show(true);
}

/**********************************************************
 * OnProcessFrame
 **********************************************************/
void TiCharacterWindow::OnProcessFrame()
{
  UpdatePaperDoll(TiUI::Instance()->GetFrameElapse());
}


/**********************************************************
 * InitPaperDoll
 **********************************************************/
void TiCharacterWindow::InitPaperDoll(int32 iPlayer)
{
  SyVect3 cameraPosition;
  // use mrectPaperDolls[iPlayer] to get screen coords
  /*
   * Initialize character info
   */
  miPaperDollPlayer = iPlayer;
  mPlayerHeading = 0.f;

  /*
   * Get the game character's in-game sprite handle
   */
  int32 actorGameSprite  = GetPlayerSprite(iPlayer);

  /*
   * Make a copy of the game sprite as our paper doll
   */
   mPaperDollSprite = mpScene->CopySprite (actorGameSprite, 0);

  /*
   * make up a 3d camera - camera is out 3 units in Z looking at origin.
   * Depending of which player it is, it will be on the left or right side
   * of the screen.
   */
   if (iPlayer == 0)
   {
     cameraPosition( -1, 1.25, 3.f); 
   }
   else
   {
     cameraPosition( 1, 1.25, 3.f); 
   }
   /*
    * Set up camera info
    */
  SyVect3 cameraLookatDirection( 0, 0, -1.f); 
  float32 screenWidth = (float32)mpRaster->GetScreenWidth();
  float32 screenHeight = (float32)mpRaster->GetScreenHeight();
  float32 screenAspect = screenWidth / screenHeight;
  mCamera.Init (*mpRaster, cameraPosition, cameraLookatDirection, 55.f, screenAspect, .1f, 1000.f);

  /*
   * Get the Character Sprite, init clock, set animation;
   */
  SyCSprite * paperDollSpritePtr = (SyCSprite*) (mpScene->Sprite (mPaperDollSprite));
  paperDollSpritePtr->EraseAllPlay(*mpScene);
  int result;
  result = paperDollSpritePtr->AppendAnimPlay (1, 0, *mpScene);

  /*
   * Initialize the paper doll time to be the game time
   */
  mLocalTime = mpScene->GetTime();

  /*
   * paperDollSprite is the sprite of the paper doll sprite.
   */
  SyCSprite * paperDollSprite = (SyCSprite*) (mpScene->Sprite (mPaperDollSprite));

  /*
   * playerSprite is the source. The sprite of the game version of the paper doll sprite.
   * The game version has the most up-to-date attachments on it.
   */
  int32 playerSpriteHandle  = GetPlayerSprite(miPaperDollPlayer);
  SyCSprite * playerSprite = (SyCSprite*) (mpScene->Sprite (playerSpriteHandle));
  //int numAttachments = playerSprite->GetNumAttach();

  /*
   * Put all the attachments on the paper doll
   */
  int hasAttachedSlot, isEmptySlot, slotSprite;
  SyRefID slotID;
  int i;
  for (i=1; i < 8; i++) // b.s hardcoding for now
  {
    slotID = (SyRefID) i;
    hasAttachedSlot = playerSprite->HasAttachSlot (slotID);
    if (hasAttachedSlot == 1)
    {
      isEmptySlot = playerSprite->IsAttachSlotEmpty (slotID);
      if (isEmptySlot == 0)
      {
        slotSprite = playerSprite->GetAttachSlotSprite (slotID);
        int emptySlot = paperDollSprite->IsAttachSlotEmpty (slotID);
        if (emptySlot == 1)
        {
          paperDollSprite->AttachToSlot (slotSprite, slotID, *mpScene);
        }
      }
    }
    else
    {
    }
  }
}


/**********************************************************
 * UpdatePaperDoll
 **********************************************************/
void TiCharacterWindow::UpdatePaperDoll(float32 fElapsed)
{
  int result;
  /*
   * If we haven't been initialized (ie no paper doll exists), do nothing
   */
  if (mPaperDollSprite == -1) 
  {
    return;
  }

  /*
   * Set up lighting
   */
  SyRasterDirLight sun;
  sun.Dir (-1.f, -1.f, -.85f);
  sun.Color (1.f, 1.f, 1.f, 1.f);
  mpRaster->SetSunLight (sun);
  mpRaster->EnableSunLight (1);
  mpRaster->SetAmbient (SyColor32F (.2f, .2f, .2f, 1.f));

  /*
   * Update player heading information
   */
  const float32 c_fRadsPerSec = SY_PI * 2;  // character spins completely around in 1 sec
  TitanControllerI *pController = TitanUI::Instance()->GetController(miPaperDollPlayer);
  float32 fX = (float32)pController->GetRight() / 10000.f;  // pController gives answers from -10000 to 10000
  mPlayerHeading += fX * fElapsed * c_fRadsPerSec;

  /*
   * Set up raster window 3D model/view transformations
   */
  SyMatrix44 rasterWorldMatrix;
  rasterWorldMatrix.RotateY (mPlayerHeading);
  SyMatrix44 rasterViewMatrix = mCamera.GetView();
  SyMatrix44 rasterProjectionMatrix = mCamera.GetProjection();
  mpRaster->SetWorld (rasterWorldMatrix);
  mpRaster->SetView (rasterViewMatrix);
  mpRaster->SetProjection (rasterProjectionMatrix);
  mpRaster->EnableAmbient (1);




  /*
   * Tick our internal clock
   */
  mLocalTime += (SyTime)(fElapsed * 1000.f);

  /*
   * Save the game clock, substitute our internal clock
   */
  SyTime timeOld = mpScene->GetTime();
  mpScene->SetTime(mLocalTime);

  /*
   * Do Character render
   */
  result = mpScene->RenderSprite (mCamera, mPaperDollSprite);

  /*
   * Restore the game clock
   */
  mpScene->SetTime(timeOld);
}

/**********************************************************
 * ClosePaperDoll
 **********************************************************/
void TiCharacterWindow::ClosePaperDoll()
{
  miPaperDollPlayer = -1;


  SyScene *pScene = TitanUI::Instance()->GetScene();
  mPaperDollSprite = pScene->ReleaseSprite (mPaperDollSprite);

  mPaperDollSprite = -1;
}

/**********************************************************
 * GetPlayerSprite
 **********************************************************/
int32 TiCharacterWindow::GetPlayerSprite (int iPlayer)
{
  /*
   * Given a iPlayer, get the Sprite handle ... easy !!
   */
  TitanInputHandler * pInputHandler = (TitanInputHandler*) mpTitan->GetInputHandler(iPlayer);
  cGameObject       * pGameObject   = pInputHandler->GetGameObject();
  cGraphic          * pGameGraphic  = pGameObject->GetGraphic();
  SyActorHandle       actorHandle  = pGameGraphic->GetActorHandle();
  int32               actorGameSprite  = mpScene->GetActorSprite(actorHandle);
  
  return actorGameSprite;
}




