#if defined WIN32
#pragma warning( disable : 4290 )
#endif

#include "Test.h"

#include "Prototype_repository.h"
#include "Create.h"

#include <iostream>

namespace MM
{

class Prototype_repository_test : public Test
{
    int                     counter_;
    Prototype_repository    *_link_;

public:
    Prototype_repository_test( const Text & suite_name ) 
        : Test( suite_name ), 
          counter_(0)
    {
    }

    void run()
    {
        test_1();           count_tests();
        //test_arg();    count_tests();
        //test_polymorphism();    count_tests();
        test_nil();         count_tests();
    }

    class A
    {
    public:
        virtual A *         clone() const { return new A; }
    };

    class B 
    {
        int                 value_;
        B(int value) : value_(value) { }

    public:
        B() : value_(0) { }
        virtual B *         clone () const          {return new B (value_);}
        virtual B *         clone (int value) const {return new B (value);}
        virtual int         value () const          {return value_;}
    };

    class C 
    {
        int                 value1_;
        double              value2_;

    public:
        C(int value1, double value2) : value1_(value1), value2_(value2) { }
        virtual C *         clone () const    {return new C (value1_, value2_);}

        virtual C *         clone (int value1, double value2) const
        {
            return new C (value1, value2);
        }

        virtual int         value1 () const            {return value1_;}
        virtual double      value2 () const            {return value2_;}

    private:
        C(const C &);
        void operator = (const C &);
    };

    class D : public C
    {
    public:
        D(int value1, double value2) : C(value1, value2) { }
        //virtual Cloneable * clone () const  {return new D (value1(), value2());}
        
        virtual C *         clone (int value1, double value2, float value3) const
        {
            return new D ((int)value3*value1, value3*value2);
        }

        virtual int         value1 () const            {return C::value1();}
        virtual double      value2 () const            {return C::value2();}

    private:
        D(const D &);
        void operator = (const D &);
    };

    void test_1()
    {
        Prototype_repository::singleton().adopt (new A);

        A* a1 = prototype<A>().clone();
        A* a2 = prototype<A>().clone();
        A* clone1 = (A*)a1->clone();
        A* clone2 = (A*)a2->clone();

        TEST ("", &a1 != &a2);
        TEST ("", &prototype<A>() == &prototype<A>());

        delete a1;
        delete clone1;
        delete a2;
        delete clone2;
    }

    /*void test_arg()
    {
        Prototype_repository::singleton().adopt (new B);
        Prototype_repository::singleton().adopt (new C(1, 2));
        Prototype_repository::singleton().adopt (new D(1, 2));

        B* b     = create<B> (12345);
        B* b_clone = (B*)b->clone();

        TEST("", b->value() == 12345);
        TEST("", b_clone->value() == 12345);

        C* c     = create<C> ();

        TEST("", c->value1() == 1);
        TEST("", c->value2() == 2);

        D* d     = create<D> (3, 5., 2.);

        TEST("", d->value1() == 6);
        TEST("", d->value2() == 10);

        delete b;
        delete c;
        delete d;
        delete b_clone;
    }

    void test_polymorphism()
    {
        Prototype_repository::singleton().adopt (new D(10, 20), typeid(C));

        C *d = create<C> (3, 5);
        C *d2 = create<D> (3, 5, 2);

        std::cout << d->value1() << " " << d->value2() << std::endl;
        TEST("", d->value1() == 3);
        TEST("", d->value2() == 5);

        std::cout << d2->value1() << " " << d2->value2() << std::endl;
        TEST("", d2->value1() == 6);
        TEST("", d2->value2() == 10);

        delete d;
        delete d2;
    }//*/

    void test_nil()
    {
        A a;
        A &ref = a;
        A &bad_ref = nil <A> ();

        TEST ("", &a == &ref);
        TEST ("", &a != &bad_ref);
        TEST ("", &nil <A> () == &bad_ref);

        //bad_ref.clone();
    }
};

Prototype_repository_test test_prototype_repository ("correctness");

//Prototype_repository_test prototype_repository_test("demo");

}//MM

