/**
 * ==========================================================================
 * File:   gfl_Exception.cpp
 * Author: Hisanao Suzuki
 * Created on 2011/12/1
 *
 * 引数が不正の際にthrowされる例外クラス
 * ==========================================================================
 */
#include <err/gfl_Exception.h>
#include <stdio.h>
#include <string.h>

//-----------------------------------------------------------------------
// MESSAGE HEADER
//-----------------------------------------------------------------------
#define GFL_EXCEPTION_CLASS_HEADER     ("gfl::err:Exception")
//-----------------------------------------------------------------------


namespace  gfl{
namespace  err{

/** ---------------------------------------------------------------------
* @brief  コンストラクタ
* @param  message エラーメッセージを追加したい場合、文字列を渡す。
*         NULLの指定も可能。
* @param  fileName エラーが発生したファイル名
*         NULLの指定も可能。
* @param  line     エラーが発生したファイル行番号
* @param  funcName エラーが発生した関数名(省略可能)
*         NULLの指定も可能。
* @return 無し
// ---------------------------------------------------------------------*/
Exception::Exception( const char * message, const char *fileName, u32 line, const char* funcName )
{
  SetName( m_fileName, fileName, FILENAME_BUFFER_SIZE )
  SetName( m_funcName, funcName, FUNCNAME_BUFFER_SIZE )
  
  m_line = line;

  SetMessage( GFL_EXCEPTION_CLASS_HEADER, message );
}


/** ---------------------------------------------------------------------
* @brief  名称の設定
* @param  dst  格納先バッファ
* @param  src  参照元バッファ
* @param  size バッファサイズ
* @return 無し
// ---------------------------------------------------------------------*/
void Exception::SetName( char *dst, const char* src, u32 size )
{
  if( src == NULL ){
    dst[0] = '\0';
  }
  else
  {
    u32 length = strlen( src );

    if( length >= size )
    {
      memcpy( dst, src, size );
      m_fileName[size-1] = '\0';
    }
    else{
      strcpy( dst, src );
    }
  }
}


/** ---------------------------------------------------------------------
* @brief  トレース情報の追加
* @param  fileName エラーが発生したファイル名
*         NULLの指定も可能。
* @param  line     エラーが発生したファイル行番号
* @param  funcName エラーが発生した関数名(省略可能)
*         NULLの指定も可能。
* @return 無し
// ---------------------------------------------------------------------*/
void Exception::Push( const char *fileName, u32 line, const char* funcName )
{
  char fileNameBuf[FILENAME_BUFFER_SIZE];
  char funcNameBuf[FUNCNAME_BUFFER_SIZE];
  char message[MESSAGE_TEMP_SIZE];

  SetName( fileNameBuf, fileName, FILENAME_BUFFER_SIZE )
  SetName( funcNameBuf, funcName, FUNCNAME_BUFFER_SIZE )

  sprintf( message, "[%s L:%u %s]", fileNameBuf, m_line, funcNameBuf );

}

/** ---------------------------------------------------------------------
* @brief  トレース情報をコンソールへ出力する
* @param  無し
* @return 無し
// ---------------------------------------------------------------------*/
void    Exception::PrintStackTrace( void ) const
{
  GFL_PRINT( "%s\n", m_message );
}


/** ---------------------------------------------------------------------
* @brief  例外が発行されたファイル名を取得
* @param  無し
* @return 例外が発行されたファイル名
// ---------------------------------------------------------------------*/
const char* Exception::GetThrowsFileName( void ) const
{
  return m_fileName;
}


/** ---------------------------------------------------------------------
* @brief  例外が発行された関数名を取得
* @param  無し
* @return 例外が発行された関数名
// ---------------------------------------------------------------------*/
const char* Exception::GetThrowsFunctionName( void ) const
{
  return m_funcName;
}


/** ---------------------------------------------------------------------
* @brief  例外が発行されたファイルの行数を取得
* @param  無し
* @return 例外が発行されたファイルの行数
// ---------------------------------------------------------------------*/
u32     Exception::GetThrowsFileLine( void ) const
{
  return m_line;
}

/** ---------------------------------------------------------------------
* @brief  エラーメッセージの設定
* @param  classHeader クラス名ヘッダ文字列
* @param  message エラーメッセージを追加したい場合、文字列を渡す。
*         NULLの指定も可能。
* @return なし
// ---------------------------------------------------------------------*/
void    Exception::SetMessage( const char *classHeader, const char* message )
{
  u32 maxSize = (MESSAGE_BUFFER_SIZE-3);

  strcpy( m_message, "%s", classHeader );

  if( message != NULL )
  {
    strcat( m_message, "  " );
    AddMessage( message );
  }
  Push( m_fileName, m_line, m_funcName );
}

void  Exception::AddMessage( const char* message )
{
  u32 nowLength = strlen( m_message );
  u32 addLength = strlen( message   );

  if( nowLength < MESSAGE_BUFFER_SIZE )
  {
    if( (nowLength+addLength) >= maxSize )
    {
      memcpy( &m_message[nowLength], message, (maxSize-nowLength) );
      m_message[maxSize] = '\0';
    }
    else{
      strcat( m_message, message );
    }
  }
}

} // err
} // gfl

