/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2016/12/07
/// 
/// @brief  DirectX シェーダフラグメント。
/// 
/// ****************************************************************************

#include "CPL_DX_Shader_Code.h"

namespace CPL {
namespace DX {
namespace Shader {


// _____________________________________________________________________________
/// @brief シェーダー用コードの生成
/// 
/// @param[in] in_str_function_name
///   : メイン関数の名前を指定します。
/// @param[in] in_SCFC
///   : シェーダコード用のフラグメントが格納された、
///     CodeFragmentCollectionオブジェクトを指定します。
/// @param[in] in_semantic
///   : セマンティクス識別型を指定します。\n
///   : メイン関数のセマンティクスとなります。
/// 
/// @return 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  ShaderCode::Create
    ( _in<char_cptr             > in_str_function_name
    , _in<CodeFragmentCollection> in_SCFC
    , _in<CodeItem::Semantic    > in_semantic
    )
{
  // コードアイテム集合の構築
  sdptr<CIV_Global>      sp_item_set_global( CPL_MAKE_SHARED(CIV_Global) );
  sdptr<CIV_Input >      sp_item_set_input ( CPL_MAKE_SHARED(CIV_Input) );
  sdptr<CIV_Output>      sp_item_set_output( CPL_MAKE_SHARED(CIV_Output) );
  sdptr<CIV_Initializer> sp_item_set_init  ( CPL_MAKE_SHARED(CIV_Initializer) );
  sdptr<CIV_Finalizer  > sp_item_set_final ( CPL_MAKE_SHARED(CIV_Finalizer) );
  sdptr<CIFunctionSet  > sp_item_set_function( CPL_MAKE_SHARED(CIFunctionSet) );

  *sp_item_set_input  = CPType(struct_) | CPName("INPUT");
  *sp_item_set_output = CPType(struct_) | CPName("OUTPUT");

  m_item_set
    << sp_item_set_global
    << sp_item_set_input
    << sp_item_set_output
    << sp_item_set_function;

  size_t frgm_num = in_SCFC.GetFragmentNum();
  CPL_LOOP2( frgm_num, frgm_idx )
  {
    sdptr<CodeFragment> sp_frgm = in_SCFC.GetFragment( frgm_idx );

    // セットアップ呼び出し
    sp_frgm->On_SetupGlobalParameter( *sp_item_set_global );
    sp_frgm->On_SetupInputParameter( *sp_item_set_input );
    sp_frgm->On_SetupOutputParameter( *sp_item_set_output );
    sp_frgm->On_SetupFunction( *sp_item_set_function, *sp_item_set_global );
    sp_frgm->On_SetupInitializer( *sp_item_set_init );
    sp_frgm->On_SetupFinalizer( *sp_item_set_final );
  }

  // グローバル
  sp_item_set_global->MakeCode( m_code_buf_instance, CodeItem::eCreateType::Global );

  // 入力
  sp_item_set_input->MakeCode( m_code_buf_instance, CodeItem::eCreateType::Global );

  // 出力
  sp_item_set_output->MakeCode( m_code_buf_instance, CodeItem::eCreateType::Global );

  // 関数
  sp_item_set_function->MakeCode( m_code_buf_instance, CodeItem::eCreateType::Global );

  //***** ステートメントブロックの構築 *****//
  ss statement_block;
  statement_block.Reserve( 1024 );
  statement_block, "OUTPUT output = (OUTPUT)0;\n";
  // 初期化
  sp_item_set_init->MakeCode( statement_block, CodeItem::eCreateType::Local );

  // 処理関数呼び出し
  CPL_LOOP2( frgm_num, frgm_idx )
  {
    sdptr<CodeFragment> sp_frgm = in_SCFC.GetFragment( frgm_idx );
    ss statement;
    sp_frgm->On_CallFunction( statement, m_item_set );

    statement_block,
      statement; // statement書き込み
  }
  // 後始末
  sp_item_set_final->MakeCode( statement_block, CodeItem::eCreateType::Local );
  //
  statement_block, "return output;\n";

  // メイン関数のコード生成
  CodeItemFunction main_func;
  main_func
    << CodeItem::Type( sp_item_set_output->GetName() )
    << CodeItem::Name( in_str_function_name )
    // 引数
    << CIVariable( CPType( sp_item_set_input->GetName() ) | CPName("input") )
    // ステートメントブロック
    << CodeItem::StatementBlock( statement_block );
  if( !in_semantic.IsEmpty() )
  {
    main_func << in_semantic;
  }

  main_func.MakeCode( m_code_buf_instance, CodeItem::eCreateType::Argument );


  //const int func_num = this->m_fc_table.GetFunctionNum();
  //CPL_LOOP2( func_num, func_idx )
  //{
  //  CodeItemFunction const&
  //    func_item = this->m_fc_table.GetFunction( func_idx );

  //  gc()^ func_item.GetFunctionName() ^ css("(");
  //  
  //  // 最初の引数
  //  {
  //    CodeItemVariable const& va = func_item.GetVariable( 0 );
  //    gc() ^ va.GetType()^ va.GetName();
  //    if( va.GetSemantics().GetLength() > 0 )
  //    {
  //      gc() ^ " : " ^ va.GetSemantics();
  //    }
  //  }
  //  // 以降の引数
  //  const int va_num = func_item.GetVariableNum();
  //  CPL_LOOP2( va_num, va_idx )
  //  {
  //    CodeItemVariable const& va = func_item.GetVariable( va_idx );
  //    gc() ^ ",\n"^ va.GetType()^ va.GetName();
  //    if( va.GetSemantics().GetLength() > 0 )
  //    {
  //      wc(" : ") ^ va.GetSemantics();
  //    }
  //  }

  //  //
  //  wc("){\n");
  //  wc( func_item.GetImplement() );
  //  wc("}\n");
  //}

  //// メイン関数（ここで各処理関数を呼び出す）
  //gc() ^ void_ ^ in_str_function_name ^ "(\n";
  //int arg_cnt = 0;
  //// 入力引数
  //int in_va_num = this->m_fva_table_in.GetVariableNum();

  //if( in_va_num > 0 )
  //{
  //  // 最初の引数
  //  {
  //    CodeItemVariable const& va = m_fva_table_in.GetVariable( 0 );
  //    gc() ^ in_^ va.GetType()^ va.GetName();
  //    
  //    if( va.GetSemantics().GetLength() > 0 )
  //    {
  //      gc() ^ " : " ^ va.GetSemantics();
  //    }
  //  }
  //  // 以降の引数
  //  for( int i = 1; i < in_va_num; ++i )
  //  {
  //    CodeItemVariable const& va = this->m_fva_table_in.GetVariable( i );
  //    gc() ^ ",\n"^in_^ va.GetType()^ va.GetName();
  //    
  //    if( va.GetSemantics().GetLength() > 0 )
  //    {
  //      wc(" : ") ^ va.GetSemantics();
  //    }
  //  }
  //}
  //// 出力引数
  //int out_va_num = this->m_fva_table_out.GetVariableNum();
  //if( out_va_num > 0 )
  //{
  //  // 最初の引数
  //  {
  //    CodeItemVariable const& va = this->m_fva_table_out.GetVariable( 0 );
  //    
  //    if( in_va_num > 0 )
  //    {
  //      wc(",\n");
  //    }
  //    wc(out_)^ va.GetType() ^ va.GetName();
  //    
  //    if( va.GetSemantics().GetLength() > 0 )
  //    {
  //      wc(" : ") ^ va.GetSemantics();
  //    }
  //  }
  //  //
  //  for( int i = 1; i < out_va_num; ++i )
  //  {
  //    CodeItemVariable const& va = this->m_fva_table_out.GetVariable( i );
  //    wc(",\n")^out_ ^ va.GetType() ^ va.GetName();
  //    
  //    if( va.GetSemantics().GetLength() > 0 )
  //    {
  //      wc(" : ") ^ va.GetSemantics();
  //    }
  //  }
  //}
  //wc(")");
  //{
  //  Block b( gc() );
  //  // メイン関数内処理
  //  // ローカル変数の定義
  //  int local_va_num = this->m_lva_table.GetVariableNum();
  //  
  //  for( int i = 0; i < local_va_num; ++i )
  //  {
  //    CodeItemVariable const& va = m_lva_table.GetVariable( i );
  //    wc(va.GetType()) ^va.GetName();
  //    
  //    if( va.GetSemantics().GetLength() > 0 )
  //    {
  //      wc(" = ")^ va.GetSemantics();
  //    }
  //    gc()^ End();
  //  }
  //  
  //  // 関数呼び出し
  //  CPL_LOOP2( frgm_num, frgm_idx )
  //  {
  //    CodeFragment::SpRefCnt sp_frgm = in_SCFC.GetFragment( frgm_idx );
  //    sp_frgm->CallImplement();
  //  }
  //}
}

/*
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// グローバル変数の追加
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool ShaderCode::AddGlobalVariable( char_cptr type, char_cptr name )
{
  // 既に同じ名前があるかどうか検査
  int gva_num = this->m_GVATable.GetNum();
  for( int i = 0; i < gva_num; ++i ){
    if( m_GVATable[ i ].name == name ){
      return false;
    }
  }

  // 追加
  m_GVATable.AddEnd( VariableInfo( type, name ) );

  return true;
}*/

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 頂点シェーダフラグメントテーブルの作成関数
// ※ in_ptr_VSFTs_end はテーブルの最後の要素＋１のアドレスであること
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//CodeFragmentList const**
//  ShaderCode::zzf_setupFragmentTable_(
//    CodeFragmentList const&  in_SFL,
//    CodeFragmentList const** in_pp_SFL_st,
//    CodeFragmentList const** in_pp_SFL_end )
//{
//  CodeFragmentList const* in_ptr_SFL = &in_SFL;
//  CodeFragmentList const** pp_SFL = in_pp_SFL_st;
//  for(; pp_SFL < in_pp_SFL_end; ++pp_SFL )
//  {
//    if( in_ptr_SFL->Get() )
//    {
//      (*pp_SFL) = in_ptr_SFL;
//    }
//    else
//    {
//      break;
//    }
//
//    if( in_ptr_SFL->GetNodeNext() )
//    {
//      in_ptr_SFL = in_ptr_SFL->GetNodeNext();
//    }
//    else
//    {
//      break;
//    }
//  }
//
//  return pp_SFL;
//}


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