/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2016/12/07
/// 
/// @brief  DirectX シェーダーコードフラグメント用変数定義クラス関連。
/// 
/// ****************************************************************************


#include "CPL_DX_Shader_CodeItemVariable.h"
#include "CPL_DX_Shader_Keywords.h"

namespace CPL {
namespace DX {
namespace Shader {


// _____________________________________________________________________________
/// @brief デフォルトコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CodeItemVariable::CodeItemVariable()
  : m_name_No( 0 )
  , m_array_num( 0 )
  , m_semantic_No( 0 )
{
  // 今のところ何もしない
}


// _____________________________________________________________________________
/// @brief コンストラクタ（パラメタ指定version）
/// 
/// @param[in] in_param : パラメタオブジェクトを指定します。\n
///   : 以下のパラメタオブジェクトが指定できます。\n
///   : CodeItem::StrageClass   \n
///   : CodeItem::TypeModifier  \n
///   : CodeItem::InputModifier \n
///   : CodeItem::Type          \n
///   : CodeItem::Name          \n
///   : CodeItem::Num           \n
///   : CodeItem::Semantic      \n
///   : CodeItem::Annotation    \n
///   : CodeItem::Initialize    \n
///   : CodeItem::PackOffset    \n
///   : CodeItem::Register      \n
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CodeItemVariable::CodeItemVariable( cref<Parameter_> in_param )
  : m_name_No( 0 )
  , m_array_num( 0 )
  , m_semantic_No( 0 )
{
  zzf_SetParameter( in_param );
}


// _____________________________________________________________________________
/// @brief デストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CodeItemVariable::~CodeItemVariable()
{
  // 今のところ何もしない
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// パラメータ汎用設定
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool CodeItemVariable::zzf_SetParameter( cref<Parameter_> in_param )
{
  bool ret = false;

  if     ( typeid(in_param) == typeid(NonParam_) ) return false;
  else if( typeid(in_param) == typeid(StrageClass  ) ){ m_strage_class  .Reset(in_param); }
  else if( typeid(in_param) == typeid(TypeModifier ) ){ m_type_modifier .Reset(in_param); }
  else if( typeid(in_param) == typeid(InputModifier) ){ m_input_modifier.Reset(in_param); }
  else if( typeid(in_param) == typeid(Type         ) ){ m_type          .Reset(in_param); }
  else if( typeid(in_param) == typeid(Name         ) ){ m_name          .Reset(in_param); }
  else if( typeid(in_param) == typeid(Num          ) ){ m_array_num = static_cast<Num const*>(&in_param)->num; }
  else if( typeid(in_param) == typeid(Semantic     ) ){ m_semantic      .Reset(in_param); }
  else if( typeid(in_param) == typeid(Annotation   ) ){ m_annotation    .Reset(in_param); }
  else if( typeid(in_param) == typeid(Initialize   ) ){ m_initial_value .Reset(in_param); }
  else if( typeid(in_param) == typeid(PackOffset   ) ){ m_packoffset    .Reset(in_param); }
  else if( typeid(in_param) == typeid(Register     ) ){ m_register      .Reset(in_param); }

  if( in_param.m_ptr_next_param )
  {
    zzf_SetParameter( *in_param.m_ptr_next_param );
  }

  return ret;
}


// _____________________________________________________________________________
/// @brief 変数情報比較
/// 
/// @param[in] in_item : シェーダーコードアイテムを指定します。
/// 
/// @retval true  : 一致
/// @retval false : 不一致
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool CodeItemVariable::operator == ( cref<CodeItem> in_item ) const
{
  CodeItemVariable const*
    ptr_variable = dynamic_cast<CodeItemVariable const*>( &in_item );

  if( !ptr_variable )
  {
    return false;
  }

  // 名前一致比較
  return (Core::StringA::str_cmp_( m_name, ptr_variable->m_name ) == 0);
}


// _____________________________________________________________________________
/// @brief コピー
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CodeItemVariable&
  CodeItemVariable::operator= ( cref<CodeItemVariable> in_variable )
{
  m_strage_class  .Reset( in_variable.m_strage_class );
  m_type_modifier .Reset( in_variable.m_type_modifier );
  m_input_modifier.Reset( in_variable.m_input_modifier );
  m_type          .Reset( in_variable.m_type );
  m_name          .Reset( in_variable.m_name );
  m_semantic      .Reset( in_variable.m_semantic );
  m_annotation    .Reset( in_variable.m_annotation );
  m_initial_value .Reset( in_variable.m_initial_value );
  m_packoffset    .Reset( in_variable.m_packoffset );
  m_register      .Reset( in_variable.m_register );
  m_name_No     = in_variable.m_name_No;
  m_array_num   = in_variable.m_array_num;
  m_semantic_No = in_variable.m_semantic_No;

  m_item_set = in_variable.m_item_set;

  return *this;
}


// _____________________________________________________________________________
/// @brief コード生成
/// 
/// 変数の宣言や定義のシェーダーコードを生成します。\n
/// 終端はセミコロンとコンマの場合があるので付けません。
/// 
/// @param[out] out_buf : 生成コード取得用の文字列オブジェクトを渡します。
/// @param[in] in_create_type
///   : 生成するコードのタイプを指定します。\n
///   : 次のフラグが指定可能です。\n
///   : eCreateType::Global       \n
///   : eCreateType::Structure    \n
///   : eCreateType::Local        \n
///   : eCreateType::Argument     \n
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  CodeItemVariable::MakeCode
    ( rout<ss         > out_buf
    , _in <eCreateType> in_create_type
    ) const
{
  bool f_argument =
    (in_create_type == eCreateType::Argument  ||
     in_create_type == eCreateType::ArgumentEnd);
  bool f_global   = typeid(*this) == typeid(CIV_Global);
  // 引数かつ自身がグローバルパラメーター場合（不正である）
  if( f_argument  &&  f_global )
  {
    return;
  }
  else
  {
    out_buf, sm_tab_str(); // タブ挿入

    // ストレージクラス 
    if( !m_strage_class.IsEmpty() )
    {
      out_buf, m_strage_class," ";
    }
    // 入力属性（引数の場合）
    if( f_argument  &&  !m_input_modifier.IsEmpty() )
    {
      out_buf, m_input_modifier," ";
    }
    // 変数型修飾子（引数でない場合）
    if( !f_argument  &&  !m_type_modifier.IsEmpty() )
    {
      out_buf, m_type_modifier," ";
    }

    // 型と名前（必須）
    out_buf, m_type, " ", m_name;

    // 配列化
    if( m_array_num > 1 )
    {
      out_buf[ m_array_num ]; // m_nameの配列化
    }
    // セマンティック
    if( !m_semantic.IsEmpty() )
    {
      out_buf, " : ", m_semantic;
    }
    // アノテーション（初期化含む）
    if( !m_annotation.IsEmpty() )
    {
      out_buf," ",m_annotation;
    }
    // 初期値
    if( !m_initial_value.IsEmpty() )
    {
      out_buf," = ",m_initial_value;
    }
    // パックオフセット
    if( !m_packoffset.IsEmpty() )
    {
      out_buf," ",m_packoffset;
    }
    // レジスタ
    if( !m_register.IsEmpty() )
    {
      out_buf, " : ", CodeKeywords::register_, m_register;
    }

    if( !f_argument  &&  m_item_set.GetItemNum() > 0 )
    {
      CodeKeywords::Block b( out_buf );
      m_item_set.MakeCode( out_buf, eCreateType::Structure );
    }

    switch( in_create_type )
    {
    case eCreateType::Global:
    case eCreateType::Structure:
    case eCreateType::Local:
      out_buf, Ends;
      break;

    case eCreateType::Argument:
      out_buf, ", ";
      break;
    }
  }
}


} // namespace Shader
} // namespace DX
} // namesapace CPL


