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

Module: TiApp

Author: Vince Harron

Description:

Application base class

Copyright 2006 Sony Online Entertainment.  All rights reserved.

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

#include "SyNew.h"
#include "TiApp.h"
#include "TiEventLoop.h"
#include "TiTopLevelWindow.h"
#include "TiFocusMessage.h"
#include <algorithm>
#include "SyDebug.h"
#include "SyAssert.h"

TiApp::TiApp(void):
mpFocus(0),
mpMainLoop(0)
{
}

TiApp::~TiApp(void)
{
  delete mpMainLoop;
}

void TiApp::RunMainLoop()
{
  SyAssert( mpMainLoop == NULL );
  mpMainLoop = SyNew TiEventLoop( this );
  mpMainLoop->Run();
}

void TiApp::ExitMainLoop()
{
  mpMainLoop->Exit();
}

void TiApp::OnFrame()
{
}

TiWindow* TiApp::GetFocus()
{
  return mpFocus;
}

bool TiApp::SetFocus( TiWindow* pFocus )
{
  if ( pFocus == mpFocus )
  {
    return true;
  }

  if ( pFocus )
  {
    // to receive focus, a window must be visible, enabled
    // topmost/top-level window or 
    // a child of the top-level/topmost window
    TiWindow* pNewFocusTopLevel = pFocus;
    for (;;)
    {
      if ( !pNewFocusTopLevel )
      {
        // pFocus has no top level parent
        SyDebug( "SetFocus failed: pFocus has no top level parent\n" );
        return false;
      }

      if ( !pNewFocusTopLevel->IsVisible() )
      {
        SyDebug( "SetFocus failed: pFocus is not visible\n" );
        return false;
      }

      if ( pNewFocusTopLevel->IsTopLevel() )
      {
        break;
      }
      pNewFocusTopLevel = pNewFocusTopLevel->GetParent();
    }

    if ( !mModalStack.empty() )
    {
      if ( pNewFocusTopLevel != (TiWindow*)mModalStack.front() )
      {
        SyDebug( "SetFocus failed: pFocus is not a child of the modal window\n" );
        return false;
      }
    }

    TiTopLevelWindow* pTopMostVisible = 0;
    for ( std::list<TiTopLevelWindow*>::iterator i = mTopLevelWindows.begin(); i != mTopLevelWindows.end(); i++ )
    {
      TiTopLevelWindow* pTopMost = *i;
      if ( pTopMost->IsVisible() )
      {
        pTopMostVisible = pTopMost;
        break;
      }
    }

    if ( pTopMostVisible != pNewFocusTopLevel )
    {
      SyDebug( "SetFocus failed: pFocus is not a child of the topmost, visible window\n" );
      return false;
    }
  }

  TiWindow* pOldWindow = mpFocus;
  TiWindow* pNewWindow = pFocus;

  // send notification(s) of the change
  if( pOldWindow )
  {
    TiFocusMessage killFocus( pOldWindow, TIWINDOW_KILLFOCUS, pOldWindow, pNewWindow );
    pOldWindow->ProcessMessage( &killFocus );
  }
  mpFocus = pFocus;
  if ( pNewWindow )
  {
    TiFocusMessage setFocus( pNewWindow, TIWINDOW_SETFOCUS, pOldWindow, pNewWindow );
    pNewWindow->ProcessMessage( &setFocus );
  }

  return true;
}

void TiApp::TopLevelAdd( TiTopLevelWindow* pTopLevel )
{
  SyAssert( std::find( mTopLevelWindows.begin(), mTopLevelWindows.end(), pTopLevel ) == mTopLevelWindows.end() );
  mTopLevelWindows.push_front( pTopLevel );
}

void TiApp::TopLevelRemove( TiTopLevelWindow* pTopLevel )
{
  std::list<TiTopLevelWindow*>::iterator i = std::find( mTopLevelWindows.begin(), mTopLevelWindows.end(), pTopLevel );
  SyAssert( i != mTopLevelWindows.end() );
  mTopLevelWindows.erase(i);
}

void TiApp::ModalStackPush( TiDialog* pModalDialog )
{
  mModalStack.push_front( pModalDialog );
}

void TiApp::ModalStackPop()
{
  mModalStack.pop_front();
}
