#include "../include/FileReader.h"

/**
  Constructor
    * Create all the entries in the parameter handler
**/
template<int dim> DataStorage<dim>::DataStorage(){
  // Physical Data
  prm.enter_subsection( "Physical Data" );
    prm.declare_entry( "initial_time", "0.", Patterns::Double(0.), "The initial time of computation." );
    prm.declare_entry( "final_time", "1.", Patterns::Double(0.), "The final time of computation." );
    prm.declare_entry( "epsilon_1", "1.", Patterns::Double(0.), "The permitivity of fluid 1." );
    prm.declare_entry( "epsilon_2", "1.", Patterns::Double(0.), "The permitivity of fluid 2." );
    prm.declare_entry("epsilon_plate", "1.", Patterns::Double(0.), "The permitivity of the plates." );
    prm.declare_entry( "K_1", "1.", Patterns::Double(0.), "The conductivity of fluid 1." );
    prm.declare_entry( "K_2", "1.", Patterns::Double(0.), "The conductivity of fluid 2." );
    prm.declare_entry( "M_1", "1.", Patterns::Double(0.), "The mobility of fluid 1." );
    prm.declare_entry( "M_2", "1.", Patterns::Double(0.), "The mobility of fluid 2." );
    prm.declare_entry( "rho_1", "1.", Patterns::Double(0.), "The density of fluid 1." );
    prm.declare_entry( "rho_2", "10.", Patterns::Double(0.), "The density of fluid 2." );
    prm.declare_entry( "beta_1", "1.", Patterns::Double(0.), "The slip coefficient of fluid 1." );
    prm.declare_entry( "beta_2", "1.", Patterns::Double(0.), "The slip coefficient of fluid 2." );
    prm.declare_entry( "viscosity_1", "1.", Patterns::Double(0.), "The viscosity of fluid 1." );
    prm.declare_entry( "viscosity_2", "1.", Patterns::Double(0.), "The viscosity of fluid 2." );
    prm.declare_entry( "lambda", "1.", Patterns::Double(0.),
                       "The regularization coefficient for the charge." );
    prm.declare_entry( "gamma", "0.02", Patterns::Double(0.), "The surface tension coeffcient." );
    prm.declare_entry( "theta_s", "25", Patterns::Double(0.), "The static contact angle (in degrees)." );
    prm.declare_entry( "delta", "0.01", Patterns::Double(0.), "The interface thickness." );
    prm.declare_entry( "alpha", "1.", Patterns::Double(0.), "The parameter for CH." );
  prm.leave_subsection();
  // Geometry data
  prm.enter_subsection( "Geometry Data" );
    prm.declare_entry( "xl", "0", Patterns::Double(), "The lower corner of the box. x-coordinate" );
    prm.declare_entry( "yl", "-2", Patterns::Double(), "The lower corner of the box. y-coordinate" );
    prm.declare_entry( "zl", "0", Patterns::Double(), "The lower corner of the box. z-coordinate" );
    prm.declare_entry( "xm", "0.5", Patterns::Double(), "The upper corner of the box. x-coordinate" );
    prm.declare_entry( "ym", "2", Patterns::Double(), "The upper corner of the box. y-coordinate" );
    prm.declare_entry( "zm", "0", Patterns::Double(), "The upper corner of the box. z-coordinate" );
    prm.declare_entry( "width", "1", Patterns::Double(), "The width of the conducting plates" );
  prm.leave_subsection();
  // Time stepping data of the problem
  prm.enter_subsection( "Time step data" );
    prm.declare_entry( "dt", "1e-2",  Patterns::Double(0.), "Time step size." );
  prm.leave_subsection();
  // Space discretization data
  prm.enter_subsection( "Space discretization" );
    prm.declare_entry( "volt_deg", "1", Patterns::Integer( 1, 5 ),
                       "The degree for the voltage space." );
    prm.declare_entry( "ph_deg", "2", Patterns::Integer( 1, 5 ),
                       "The degree for the phase field space." );
    prm.declare_entry( "pres_deg", "1", Patterns::Integer( 1, 5 ),
                       "The polynomial degree for the pressure space." );
    prm.declare_entry( "n_of_initial_refines", "5", Patterns::Integer( 0, 15 ),
                       "Number of global refines." );
    prm.declare_entry( "n_of_extra_refines", "5", Patterns::Integer( 0, 15 ),
                       "Number of extra refines." );
  prm.leave_subsection();
  // Voltage solution data
  prm.enter_subsection( "Data solve voltage" );
    prm.declare_entry( "update_prec", "15", Patterns::Integer(1),
                       "How often we update the preconditioner." );
    prm.declare_entry( "sweeps", "3", Patterns::Integer(1),
                       " The number of sweeps the AMG smoother does." );
    prm.declare_entry( "eps", "1e-6", Patterns::Double(0.),
                       " The stopping criterion." );
    prm.declare_entry( "threshold", "1e-4", Patterns::Double(0.),
                       "The aggregation threshold for AMG." );
  prm.leave_subsection();
  // Charge solution data
  prm.enter_subsection( "Data solve charge" );
    prm.declare_entry( "update_prec", "15", Patterns::Integer(1),
                       "How often we update the preconditioner." );
    prm.declare_entry( "sweeps", "3", Patterns::Integer(1),
                       "The number of sweeps the AMG smoother does." );
    prm.declare_entry( "eps", "1e-6", Patterns::Double(0.),
                       "The stopping criterion." );
    prm.declare_entry( "threshold", "1e-4", Patterns::Double(0.),
                       "The aggregation threshold for AMG." );
  prm.leave_subsection();
  // Velocity solution data
  prm.enter_subsection( "Data solve velocity" );
    prm.declare_entry( "Krylov_size", "40", Patterns::Integer(1),
                       "The size of the Krylov subspace to be used." );
    prm.declare_entry( "update_prec", "10", Patterns::Integer(1),
                       "How often we update the preconditioner." );
    prm.declare_entry( "sweeps", "4", Patterns::Integer(1),
                       "The number of sweeps the AMG smoother does." );
    prm.declare_entry( "eps", "1e-6", Patterns::Double(0.),
                       "The stopping criterion." );
    prm.declare_entry( "threshold", "1e-3", Patterns::Double(0.),
                       "The aggregation threshold for AMG." );
  prm.leave_subsection();
  // Penalty solution data
  prm.enter_subsection( "Data solve penalty" );
    prm.declare_entry( "sweeps", "3", Patterns::Integer(1),
                       "The number of sweeps the AMG smoother does." );
    prm.declare_entry( "eps", "1e-6", Patterns::Double(0.),
                       "The stopping criterion." );
    prm.declare_entry( "threshold", "1e-4", Patterns::Double(0.),
                       "The aggregation threshold for AMG." );
  prm.leave_subsection();
  // Verbosity of output
  prm.declare_entry( "verbose", "true", Patterns::Bool(), "The verbosity of the solution process." );
  // How often we want the data to be outputted
  prm.declare_entry( "output", "10", Patterns::Integer(1),
                     "How many time steps we print the solution. " );
  prm.declare_entry( "test_case", "move", Patterns::Selection( "move|split|merge" ),
                     "The test case: move merge split" );
}

