// Copyright (C) 2007 Murtazo Nazarov.
// Licensed under the GNU GPL Version 2.
// 
// Based on existing NSESolver of Johan Hoffman

#ifndef __CNS_SOLVER_H
#define __CNS_SOLVER_H

//#include <dolfin/Solver.h>
#include <dolfin.h>
#include "FormFactory.h"


namespace dolfin
{
  namespace unicorn
  {
  // This is a solver for the time dependent compressible 
  // Euler equations. 
  class dolfin::BoundaryCondition;

  class CNSSolver 
  {
  public:
    
    // Create the Compressible solver
    //CNSSolver(Mesh& mesh, Function& f, Function& initialdata, BoundaryCondition& bc);
    CNSSolver(Mesh& mesh, Function& f, Function& initialdata, Array<dolfin::BoundaryCondition*>& bc);
    
    // Solve Compressible equations
    void solve();

    // Solve Copressible equations (static version)
    //static void solve(Mesh& mesh, Function& f, Function& initialdata, BoundaryCondition& bc);
    static void solve(Mesh& mesh, Function& f, Function& initialdata, Array<dolfin::BoundaryCondition*>& bc);

    // Set initial data
    void SetInitialData(Function& w, Function& initial);

    // Compute cell diameter
    void ComputeCellSize(Mesh& mesh, Vector& hvector);
      
    // Get minimum cell diameter
    void GetMinimumCellSize(Mesh& mesh, real& hmin);

    // Compute stabilization 
    void ComputeStabilization(Mesh& mesh, Function& w, real k, 
			      Vector& dvector);
    
    // Compute cell mean                                                                                                   
    static void ComputeMean(Mesh& mesh, Function& vmean, Function& v);

    // Set initial velocity 
    void SetInitialData(Function& rho0, Function& m0, Function& e0);

    // Compute velosity and pressure
    void ComputeUP(Mesh& mesh, Function& w, Function& p, Function& u, real gamma, int nsdim);

    // Pick up the components of the w
    void ComputeRME(Mesh& mesh, Function& w, Function& rho, Function& m, Function& e, int nsdim);

    // Compute the volume inverse of each element
    void ComputeVolInv(Mesh& mesh, Vector& vol_inv);

    // Compute the shock capturing constant nu:
    void ComputeNu(Mesh& mesh, Function& res_rho, Function& res_m, Function& res_e, 
			      Function& nu_rho, Function& nu_m, Function& nu_e, int nsdim);

    // Compute the Mach Number
    void ComputeMachNum(Mesh& mesh, Function& rho, Function& p, Function& u, Function& muchn, real gamma, int nsdim);


  private:
    Mesh& mesh;
    Function& f;
    Function& initial;
    Array<BoundaryCondition*>& bcs;
    //BoundaryCondition& bc;
   };

  }}

#endif
