#include <dolfin.h>
#include <boost/numeric/ublas/matrix.hpp>
#include <unicorn/EquiAffineMap.h>
#include <unicorn/MeshQuality.h>

namespace dolfin { namespace unicorn
{

  // Sub domain for Dirichlet boundary condition
  class DirichletBoundary : public SubDomain
  {
  public:
    bool inside(const real* x, bool on_boundary) const
    {
      if(fabs(x[0] - 0.0) < 1.0e-8)
	return true;
      else
	return false;
    }
  };

  class MySource : public Function
  {
  public:
    MySource(Mesh& mesh) : Function(mesh)
    {
    }
    
    void eval(real* values, const real* x) const
    {
      int d = cell().dim();
      for(int i = 0; i < d; i++)
	values[i] = 0.0;

      values[1] = -1.0e1;
    }
  };

  class Density : public Function
  {
  public:
    Density(Mesh& mesh) : Function(mesh)
    {
    }
    
    void eval(real* values, const real* x) const
    {
      values[0] = 1.0;
    }
  };

  class InitialValue : public Function
  {
  public:
    InitialValue(Mesh& mesh) : Function(mesh)
    {
    }

    void eval(real* values, const real* x) const
    {
      real val = 0.0;

      int d = cell().dim();
      int N = 2 * d + d * d;

      for(int i = 0; i < N; i++)
      {
	if(i < d)
	  val = x[i];
	else if(i >= 2 * d)
	{
	  int ii = (i - 2 * d) % d;
	  int jj = (i - 2 * d) / d;

	  if(ii == jj)
	  {
	    val = 1.0;
	    //val = 0.0;
	  }
	  else
	  {
	    val = 0.0;
	  }
	}
	values[i] = val;
      }
    }
  };

  class MyBC : public Function
  {
  public:
    MyBC(Mesh& mesh) : Function(mesh)
    {
    }
    
    void eval(real* values, const real* x) const
    {
      int d = mesh().topology().dim();

      for(int i = 0; i < d; i++)
      {
	if(i < 2 * d && x[0] < 1e-8)
	{
	  values[i] = 0.0;
	}
      }
    }
  };

  void transform(Mesh& mesh)
  {
    for (VertexIterator n(mesh); !n.end(); ++n)
    {
      Vertex& vertex = *n;
      Point p = vertex.point();
      
      MeshGeometry& geometry = mesh.geometry();
      
/*       real xold = p.x(); */
/*       real yold = p.y(); */
      
      //geometry.x(vertex.index(), 0) += 1.5 * yold * xold;
      geometry.x(vertex.index(), 0) *= 2.0;
    }
  }
}}
