/**
 * 例外を使用した場合のサンプル
 *
 * ASSERTを使用せず、必ず各種エラーを処理するものとする
 *
 */
 
#include <err/gfl_Error.h>

#define NOT_THROWS_EXCEPTION   throw()

//========================================================================================

//==============================================
// Procクラス
//==============================================
class Proc :public gfl::proc::BaseProcess
{
  SampleClass *m_samp;
  bool         m_isFalt;
};



Proc::Proc( APP_PARAM * prm ) : m_samp(NULL), m_isFalt(false)
{
}


gfl::proc::Result Proc::DoMainProcess()
{
  // 継続できない状況に陥った場合は、
  // 状況に合わせた例外が呼び出し元にthrowされる
  ControlChara();
  ControlField();
  ControlSound();
  ControlNetwork();

  return isFinish() ? gfl::proc::RES_FINISH : gfl::proc::RES_CONTINUE;
}


gfl::proc::Result Proc::InitFunc( gfl::proc::Manager * )
{
  try
  {
    gfl::heap::HeapBase* systemHeap = gfl::heap::Manager::GetHeapByHeapId( gfl::heap::HEAPID_SYSTEM );
    m_samp = GFL_NEW(systemHeap) SampleClass();
    
    m_samp->Initialize();
  }
  catch( ... ){
    m_isFalt = true;
  }
}

gfl::proc::Result Proc::UpdateFunc( gfl::proc::Manager * )
{
  if( !m_isFalt )
  {
    try
    {
      return DoMainProcess();
    }
    catch( ... ){
      // 継続できないエラー発生！
    }
  }
      
  // エラーが発生した旨を呼び出し元に通知するための処理を準備
  // ここでは、返却値にエラーが発生した場合のリザルトコードを返すものとする
  return gfl::proc::RES_ERROR;
}

void Proc::DrawFunc( gfl::proc::Manager * )
{
  if( m_isFalt ){
    return; // エラーなので表示しない
  }

    // 描画本体が記載される
}

gfl::proc::Result GameProc::EndFunc(gfl::proc::Manager* pManager)
{
  GFL_SAFE_DELETE( m_samp );
  
  return gfl::proc::RES_FINISH;
}

//========================================================================================

//==============================================
// コンストラクタは例外をthrowしては駄目！
//==============================================
void SampleClass::SampleClass() NOT_THROWS_EXCEPTION
{
}

//==============================================
// デストラクタは例外をthrowしては駄目！
//==============================================
void SampleClass::~SampleClass() NOT_THROWS_EXCEPTION
{
}


//==============================================
// 初期化 
//==============================================
void SampleClass::Initialize() 
{
  try
  {
    InitializeFont();
    InitializeCharaModel();
    InitializeFieldModel();
    InitializeSound();
    InitializeNetwork();
  }
  // 以下、例外を出力しているが、出力しないでよい場合は
  // catchしないで関数外へthrowさせてしまってOK
  catch( gfl::err::FileNotFoundException &fileEx )
  {
    fileEx.PrintStackTrace();
    throw fileEx;
  }
  catch( gfl::err::IOException &ioEx )
  {
    ioEx.PrintStackTrace();
    throw ioEx;
  }
  catch( gfl::err::MemoryAllocateException &memEx )
  {
    memEx.PrintStackTrace();
    throw memEx;
  }
  catch( gfl::err::Exception &ex ){
    ex.PrintStackTrace();
    throw ex;
  }
}

//==============================================
// ワーク領域として確保したメモリ等のクリーニング
// ちょっとこの方法、不恰好ですね･･･。
// javaのようにfinallyがあればいいんですが。
//==============================================
void SampleClass::CleanInitializeFontWork( u8* fontData, gfl::fs::RomFile &file )
{
   GFL_SAFE_DELETE( fontData );
   file.close();
}

//==============================================
// フォントの初期化 
//==============================================
void SampleClass::InitializeFont() 
   // 以下は、下記例外だけをthrowすることを確約するもの。
   // これ以外の例外がthrowされた場合は、アプリケーションが強制終了となる
   // なお未記載の場合は、あらゆる例外を呼び出しもとの関数にthrowすることが可能
   throw ( gfl::err::Exception, gfl::err::FileNotFoundException, gfl::err::IOException, gfl::err::MemoryAllocateException )
{
  gfl::fs::RomFile file;
  u8*              fontData = NULL;

  // 以下、関数内部でファイルが見つからない場合は
  // 関数内で「gfl::err::FileNotFoundExceptionがthrowされる」
  file.Open( L"rom:/cbf_std.bcfnt", gfl::fs::OPEN_MODE_READ );

  size_t fileSize = file.GetSize();

  try
  {
    // メモリの確保に失敗した場合、関数内で
    // 「gfl::err::MemoryAllocateException」がthrowされる
    fontData = m_deviceAllocator->Alloc( fileSize, 128 );

    file.Read( fontData, fileSize );

    // ファイル全てをロードできなかった
    if( readSize != fileSize ){
       THROW_GFL_IO_EXCEPTION( "[font file load]" );
    }

    gfl::grp::util::DrawUtil::Initialize( m_graphics, m_heapAllocator, m_deviceAllocator );
    gfl::grp::util::DrawUtil::SetFontResource( fontData );

    CleanInitializeFontWork( fontData, file );
  }
  catch( gfl::err::IOException &ioEx )
  {
    CleanInitializeFontWork( fontData, file );
    throw ioEx;
  }
  catch( gfl::err::MemoryAllocateException &memEx )
  {
    CleanInitializeFontWork( fontData, file );
    throw memEx;
  }
  catch( ... )
  {
    CleanInitializeFontWork( fontData, file );
    THROW_GFL_EXCEPTION( "[unknown error]" ); 
  }
}


