// list_generator.h        -*-C++-*-
// -------------------------------------------------------
// Algorithm Library Design, Juha K"arkk"ainen, 06/06/2003
// A list generator described in
//   "Generative Programming: Methods, Tools, and Applications"
//   by Krzysztof Czarnecki and Ulrich W. Eisenecker
//   Addison-Wesley, 2000
// with minor changes.
//
// Solution for Exercise 5. Roman Dementiev, 20/06/2003

#include "list_components.h"

//----------------------------------------------------------------------
// Meta IF
//----------------------------------------------------------------------

template <bool condition, class Then, class Else>
struct IF {
  typedef Then RET;
};

template <class Then, class Else>
struct IF<false, Then, Else> {
  typedef Else RET;
};

//----------------------------------------------------------------------
// Configuration DSL
//----------------------------------------------------------------------

// avoid namespace pollution
namespace DSL {
    enum Ownership {ext_ref, own_ref, cp};
    enum Morphology {mono, poly};
    enum CounterFlag {with_counter, no_counter};
    enum TracingFlag {with_tracing, no_tracing};


    struct DefaultConfig {
        static const Ownership   ownership    = cp;
        static const Morphology  morphology   = mono;
        static const CounterFlag counter_flag = no_counter;
        static const TracingFlag tracing_flag = no_tracing;
        typedef int LengthType;
    };
    
    struct DefaultConfigSetter : virtual public DefaultConfig {};
    
    template< Ownership _ownership >
    struct Ownership_is : virtual public DefaultConfig {
        struct owner_tag {};
        static const Ownership ownership  = _ownership;
    };
    
    template< Morphology _morphology >
    struct Morphology_is : virtual public DefaultConfig {
        struct morph_tag {};
        static const Morphology morphology = _morphology;
    };
    
    template< CounterFlag _counter_flag, typename lengthtype = int >
    struct CounterFlag_is : virtual public DefaultConfig {
        struct counter_tag {};
        static const CounterFlag counter_flag  = _counter_flag;
        typedef lengthtype LengthType; // gets also set to default = int, if not needed. anyway ...
    };
    
    template< TracingFlag _tracing_flag >
    struct TracingFlag_is : virtual public DefaultConfig {
        struct tracing_tag {};
        static const TracingFlag tracing_flag = _tracing_flag;
    };

    template< class Base, int D >
    struct Discriminator : public Base {};

}; // end namespace

typedef DSL::Ownership_is< DSL::ext_ref > ext_ref;
typedef DSL::Ownership_is< DSL::own_ref > own_ref;
typedef DSL::Ownership_is< DSL::cp >      cp;

typedef DSL::Morphology_is< DSL::mono > mono;
typedef DSL::Morphology_is< DSL::poly > poly;

template< typename lengthtype = int >
struct with_counter : public DSL::CounterFlag_is< DSL::with_counter, lengthtype > {};
typedef DSL::CounterFlag_is< DSL::no_counter   > no_counter;

typedef DSL::TracingFlag_is< DSL::with_tracing > with_tracing;
typedef DSL::TracingFlag_is< DSL::no_tracing   > no_tracing;



//----------------------------------------------------------------------
// List generator
//----------------------------------------------------------------------

template <
  class ElementType_,
  class Config1Setter = DSL::Discriminator< DSL::DefaultConfigSetter, 1 >,
  class Config2Setter = DSL::Discriminator< DSL::DefaultConfigSetter, 2 >,
  class Config3Setter = DSL::Discriminator< DSL::DefaultConfigSetter, 3 >,
  class Config4Setter = DSL::Discriminator< DSL::DefaultConfigSetter, 4 >
>
class LIST_GENERATOR
{
    class ListConfig : public Config1Setter,
                       public Config2Setter,
                       public Config3Setter,
                       public Config4Setter
    {};
    typedef typename ListConfig::LengthType LengthType_;
public:

  // forward declaration of the configuration repository
  struct Config;

private:

  enum {
    is_copy      = ListConfig::ownership    == DSL::cp,
    is_own_ref   = ListConfig::ownership    == DSL::own_ref,
    is_mono      = ListConfig::morphology   == DSL::mono,
    has_counter  = ListConfig::counter_flag == DSL::with_counter,
    does_tracing = ListConfig::tracing_flag == DSL::with_tracing
  };

  typedef typename
  IF<is_copy || is_own_ref,
     ElementDestroyer<ElementType_>,
     EmptyDestroyer<ElementType_>
  >::RET Destroyer_;

  typedef typename
  IF<is_mono,
     DynamicTypeChecker<ElementType_>,
     EmptyTypeChecker<ElementType_>
  >::RET TypeChecker_;

  typedef typename
  IF<is_copy,
     typename 
     IF<is_mono,
	MonomorphicCopier<ElementType_>,
	PolymorphicCopier<ElementType_> >::RET,
     EmptyCopier<ElementType_>
  >::RET Copier_;

  typedef typename
  IF<is_copy,
     const ElementType_,
     ElementType_
  >::RET ElementArgumentType_;

  typedef PtrList<Config> BasicList;

  typedef typename
  IF<has_counter,
     LengthList<BasicList>,
     BasicList
  >::RET OptLengthList;

  typedef typename
  IF<does_tracing,
     TracedList<OptLengthList>,
     OptLengthList
  >::RET List;

public:

  typedef List RET;

  struct Config {
    typedef ElementType_           ElementType;
    typedef ElementArgumentType_   ElementArgumentType;
    typedef Copier_                Copier;
    typedef Destroyer_             Destroyer;
    typedef TypeChecker_           TypeChecker;
    typedef LengthType_            LengthType;

    typedef RET                    FinalListType;
  };

};

