/***************************************************************************
 FastSweepingMethod.h  -  description
 -------------------
 begin                : Jul 14, 2016
 copyright            : (C) 2017 by Tomas Oberhuber
 email                : tomas.oberhuber@fjfi.cvut.cz
 ***************************************************************************/

/* See Copyright Notice in tnl/Copyright */

#pragma once

//#include <TNL/Meshes/Grid.h>
//#include <TNL/Functions/Analytic/Constant.h>
//#include <TNL/Pointers/SharedPointer.h>
#include "tnlDirectEikonalMethodsBase.h"


template< typename Mesh,
        typename Communicator,
        typename Anisotropy = Functions::Analytic::Constant< Mesh::getMeshDimension(), typename Mesh::RealType > >
class FastSweepingMethod
{   
};

template< typename Real,
        typename Device,
        typename Index,
        typename Communicator,
        typename Anisotropy >
class FastSweepingMethod< Meshes::Grid< 1, Real, Device, Index >, Communicator, Anisotropy >
: public tnlDirectEikonalMethodsBase< Meshes::Grid< 1, Real, Device, Index > >
{
  //static_assert(  std::is_same< Device, TNL::Devices::Host >::value, "The fast sweeping method works only on CPU." );
  
  public:
    
    typedef Meshes::Grid< 1, Real, Device, Index > MeshType;
    typedef Real RealType;
    typedef Device DeviceType;
    typedef Index IndexType;
    typedef Anisotropy AnisotropyType;
    typedef tnlDirectEikonalMethodsBase< Meshes::Grid< 1, Real, Device, Index > > BaseType;
    using MeshPointer = Pointers::SharedPointer<  MeshType >;
    using AnisotropyPointer = Pointers::SharedPointer< AnisotropyType, DeviceType >;
    
    
    using typename BaseType::InterfaceMapType;
    using typename BaseType::MeshFunctionType;
    using typename BaseType::InterfaceMapPointer;
    using typename BaseType::MeshFunctionPointer;
   
    
    FastSweepingMethod();
    
    const IndexType& getMaxIterations() const;
    
    void setMaxIterations( const IndexType& maxIterations );
    
    void solve( const MeshPointer& mesh,
            MeshFunctionPointer& Aux,
            const AnisotropyPointer& anisotropy,
            MeshFunctionPointer& u );
    
    
    protected:
      
      const IndexType maxIterations;
};

template< typename Real,
        typename Device,
        typename Index,
        typename Communicator,
        typename Anisotropy >
class FastSweepingMethod< Meshes::Grid< 2, Real, Device, Index >, Communicator, Anisotropy >
: public tnlDirectEikonalMethodsBase< Meshes::Grid< 2, Real, Device, Index > >
{
  //static_assert(  std::is_same< Device, TNL::Devices::Host >::value, "The fast sweeping method works only on CPU." );
  
  public:
    
    typedef Meshes::Grid< 2, Real, Device, Index > MeshType;
    typedef Real RealType;
    typedef Device DeviceType;
    typedef Index IndexType;
    typedef Anisotropy AnisotropyType;
    typedef tnlDirectEikonalMethodsBase< Meshes::Grid< 2, Real, Device, Index > > BaseType;
    typedef Communicator CommunicatorType;
    typedef Containers::StaticVector< 2, Index > StaticVector;
    
    using MeshPointer = Pointers::SharedPointer<  MeshType >;
    using AnisotropyPointer = Pointers::SharedPointer< AnisotropyType, DeviceType >;
    using MPI = Communicators::MpiCommunicator;
    
    using typename BaseType::InterfaceMapType;
    using typename BaseType::MeshFunctionType;
    using typename BaseType::InterfaceMapPointer;
    using typename BaseType::MeshFunctionPointer;
    using typename BaseType::ArrayContainer;
        
    FastSweepingMethod();
    
    const IndexType& getMaxIterations() const;
    
    void setMaxIterations( const IndexType& maxIterations );
    
    void solve( const MeshPointer& mesh,
            MeshFunctionPointer& Aux,
            const AnisotropyPointer& anisotropy,
            const MeshFunctionPointer& u );
    
    protected:
      
      const IndexType maxIterations;
    
      void setOverlaps( StaticVector& vecLowerOverlaps, StaticVector& vecUpperOverlaps,
              const MeshPointer& mesh);
      
      bool goThroughSweep( const StaticVector boundsFrom, const StaticVector boundsTo, 
              MeshFunctionType& aux, const InterfaceMapType& interfaceMap,
              const AnisotropyPointer& anisotropy );
      
      void getInfoFromNeighbours( int& calculated, int& calculateAgain, const MeshPointer& mesh );
};

template< typename Real,
        typename Device,
        typename Index,
        typename Communicator,
        typename Anisotropy >
class FastSweepingMethod< Meshes::Grid< 3, Real, Device, Index >, Communicator, Anisotropy >
: public tnlDirectEikonalMethodsBase< Meshes::Grid< 3, Real, Device, Index > >
{
  //static_assert(  std::is_same< Device, TNL::Devices::Host >::value, "The fast sweeping method works only on CPU." );
  
  public:
    
    typedef Meshes::Grid< 3, Real, Device, Index > MeshType;
    typedef Real RealType;
    typedef Device DeviceType;
    typedef Index IndexType;
    typedef Anisotropy AnisotropyType;
    typedef tnlDirectEikonalMethodsBase< Meshes::Grid< 3, Real, Device, Index > > BaseType;
    typedef Communicator CommunicatorType;
    typedef Containers::StaticVector< 3, Index > StaticVector;
    
    using MeshPointer = Pointers::SharedPointer<  MeshType >;
    using AnisotropyPointer = Pointers::SharedPointer< AnisotropyType, DeviceType >;
    using MPI = Communicators::MpiCommunicator;
    
    using typename BaseType::InterfaceMapType;
    using typename BaseType::MeshFunctionType;
    using typename BaseType::InterfaceMapPointer;
    using typename BaseType::MeshFunctionPointer;   
    using typename BaseType::ArrayContainer;
    
    
    FastSweepingMethod();
    
    const IndexType& getMaxIterations() const;
    
    void setMaxIterations( const IndexType& maxIterations );
    
    void solve( const MeshPointer& mesh,
            MeshFunctionPointer& Aux,
            const AnisotropyPointer& anisotropy,
            MeshFunctionPointer& u );
    
    
    protected:
      
      const IndexType maxIterations;
      
      void setOverlaps( StaticVector& vecLowerOverlaps, StaticVector& vecUpperOverlaps,
              const MeshPointer& mesh);
      
      bool goThroughSweep( const StaticVector boundsFrom, const StaticVector boundsTo, 
              MeshFunctionType& aux, const InterfaceMapType& interfaceMap,
              const AnisotropyPointer& anisotropy );
      
      void getInfoFromNeighbours( int& calculated, int& calculateAgain, const MeshPointer& mesh );
};


#include "tnlFastSweepingMethod1D_impl.h"
#include "tnlFastSweepingMethod2D_impl.h"
#include "tnlFastSweepingMethod3D_impl.h"
