#include <dolfin.h>

namespace dolfin
{

  // Sub domain for Dirichlet boundary condition
  class DirichletBoundary : public SubDomain
  {
  public:
    bool inside(const real* x, bool on_boundary) const
    {
      return false && on_boundary;
    }
  };

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

    void eval(real* values, const real* x) const
    {
      if(x[0] - t < -M_PI / 2.0)
      {
	values[0] = -1.0;
      }
      else if(x[0] - t > M_PI / 2.0)
      { 
	values[0] = 1.0;
      }
      else
      {
	values[0] = sin(x[0] - t);
      }
    }

    real t;
  };

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

    void eval(real* values, const real* x) const
    {
      for(int i = 0; i < 2; i++)
      {
	if(i == 0)
	{
	  values[i] = 1.0;
	}
	else
	{
	  values[i] = 0.0;
	}
      }
    }
  };
  
  class InitialValue : public Function
  {
  public:
    InitialValue(Mesh& mesh) : Function(mesh)
    {
    }
    
    void eval(real* values, const real* x) const
    {
      if(x[0] < -M_PI / 2.0)
      {
	values[0] = -1.0;
      }
      else if(x[0] > M_PI / 2.0)
      {
	values[0] = 1.0;
      }
      else
      {
	values[0] = sin(x[0]);
      }
    }
  };

  class MyBC : public Function
  {
  public:
    MyBC(Mesh& mesh) : Function(mesh)
    {
    }
    
    void eval(real* values, const real* x) const
    {
      // Homogenous Neumann
    }
  };

  void transform(Mesh& mesh)
  {
    for (VertexIterator n(mesh); !n.end(); ++n)
    {
      Vertex& vertex = *n;
      
      MeshGeometry& geometry = mesh.geometry();
      
      for(unsigned int i = 0; i < mesh.topology().dim(); i++)
      {
	if(i == 0)
	  geometry.x(vertex.index(), i) -= 0.5;
	if(i == 1)
	  geometry.x(vertex.index(), i) -= 0.5;
      }

      for(unsigned int i = 0; i < mesh.topology().dim(); i++)
      {
	if(i == 0)
	  geometry.x(vertex.index(), i) *= 20.0;
	if(i == 1)
	  geometry.x(vertex.index(), i) *= 20.0;
      }
    }
  }
}
