#include <cassert>
#include <iostream>
#include <vector>
using namespace std;

#include <fnobj.h>
#include <fnobjT.h>
#include <fnobjTfn.h>
#include <print.h>

#include <fnobjtest.h>



  class hat : public fnobj0<void>
  {
  public:
    void operator()() { cout << "hat" << endl; }
  };

  class hat2 : public fnobj0const<void>
  {
  public:
    void operator()() const { cout << "hat2 has const" << endl; }
  };

  class hat3 
  {
  public:

    void sumfunc()
      { cout << "hat3 sumfunc()" << endl; }

    void anotherone() const
      { cout << "hat3 anotherone() const" << endl; }
  };

 

void fnobjtest01()
{
  hat h1;
  
  cout << "Direct call to h1()" << endl;
  h1();

  cout << "call through functional pointer" << endl;

  fnobj0T<hat&,void> h2(h1);
  fnobj0<void> *ptr;
  ptr = & h2;
  (*ptr)();

  cout << "member function hat3::sumfunc made into a functional object" << endl;

  hat3 h3;
  //h3.sumfunc();
  fnobj0Tfn<hat3,void> ph3(h3,&hat3::sumfunc);

  ptr = &ph3;

  (*ptr)();

  cout << "Testing the const functional ojbect" << endl;
  fnobj0const<void> *ptr2 = new hat2();
  (*ptr2)();

  delete ptr2;

  cout << "Testing const with a function func. object." << endl;

  fnobj0constTfn<hat3,void> qh3(h3,&hat3::anotherone);
  ptr2 = &qh3; 
  (*ptr2)();
}


class datamodel
{
  int age;
public:

  int getAge() const
    { return age; }

  void setAge2(int const age_)
    { age=age_; }

};

class person
{
  int age;
public:
  void setAge(int const age_)
    { age=age_; }
  int getthepersonsAge() const 
    { return age; }
};

class people
{
public:

  fnobj1<void,int const> *setage;
  fnobj0const<int> *getage;

  people
  (
    fnobj1<void,int const> *setage_,
    fnobj0const<int> *getage_
  )
    : setage(setage_), getage(getage_) {}

  ~people()
    { delete setage; delete getage; }

  void set(const int k)
    { assert(setage!=0); (*setage)(k); }

  int get()
    { assert(getage!=0); return (*getage)(); }

};

void fnobjtest02()
{
  cout << "Demonstrating functional objects used to build a new type." << endl;
  cout << "  people is a mixed type.  This reminds me of Java interfaces" << endl;

  vector< people* > v;

  datamodel d1;
  d1.setAge2(15);

  person p1;
  p1.setAge(20);

//new fnobj1Tfn<datamodel,void,int const>(d1,&datamodel::setAge2);


  v.push_back
  ( 
    new people( 
      new fnobj1Tfn<datamodel,void,int const>(d1,&datamodel::setAge2),
      new fnobj0constTfn<datamodel,int>(d1,&datamodel::getAge)
    ) 
  );


  v.push_back
  ( 
    new people( 
      new fnobj1Tfn<person,void,int const>(p1,&person::setAge),
      new fnobj0constTfn<person,int>(p1,&person::getthepersonsAge)
    ) 
  );



  for (uint i=0; i<v.size(); ++i)
    cout << SHOW( v[i]->get() ) << endl;
  
  for (uint i=0; i<v.size(); ++i)
    delete v[i];
}





