// $Id: grid.hh,v 1.5 2003/02/10 18:48:18 robertk Exp $

#ifndef DUNE_GRID_HH
#define DUNE_GRID_HH

#include <assert.h>

#include <string>
#include <vector>

#include <iostream>
#include <iterator>
#include <array.hh>

using namespace std;

namespace Dune {

  template <class BASE>  class LevelAccess;
  /**
     The abstract definition of a grid
  */
  template <class BASE>
  class Grid {
  public: 


    class GetAccess
    {
    public:
      typedef LevelAccess < typename BASE::FACEACCESS > FACEACCESS;
      typedef typename BASE::GetAccess BASEga;

      GetAccess () {};
      GetAccess (const GetAccess &ga)
      {

      };
      
      
      FACEACCESS getFaceAccess()
      {
        return child().getFaceAccess();   
      }
    private:  
      BASEga& child() { return static_cast<BASEga&>(*this); };
      const BASEga& constChild() const
      { return static_cast<const BASEga&>(*this); };
    }; // end GetAccess 
    
  private:
    /* Barton-Nackman */
    BASE& child()  {return static_cast<BASE&>(*this);};
    const BASE& constChild() const {return static_cast<const BASE&>(*this);};
  public:
    
    GetAccess& getAccess()
    {
      return child().getAccess();
    }

  }; // end Grid


  /// interface Grid Access
  template <class BASE>
  class LevelAccess 
  {
  
    typedef int level;
  public:      
    LevelAccess( ) { };
    LevelAccess( const LevelAccess &L)
    {
      cout << "Copy LevelAccess \n";
      child() = constCastToBase(L);
    }
    
    /// interface Element 
    class Element
    {
    public:
      typedef typename BASE::Element BASEel;
      typedef typename BASE::NEIGHtype BASEneigh;
      typedef typename BASE::VERTEXtype VERTEXtype;
    public:
      Element() {};
      Element(const Element &el)
      {
        child() = constCastToBase(el);
      };

      int getElNum()
      {
        return child().getElNum();
      };
  
      VERTEXtype vertex()
      {
        return child().vertex();
      };

      void printVertex()
      {
        child().printVertex();
        //child().printElInfo();
      }

      BASEneigh* getNeighbours(int neigh)
      {
        return (child().getNeighbours(neigh));
      };

    private:
      BASEel& child() { return static_cast<BASEel&>(*this); };
      const BASEel& constChild() const
      { return static_cast<const BASEel&>(*this); };
      BASEel& castToBase(Element &e) 
      {
        return static_cast<BASEel&>(e);
      };

    }; // end Element

  public:
    /* grid::iterator */
    class Iterator {  
    public:
      typedef typename BASE::Iterator BASEit;

    public:
      Iterator () {   };
    
      Iterator( const Iterator &I)
      {
        cout << "Copy LevelAccess::Iterator \n";
        child() = constCastToBase(I);
      }
   
      BASEit& child() { return static_cast<BASEit&>(*this); };
      const BASEit& constChild() const
      { return static_cast<const BASEit&>(*this); };
      
      const BASEit& constCastToBase(const Iterator &I) 
      {
        return static_cast<const BASEit&>(I);
      };

      BASEit& castToBase(Iterator &I) 
      {
        return static_cast<BASEit&>(I);
      };
      
      Element* operator ->()  { return child().operator->(); };
     
      Element& operator *()  
      {   
        return (*child()); 
      };

      Element cloneObject() const { return constChild().cloneObject(); };
      BASEit& operator ++() { return ++child(); };
      bool operator ==(Iterator& I) 
      { 
        return child()==castToBase(I); 
      };

      bool operator !=(Iterator& I)  
      { 
        return !(child()==castToBase(I)); 
      };
    
    };  /* end grid::Iterator */
    
  private:
    BASE& child() { return static_cast<BASE&>(*this); };
    const BASE& constChild() const
    { return static_cast<const BASE&>(*this); };
    BASE& castToBase(LevelAccess &L) 
    {
      return static_cast<BASE&>(L);
    };
      
    const BASE& constCastToBase(const LevelAccess &L) 
    {
      return static_cast<const BASE&>(L);
    };
      

  public:
    //! get an Iterator pointing to the first index
    Iterator begin(int l)  
    { 
      cout << "LevelAccess::Iterator begin\n";
      return child().begin(l); 
    };

    //! get an iterator pointing behind the last index
    Iterator end(int l)  
    { 
      return child().end(l); 
    };
    
    Iterator firstChild(int l,Element *el = NULL)  
    { 
      cout << "LevelAccess::Iterator begin\n";
      return child().firstChild(l,el); 
    };

    //! get an iterator pointing behind the last index
    Iterator lastChild(int l,Element *el = NULL)  
    { 
      return child().lastChild(l,el); 
    };
    
  }; // class LevelAccess

 
}; // namespace Dune

#endif // DUNE_GRID_HH