/**
  Destructor
    * Does nothing
**/
template<int dim> DataStorage<dim>::~DataStorage() {}

/**
  read_data
    * Reads all the data from the parameter file and copies to the variables
**/
template<int dim> void DataStorage<dim>::read_data( char *filename ){
  std::ifstream file;
  file.open( filename );
  Assert( file, ExcFileNotOpen( filename ) );
  prm.read_input( file );
  // Physical data
  prm.enter_subsection( "Physical Data" );
    t_0 = prm.get_double( "initial_time" );
    T   = prm.get_double( "final_time" );
    epsilon.first  = prm.get_double( "epsilon_1" );
    epsilon.second = prm.get_double( "epsilon_2" );
    epsilon_plate  = prm.get_double( "epsilon_plate" );
    K.first  = prm.get_double( "K_1" );
    K.second = prm.get_double( "K_2" );
    M.first  = prm.get_double( "M_1" );
    M.second = prm.get_double( "M_2" );
    rho.first  = prm.get_double( "rho_1" );
    rho.second = prm.get_double( "rho_2" );
    beta.first  = prm.get_double( "beta_1" );
    beta.second = prm.get_double( "beta_2" );
    eta.first  = prm.get_double( "viscosity_1" );
    eta.second = prm.get_double( "viscosity_2" );
    lambda = prm.get_double( "lambda" );
    gamma = prm.get_double( "gamma" );
    // Notice that we convert the angle from degrees to radias
    theta_s = 180.*prm.get_double( "theta_s" )/M_PI;
    delta = prm.get_double( "delta" );
    alpha = prm.get_double( "alpha" );
  prm.leave_subsection();
  // Geometry Data
  prm.enter_subsection( "Geometry Data" );
    pl(0) = prm.get_double( "xl" );
    pu(0) = prm.get_double( "xm" );
    if( dim > 1 ){
      pl(1) = prm.get_double( "yl" );
      pu(1) = prm.get_double( "ym" );
    }
    if( dim > 2 ){
      pl(2) = prm.get_double( "zl" );
      pu(2) = prm.get_double( "zm" );
    }
    width = prm.get_double( "width" );
  prm.leave_subsection();
  // Time stepping data
  prm.enter_subsection( "Time step data" );
    dt = prm.get_double( "dt" );
  prm.leave_subsection();
  // Space discretization data
  prm.enter_subsection( "Space discretization" );
    volt_deg = prm.get_integer( "volt_deg" );
    ph_deg   = prm.get_integer( "ph_deg" );
    pres_deg = prm.get_integer( "pres_deg" );
    n_of_initial_refines = prm.get_integer( "n_of_initial_refines" );
    n_of_extra_refines   = prm.get_integer( "n_of_extra_refines" );
  prm.leave_subsection();
  // Voltage solution data
  prm.enter_subsection( "Data solve voltage" );
    volt_smoother_sweeps = prm.get_integer( "sweeps" );
    volt_eps = prm.get_double( "eps" );
    volt_aggregation_threshold = prm.get_double( "threshold" );
    volt_update_prec = prm.get_integer( "update_prec" );
  prm.leave_subsection();
  // Charge solution data
  prm.enter_subsection( "Data solve charge" );
    charge_smoother_sweeps = prm.get_integer( "sweeps" );
    charge_eps = prm.get_double( "eps" );
    charge_aggregation_threshold = prm.get_double( "threshold" );
    charge_update_prec = prm.get_integer( "update_prec" );
  prm.leave_subsection();
  // Velocity solution data
  prm.enter_subsection( "Data solve velocity" );
    vel_Krylov_size = prm.get_integer( "Krylov_size" );
    vel_update_prec = prm.get_integer( "update_prec" );
    vel_smoother_sweeps = prm.get_integer( "sweeps" );
    vel_eps = prm.get_double( "eps" );
    vel_aggregation_threshold = prm.get_double( "threshold" );
  prm.leave_subsection();
  // Penalty solution data
  prm.enter_subsection ( "Data solve penalty" );
    penalty_smoother_sweeps = prm.get_integer ( "sweeps" );
    penalty_eps = prm.get_double ( "eps" );
    penalty_aggregation_threshold = prm.get_double ( "threshold" );
  prm.leave_subsection();
  // Verbosity
  verbose = prm.get_bool( "verbose" );
  // Output frequency
  output = prm.get_integer( "output" );
  // test case
  if( prm.get( "test_case" ) == std::string("move") )
    testcase = TEST_CASE_MOVE;
  if( prm.get( "test_case" ) == std::string("split") )
    testcase = TEST_CASE_SPLIT;
  if( prm.get( "test_case" ) == std::string("merge") )
    testcase = TEST_CASE_MERGE;
}

/**
  print_usage
    * Prints the format of paramter-file.prm to the screen
**/
template<int dim> void DataStorage<dim>::print_usage(){
  std::cout<<" parameter-file.prm file format"<<std::endl;
  prm.print_parameters( std::cout, ParameterHandler::Text );
}

template class DataStorage<DIM>;
