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

#pragma once

#include "CPL_DX_Shader_CodeItem.h"

namespace CPL {
namespace DX {
namespace Shader {


// _____________________________________________________________________________
/// @brief シェーダーコード変数フラグメント定義用クラス。
///
// *****************************************************************************
class CodeItemVariable
  : public CodeItem
{
  friend class CodeItemVariable;

  using type_this = CodeItemVariable;
protected:
  css16       m_strage_class;
  css16       m_type_modifier;
  css16       m_input_modifier;
  css16       m_interpolate_modifier;
  css128      m_type;
  css128      m_name;
  int         m_name_No;
  int         m_array_num; // 1以下の場合、配列として扱わない。
  css32       m_semantic;
  int         m_semantic_No;
  css128      m_annotation;
  css128      m_initial_value;
  css16       m_packoffset;
  css16       m_register;
  CodeItemSet m_item_set;

  bool zzf_SetParameter( cref<Parameter_> in_param );
public:
  CodeItemVariable();
  CodeItemVariable( cref<type_this> in_civ )
  {
    *this = in_civ;
  }
  CodeItemVariable( cref<Parameter_> in_param );
  virtual ~CodeItemVariable();

  char_cptr GetStrageClass()    const { return m_strage_class;         }
  char_cptr GetTypeModifier()   const { return m_type_modifier;        }
  char_cptr GetInputModifier()  const { return m_input_modifier;       }
  char_cptr GetInterpolation()  const { return m_interpolate_modifier; }
  char_cptr GetType()           const { return m_type;                 }
  char_cptr GetName()           const { return m_name;                 }
  char_cptr GetSemantic()       const { return m_semantic;             }
  char_cptr GetAnnotation()     const { return m_annotation;           }
  char_cptr GetInitilize()      const { return m_initial_value;        }
  char_cptr GetPackOffset()     const { return m_packoffset;           }
  char_cptr GetRegister()       const { return m_register;             }
  char_cptr GetStatementBlock() const { return "";                     }
  int       GetNum()            const { return m_array_num;            }

  bool operator == ( cref<CodeItem> in_item ) const;
  bool operator != ( cref<CodeItem> in_item ) const
  {
    return !(*this == in_item);
  }
  type_this& operator = ( cref<type_this> in_variable );

  // _____________________________________________________________________________
  /// @brief 変数用コードアイテム登録
  /// 
  /// @param[in] in_item : 変数用のコードアイテムオブジェクトを指定します。
  /// 
  /// @retval true  : 登録成功
  /// @retval false : 登録失敗
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_Item>
  bool Entry( cref<T_Item> in_item )
  {
    return m_item_set.Entry( in_item );
  }

  // _____________________________________________________________________________
  /// @brief 変数用コードアイテム登録
  /// 
  /// @param[in] in_item : 変数用のコードアイテムオブジェクトを指定します。
  /// 
  /// @return 自身への参照を返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_Item>
  type_this& operator << ( cref<T_Item> in_item )
  {
    Entry( in_item );
    return *this;
  }

  // _____________________________________________________________________________
  /// @copydoc operator<<(cref<T_Item>)
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_Item>
  type_this& operator , ( T_Item const& in_item )
  {
    Entry( in_item );
    return *this;
  }

  // _____________________________________________________________________________
  /// @brief 保持アイテム数の取得
  /// 
  /// @return 保持アイテム数を返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  size_t GetItemNum() const
  {
    return m_item_set.GetItemNum();
  }

  // _____________________________________________________________________________
  /// @brief コードアイテムの取得
  /// 
  /// @param[in] in_index
  ///   : 取得するコードアイテムの位置（インデックス）を指定します。
  /// 
  /// @return 該当するアイテムを指すスマートポインタを返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  sdptr<CodeItem> GetItem( _in<int> in_index ) const
  {
    return m_item_set.GetItem( in_index );
  }

  // _____________________________________________________________________________
  /// @copydoc CodeItemSet::FindItem(cref<Parameter_>,cref<Parameter_>,cref<Parameter_>)const
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_Item>
  std::shared_ptr<T_Item>
    FindItem
      ( cref<Parameter_> in_param0
      , cref<Parameter_> in_param1 = NonParam_("")
      , cref<Parameter_> in_param2 = NonParam_("")
      ) const
  {
    return m_item_set.FindItem<T_Item>( in_param0, in_param1, in_param2 );
  }

  type_this& operator = ( StrageClass   const& in_strage_class   ){ m_strage_class  .Reset( in_strage_class   ); return *this; }
  type_this& operator = ( TypeModifier  const& in_type_modifier  ){ m_type_modifier .Reset( in_type_modifier  ); return *this; }
  type_this& operator = ( InputModifier const& in_input_modifier ){ m_input_modifier.Reset( in_input_modifier ); return *this; }
  type_this& operator = ( Type          const& in_type           ){ m_type          .Reset( in_type           ); return *this; }
  type_this& operator = ( Name          const& in_name           ){ m_name          .Reset( in_name           ); return *this; }
  type_this& operator = ( Semantic      const& in_semantic       ){ m_semantic      .Reset( in_semantic       ); return *this; }
  type_this& operator = ( Annotation    const& in_annotations    ){ m_annotation    .Reset( in_annotations    ); return *this; }
  type_this& operator = ( Initialize    const& in_value_of_initial  ){ m_initial_value .Reset( in_value_of_initial  ); return *this; }
  type_this& operator = ( PackOffset    const& in_packoffset     ){ m_packoffset    .Reset( in_packoffset     ); return *this; }
  type_this& operator = ( Register      const& in_register       ){ m_register      .Reset( in_register       ); return *this; }
  type_this& operator = ( Num           const& in_num            ){ m_array_num = in_num.num; return *this; }
  
  type_this& operator << ( StrageClass   const& in_strage_class   ){ return (*this) = in_strage_class  ; }
  type_this& operator << ( TypeModifier  const& in_type_modifier  ){ return (*this) = in_type_modifier ; }
  type_this& operator << ( InputModifier const& in_input_modifier ){ return (*this) = in_input_modifier; }
  type_this& operator << ( Type          const& in_type           ){ return (*this) = in_type          ; }
  type_this& operator << ( Name          const& in_name           ){ return (*this) = in_name          ; }
  type_this& operator << ( Semantic      const& in_semantic       ){ return (*this) = in_semantic      ; }
  type_this& operator << ( Annotation    const& in_annotations    ){ return (*this) = in_annotations   ; }
  type_this& operator << ( Initialize    const& in_value_of_initial  ){ return (*this) = in_value_of_initial ; }
  type_this& operator << ( PackOffset    const& in_packoffset     ){ return (*this) = in_packoffset    ; }
  type_this& operator << ( Register      const& in_register       ){ return (*this) = in_register      ; }
  type_this& operator << ( Num           const& in_num            ){ return (*this) = in_num           ; }

  type_this& operator , ( StrageClass   const& in_strage_class   ){ return (*this) = in_strage_class  ; }
  type_this& operator , ( TypeModifier  const& in_type_modifier  ){ return (*this) = in_type_modifier ; }
  type_this& operator , ( InputModifier const& in_input_modifier ){ return (*this) = in_input_modifier; }
  type_this& operator , ( Type          const& in_type           ){ return (*this) = in_type          ; }
  type_this& operator , ( Name          const& in_name           ){ return (*this) = in_name          ; }
  type_this& operator , ( Semantic      const& in_semantic       ){ return (*this) = in_semantic      ; }
  type_this& operator , ( Annotation    const& in_annotations    ){ return (*this) = in_annotations   ; }
  type_this& operator , ( Initialize    const& in_value_of_initial  ){ return (*this) = in_value_of_initial ; }
  type_this& operator , ( PackOffset    const& in_packoffset     ){ return (*this) = in_packoffset    ; }
  type_this& operator , ( Register      const& in_register       ){ return (*this) = in_register      ; }
  type_this& operator , ( Num           const& in_num            ){ return (*this) = in_num           ; }

  //void  SetAllParameter( cref<Parameter_> in_param );

  void  MakeCode( rout<ss> out_buf, _in<eCreateType> in_create_type ) const;

};


template<int I>
class CodeItemVariableT
  : public CodeItemVariable
{
public:
  CodeItemVariableT(){}
  CodeItemVariableT( CodeItemVariableT const& in_civ )
    : CodeItemVariable( in_civ )
  {}
  ~CodeItemVariableT(){}

  CodeItemVariable& operator = ( Parameter_ const& in_param )
  {
    zzf_SetParameter( in_param );
    return *this;
  }
};


typedef CodeItemVariable                         CIVariable;
typedef CodeItemVariableT<eCodeItemType::Input > CIV_Input;
typedef CodeItemVariableT<eCodeItemType::Output> CIV_Output;


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