/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2013/10/09
/// 
/// @brief  選択テンプレート？
/// 
/// ****************************************************************************

#pragma once

#include "Array/CPL_Core_KeyArray.h"
#include "../Container/CPL_Core_Stack.h"
#include "../Container/List/CPL_Core_Tree.h"


namespace CPL {
namespace Core {


// _____________________________________________________________________________
/// @brief 選択テーブルクラス。
/// 
/// @tparam T_Key     : キーとなる型。
/// @tparam T_Type    : データの型。
/// @tparam T_TypePtr : T_Typeのポインタを指す型。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T_Key, class T_Type, class T_TypePtr = T_Type*>
class Selector
  : public Array::DynamicKey<T_Key,T_Type>
{
protected:
  size_t  m_select_index;

  typedef typename std::remove_pointer<T_TypePtr>::type TYPE;

public:
  TYPE*       GetActive()       { return &(*this)[ m_select_index ]; }
  TYPE const* GetActive() const { return &(*this)[ m_select_index ]; }
  T_Key       GetActiveKey(){ return this->m_table[ m_select_index ].item0; }
  bool        Select( T_Key in_key );

  Selector() : m_select_index(0) {}
  virtual ~Selector(){}
};


// _____________________________________________________________________________
/// @brief 選択。
/// 
/// @retval true  : 該当あり。
/// @retval false : 該当なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T_Key, class T_Type, class T_TypePtr> inline
bool Selector<T_Key,T_Type,T_TypePtr>::Select( T_Key in_key )
{
  m_select_index = this->FindIndex( in_key );
  if( m_select_index < 0 )
  {
    m_select_index = 0;
    return false;
  }
  return true;
}



// _____________________________________________________________________________
/// @brief スタック付き選択テーブル。
/// 
/// @tparam T_Key  : キーとなる型。
/// @tparam T_Type : データの型。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T_Key, class T_Type>
class SelectorStack
  : public Selector<T_Key,T_Type>
{
protected:
  Stack<T_Type*> m_stack;

public:
  bool Call( T_Key in_key );
  bool Return();

  SelectorStack() : m_stack(4) {}
  SelectorStack( int block ) : m_stack(block) {}
  virtual ~SelectorStack(){}
};


// _____________________________________________________________________________
/// @brief 現在の選択中のものをスタックにプッシュしてキーに該当するものを選択。
/// 
/// @retval true  : 該当あり。
/// @retval false : 該当なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T_Key, class T_Type> inline
bool SelectorStack<T_Key,T_Type>::Call( T_Key in_key )
{
  T_Type* ptr = Find( in_key );

  if( ptr == nullptr )
  {
    return false;
  }

  return m_stack.Push( ptr );
}


// _____________________________________________________________________________
/// @brief Callで呼び出す一つ前に戻す。
/// 
/// @retval true  : スタック登録あり。
/// @retval false : スタック登録なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T_Key, class T_Type> inline
bool SelectorStack<T_Key,T_Type>::Return()
{
  if( m_stack.Pop() )
  {
    this->m_select_index = m_stack.GetNum()-1;
    return true;
  }
  else
  {
    return false;
  }
}




} // namespace Core
} // namespace CPL
