#ifndef AMDIS_PROBLEMIMPLICIT_H
#define AMDIS_PROBLEMIMPLICIT_H

#include "AMDiS.h"
#include "ProblemScal.h"
#include "ProblemVec.h"

namespace AMDiS {
  class ProblemImplicitScal : public ProblemScal 
  {

  public:
    ProblemImplicitScal(std::string name, ProblemIterationInterface* pis = NULL)
      : ProblemScal(name, pis),
        r(NULL),
        phi1(NULL),
        phi2(NULL),
        levelSet(NULL)
        {}

    /// @return: true if implicit mesh type is ok (see below) and false in 
    /// all other cases
    /// initfile entries: 
    /// name+"->implicit mesh->mesh file": name of serialized mesh
    /// name+"->implicit mesh->dof file": name of serialized dofvector
    /// name+"->implicit mesh->type": type of serialized dofvector. 
    /// type can be: 
    ///    0: dofvector is a signed distance r
    ///    1: dofvector is a phasefield phi=0.5*(1-tanh(3*r/eps))
    ///    2: dofvector is a phasefield phi=0.5*(1+tanh(3*r/eps))
    /// assumes:
    ///    a) already created, but not yet initialized mesh
    ///    b) already created feSpace
    virtual bool createImplicitMesh();
    virtual void initialize(Flag initFlag, ProblemScal *adoptProblem = NULL,
			    Flag adoptFlag = INIT_NOTHING);

  protected:
    /// DOFVector for a signed distance
    DOFVector< double > *r;

    /// DOFVector for the phasefield function 0.5*(1-tanh(3*r/eps))
    DOFVector< double > *phi1;

    /// DOFVector for the phasefield function 0.5*(1+tanh(3*r/eps))
    DOFVector< double > *phi2;

    /// DOFVector for the levelset function 
    /// (levelSet(x): x \in \Omega: 1, x \not \in Omega: -1, x \in \Gamma: 0)
    DOFVector< double > *levelSet;

  };

  class ProblemImplicitVec : public ProblemVec
  {
  public:
    ProblemImplicitVec(std::string name, 
		    ProblemIterationInterface* problem = NULL)
      : ProblemVec(name, problem),
	r(0),
	phi1(0),
	phi2(0),
	levelSet(0)
        {}

    virtual bool createImplicitMesh();
    virtual void initialize(Flag initFlag, ProblemScal *adoptProblem=NULL, 
		            Flag adoptFlag = INIT_NOTHING);

  protected:

    bool createImplicitMesh(int p); 
    /// DOFVector for a signed distance
    std::vector< DOFVector< double >* > r;

    /// DOFVector for the phasefield function 0.5*(1-tanh(3*r/eps))
    std::vector< DOFVector< double >* > phi1;

    /// DOFVector for the phasefield function 0.5*(1+tanh(3*r/eps))
    std::vector< DOFVector< double >* > phi2;

    /// DOFVector for the levelset function 
    /// (levelSet(x): x \in \Omega: 1, x \not \in Omega: -1, x \in \Gamma: 0)
    std::vector< DOFVector< double >* > levelSet;

  };
}
#endif