using SMath.Math.Symbolic;

namespace coolprop_wrapper
{
  class Unit
  {
    static string uname(string u) { return SMath.Manager.UnitsManager.GetCurrentUnitName(u); }
    static MItem unit(string Format, params string[] units)
    {
      var lUnits = new System.Collections.Generic.List<string>(units.Length);
      foreach (var unit in units)
        lUnits.Add(uname(unit));
      string u = string.Format(Format, lUnits.ToArray());
      return Expression.SimplifyEx(Converter.ToMItem(u), new SMath.Manager.ActionContext());
    }
    public static MItem K { get { return unit("{0}", "'K"); } }
    // [Pa] = [kg/{m*s^2}]
    public static MItem Pa { get { return unit("{0}/{{{1}*{2}^2}}", "'kg", "'m", "'s"); } }
    // [J] = [kg*m^2/s^2]
    public static MItem J_kg { get { return unit("{0}^2/{{{1}^2}}", "'m", "'s"); } } // J/kg
    public static MItem mol_m3 { get { return unit("{0}/{{{1}^3}}", "'mol","'m"); } } // mol/m^3
    public static MItem kg_m3 { get { return unit("{0}/{{{1}^3}}", "'kg", "'m"); } } // kg/m^3
    public static MItem J_mol { get { return unit("{{{0}*{1}^2}}/{{{2}^2*{3}}}", "'kg", "'m", "'s", "'mol"); } } // J/mol
    public static MItem J_mol_K { get { return unit("{{{0}*{1}^2}}/{{{2}^2*{3}*{4}}}", "'kg", "'m", "'s", "'mol", "'K"); } } // J/mol/K
    public static MItem J_kg_K { get { return unit("{{{0}^2}}/{{{1}^2*{2}}}", "'m", "'s", "'K"); } } // J/kg/K
    public static MItem m_s { get { return unit("{0}/{1}", "'m", "'s"); } } // m/s
    // [W]=[{kg*m^2}/{s^3}]
    public static MItem W_m_K { get { return unit("{{{0}*{1}}}/{{{2}^3*{3}}}", "'kg", "'m", "'s", "'K"); } } // W/m/K
    public static MItem _K { get { return unit("1/{0}", "'K"); } } // 1/K
    public static MItem _Pa { get { return unit("{{{1}*{2}^2}}/{0}", "'kg", "'m", "'s"); } } // 1/Pa
    // [N]=[{kg*m}/{s^2}]
    public static MItem N_m { get { return unit("{0}/{{{1}^2}}", "'kg", "'s"); } } // N/m
    public static MItem kg_mol { get { return unit("{0}/{1}", "'kg", "'mol"); } } // kg/mol
    public static MItem Pa_s { get { return unit("{0}/{{{1}*{2}}}", "'kg", "'m", "'s"); } } // Pa*s

    public static MItem unitless { get { return unit("1"); } }

    public static SMath.Math.Symbolic.MItem Find(string param)
    {
      switch (param)
      {
        case "DMOLAR": case "Dmolar":
        case "RHOMOLAR_CRITICAL": case "rhomolar_critical":
        case "RHOMOLAR_REDUCING": case "rhomolar_reducing":
          return mol_m3;
        case "D": case "DMASS": case "Dmass":
        case "RHOCRIT": case "RHOMASS_CRITICAL": case "rhocrit": case "rhomass_critical":
        case "RHOMASS_REDUCING": case "rhomass_reducing":
          return kg_m3;
        case "HMOLAR": case "Hmolar":
        case "UMOLAR": case "Umolar":
        case "GMOLAR": case "Gmolar":
          return J_mol;
        case "H": case "HMASS": case "Hmass":
        case "U": case "UMASS": case "Umass":
        case "GMASS": case "Gmass":
          return J_kg;
        case "P":
        case "PCRIT": case "P_CRITICAL": case "Pcrit": case "p_critical": case "pcrit":
        case "PMAX": case "P_MAX": case "P_max": case "pmax":
        case "PMIN": case "P_MIN": case "P_min": case "pmin":
        case "PTRIPLE": case "P_TRIPLE": case "p_triple": case "ptriple":
        case "P_REDUCING": case "p_reducing":
          return Pa;
        case "SMOLAR": case "Smolar":
        case "CP0MOLAR": case "Cp0molar":
        case "CPMOLAR": case "Cpmolar":
        case "CVMOLAR": case "Cvmolar":
        case "GAS_CONSTANT": case "gas_constant":
          return J_mol_K;
        case "S": case "SMASS": case "Smass":
        case "CVMASS": case "Cvmass": case "O":
        case "C": case "CPMASS": case "Cpmass":
          return J_kg_K;
        case "T":
        case "TCRIT": case "T_CRITICAL": case "T_critical": case "Tcrit":
        case "TMAX": case "T_MAX": case "T_max": case "Tmax":
        case "TMIN": case "T_MIN": case "T_min": case "Tmin":
        case "TTRIPLE": case "T_TRIPLE": case "T_triple": case "Ttriple":
        case "T_REDUCING": case "T_reducing":
          return K;
        case "A": case "SPEED_OF_SOUND": case "speed_of_sound":
          return m_s;
        case "CONDUCTIVITY": case "L": case "conductivity":
          return W_m_K;
        case "ISOBARIC_EXPANSION_COEFFICIENT": case "isobaric_expansion_coefficient":
          return _K;
        case "ISOTHERMAL_COMPRESSIBILITY": case "isothermal_compressibility":
          return _Pa;
        case "I": case "SURFACE_TENSION": case "surface_tension":
          return N_m;
        case "M": case "MOLARMASS": case "MOLAR_MASS": case "MOLEMASS": case "molar_mass": case "molarmass": case "molemass":
          return kg_mol;
        case "V": case "VISCOSITY": case "viscosity":
          return Pa_s;
      }
      return unitless;
    }

    public static void match(string param, SMath.Math.Numeric.TNumber val)
    {
      if (!val.obj.Units.MathEqual(Find(param)) && !val.obj.Units.MathEqual(unitless))
        throw new SMath.Manager.EvaluationException(SMath.Manager.Errors.UnitsDontMatch);
    }
  }
}
