#include <stdio.h>
#include "exception.h"
#include "typeinfo.h"

#include "autodstry.c++"

class TestException1 : public exception
{
  public:

    TestException1();
    TestException1(TestException1 const&);
    ~TestException1();

    TestException1& operator=(TestException1 const&);

    virtual char const* what() const;

    RTTI_SCAFFOLDING_DECL
};

TestException1::TestException1()
  { printf("TestException1::TestException1()\n"); }

TestException1::TestException1(TestException1 const& rhs)
  : exception(rhs)
  { printf("TestException1::TestException1(TestException1 const&)\n"); }

TestException1::~TestException1()
  { printf("TestException1::~TestException1\n"); }

TestException1& TestException1::operator=(TestException1 const& rhs)
  {
    ((exception&)*this) = rhs;
    return *this;
  }

char const* TestException1::what() const
  { return "TestException1"; }

RTTI_SCAFFOLDING_DEFN_1(TestException1, exception)



class TestException2 : public exception
{
  public:

    TestException2();
    TestException2(TestException2 const&);
    ~TestException2();

    TestException2& operator=(TestException2 const&);

    virtual char const* what() const;

    RTTI_SCAFFOLDING_DECL
};

TestException2::TestException2()
  { printf("TestException2::TestException2()\n"); }

TestException2::TestException2(TestException2 const& rhs)
  : exception(rhs)
  { printf("TestException2::TestException2(TestException2 const&)\n"); }

TestException2::~TestException2()
  { printf("TestException2::~TestException2\n"); }

TestException2& TestException2::operator=(TestException2 const& rhs)
  {
    ((exception&)*this) = rhs;
    return *this;
  }

char const* TestException2::what() const
  { return "TestException2"; }

RTTI_SCAFFOLDING_DEFN_1(TestException2, exception)



class TestClass
{
  public:

    TestClass(int n);
    ~TestClass();

  private:

    int n_;
};

TestClass::TestClass(int n)
  : n_(n)
  { printf("TestClass::TestClass():  %i\n", n_); }

TestClass::~TestClass()
  { printf("TestClass::~TestClass(): %i\n", n_); }


inline void destroy(TestClass* t)
  { t->~TestClass(); }


void foo()
{
  printf("foo()\n");

  TestClass test_object_1(2);
  DESTROY_ON_THROW(test_object_1);

  try
  {
    TestClass test_object_2(3);
    DESTROY_ON_THROW(test_object_2);

    throw(TestException1());
  }
  BEGIN_HANDLERS
  catch(TestException1, ex)
  {
    printf("foo(): Caught a TestException1\n");

    int i = 1234;
    printf("i: %i\n", i);

    try
    {
      i *= 2;
      printf("i: %i\n", i);
      throw(TestException2());
    }
    BEGIN_HANDLERS
    catch(TestException2, ex)
    {
      printf("foo() inner: Caught a TestException2\n");

//      rethrow;
    }
    catch_DOTS
    {
      printf("foo() inner: Caught some other exception\n");
    }
    END_HANDLERS

    printf("foo() inner: Continue after TestException2\n");
    printf("i: %i\n", i);

    rethrow;
  }
  catch_DOTS
  {
    printf("foo(): Caught some other exception\n");
  }
  END_HANDLERS

  printf("foo(): Continue after TestException1\n");
}


int main()
{
  printf("main()\n");

  TestClass test_object_1(1);
  DESTROY_ON_THROW(test_object_1);

  try
  {
    foo();
  }
  BEGIN_HANDLERS
  catch(TestException1, ex)
  {
    printf("main(): Caught a TestException1\n");
    rethrow;
  }
  catch(TestException2, ex)
  {
    printf("main(): Caught a TestException2\n");
    rethrow;
  }
  catch_DOTS
  {
    printf("main(): Caught some other exception\n");
  }
  END_HANDLERS
}
