/// This file is part of the X3DToolKit library
/// Copyright (C) 2002-2004  Yannick Le Goc (legoc@imag.fr)

/// http://artis.imag.fr/Members/Yannick.Legoc/X3D/

/// This library is free software; you can redistribute it and/or
/// modify it under the terms of the GNU Lesser General Public
/// License as published by the Free Software Foundation; either
/// version 2.1 of the License, or (at your option) any later version.

/// This library is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
/// Lesser General Public License for more details.

/// You should have received a copy of the GNU Lesser General Public
/// License along with this library; if not, write to the Free Software
/// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#ifndef X3DTK_TYPELIST_H
#define X3DTK_TYPELIST_H

#include "X3DBaseTypes.h"

namespace X3DTK {

#ifdef TEMPLATE_SPECIALIZATION_SUPPORTED

////////////////////////////////////////////////////////////////////////////////
/// tlist

/*! \brief Class declared in <b><X3DTK/kernel.h></b> providing a type list used for
 * template metaprogramming. This class has only a compilation life.
 *
 *  \ingroup base
 */

template<class H, class T = nil>
struct tlist
{
  /// Head type provided for convenience.
  typedef H head_type;
  /// Tail type provided for convenience.
  typedef T tail_type;
};

#ifndef DOXYGEN

////////////////////////////////////////////////////////////////////////////////
/// findIn

template<class TL, class F> struct findIn;

template<class H, class T, class F>
struct findIn<tlist<H, T>, F>
{
  enum {result = findIn<T, F>::result};
};

template<class T, class F>
struct findIn<tlist<F, T>, F>
{
  enum {result = true};
};

template<class T>
struct findIn<nil, T>
{
  enum {result = false};
};

#endif

////////////////////////////////////////////////////////////////////////////////
/// clist

template<class TL> class clist;

/*! \brief Class declared in <b><X3DTK/kernel.h></b> providing an automatic class
 * generation from a tlist. 
 *
 *  \ingroup base
 */

template<class H, class T>
class clist<tlist<H, T> > : public H, public clist<T>
{
public:
  template<class F, bool optional>  
  F &get();

  template<class F, bool optional>  
  const F &get() const;

  template<class F>  
  inline static bool find();
};

#ifndef DOXYGEN

template<class H>
class clist<tlist<H, nil> > : public H
{
public:
  template<class F, bool optional>  
  F &get();

  template<class F, bool optional>  
  const F &get() const;
  
  template<class F>  
  inline static bool find();
};

template<class T, class F, bool present, bool optional> struct Get;

template<class T, class F, bool optional>
struct Get<T, F, true, optional>
{
  inline static F &apply(clist<T> &t) 
  {
    return t;
  };
};

template<class T, class F>
struct Get<T, F, false, true>
{
  static F &apply(clist<T> &t) 
  {
    static F f;
    return f;
  };
};

template<class H, class T>
template<class F>
bool clist<tlist<H, T> >::find()
{
  return findIn<tlist<H, T>, F>::result;
}

template<class H, class T>
template<class F, bool optional>
F &clist<tlist<H, T> >::get()
{
  return Get<tlist<H, T>, F, findIn<tlist<H, T>, F>::result, optional>::apply(*this);
}

template<class H, class T>
template<class F, bool optional>
const F &clist<tlist<H, T> >::get() const
{
  return Get<tlist<H, T>, F, findIn<tlist<H, T>, F>::result, optional>::apply(*this);
}


template<class H>
template<class F>
bool clist<tlist<H, nil> >::find()
{
  return findIn<tlist<H, nil>, F>::result;
}

template<class H>
template<class F, bool optional>
F &clist<tlist<H, nil> >::get()
{
  return Get<tlist<H, nil>, F, findIn<tlist<H, nil>, F>::result, optional>::apply(*this);
}

template<class H>
template<class F, bool optional>
const F &clist<tlist<H, nil> >::get() const
{
  return Get<tlist<H, nil>, F, findIn<tlist<H, nil>, F>::result, optional>::apply(*this);
}

#endif
#endif

}

#endif
