using System.Runtime.InteropServices;

namespace coolprop_wrapper.Functions
{
  class CoolProp_PropsSI : IFunction
  {
    //  double PropsSI(const char *Output, const char *Name1, double Prop1, const char *Name2, double Prop2, const char *Ref);
    [DllImport(
      "CoolProp.x86.dll", EntryPoint = "PropsSI",
      CharSet = CharSet.Ansi)]
    internal static extern double PropsSI_x86(
      string Output,
      string Name1,
      double Prop1,
      string Name2,
      double Prop2,
      string FluidName);
    [DllImport(
      "CoolProp.x64.dll", EntryPoint = "PropsSI",
      CharSet = CharSet.Ansi)]
    internal static extern double PropsSI_x64(
      string Output,
      string Name1,
      double Prop1,
      string Name2,
      double Prop2,
      string FluidName);
    internal static double PropsSI(
      string Output,
      string Name1,
      double Prop1,
      string Name2,
      double Prop2,
      string FluidName)
    {
      switch (System.IntPtr.Size) {
        case 4:
          return PropsSI_x86(Output, Name1, Prop1, Name2, Prop2, FluidName);
        case 8:
          return PropsSI_x64(Output, Name1, Prop1, Name2, Prop2, FluidName);
      }
      throw new SMath.Manager.EvaluationException(SMath.Manager.Errors.PluginCannotBeEnabled);
    }

    SMath.Manager.Term inf;
    public static int[] Arguments = new[] { 6 };

    public CoolProp_PropsSI(int childCount)
    {
      inf = new SMath.Manager.Term("CoolProp_PropsSI", SMath.Manager.TermType.Function, childCount);
    }

    SMath.Manager.Term IFunction.Info
    {
      get { return inf; }
    }

    SMath.Manager.TermInfo IFunction.GetTermInfo(string lang)
    {
      string funcInfo;

      var argsInfos = new System.Collections.Generic.List<SMath.Manager.ArgumentInfo>();

      switch (inf.ChildCount)
      {
        case 6:
        default:
          funcInfo = "(Output, Name1, Prop1, Name2, Prop2, FluidName) Return a value that depends on the thermodynamic state\r\n" +
                     "Output The output parameter, one of \"T\",\"D\",\"H\",etc.\r\n" +
                     "Name1 The first state variable name, one of \"T\",\"D\",\"H\",etc.\r\n" +
                     "Prop1 The first state variable value\r\n" +
                     "Name2 The second state variable name, one of \"T\",\"D\",\"H\",etc.\r\n" +
                     "Prop2 The second state variable value\r\n" +
                     "FluidName The fluid name";
          argsInfos.Add(new SMath.Manager.ArgumentInfo(SMath.Manager.ArgumentSections.String));
          argsInfos.Add(new SMath.Manager.ArgumentInfo(SMath.Manager.ArgumentSections.String));
          argsInfos.Add(new SMath.Manager.ArgumentInfo(SMath.Manager.ArgumentSections.RealNumber));
          argsInfos.Add(new SMath.Manager.ArgumentInfo(SMath.Manager.ArgumentSections.String));
          argsInfos.Add(new SMath.Manager.ArgumentInfo(SMath.Manager.ArgumentSections.RealNumber));
          argsInfos.Add(new SMath.Manager.ArgumentInfo(SMath.Manager.ArgumentSections.String));
          break;
      }

      return new SMath.Manager.TermInfo(inf.Text,
                                        inf.Type,
                                        funcInfo,
                                        SMath.Manager.FunctionSections.Unknown,
                                        true,
                                        argsInfos.ToArray());
    }

    bool IFunction.NumericEvaluation(SMath.Manager.Term value, SMath.Math.Numeric.TNumber[] args, ref SMath.Math.Numeric.TNumber result)
    {
      switch (args.GetLength(0))
      {
        case 6:
          string Output    = args[0].obj.ToString().Trim('"');
          string Name1     = args[1].obj.ToString().Trim('"');
          double Prop1     = args[2].obj.ToDouble();
          string Name2     = args[3].obj.ToString().Trim('"');
          double Prop2     = args[4].obj.ToDouble();
          string FluidName = args[5].obj.ToString().Trim('"');
          var Result = PropsSI(Output, Name1, Prop1, Name2, Prop2, FluidName);
          coolpropPlugin.LogInfo(string.Format("[INFO ] [CoolProp_PropsSI.ExpressionEvaluation()] Output = {0}, Name1 = {1}, Prop1 = {2}, Name2 = {3}, Prop2 = {4}, FluidName = {5}, Result = {6}", Output, Name1, Prop1, Name2, Prop2, FluidName, Result));
          result = new SMath.Math.Numeric.TNumber(Result);
          result.obj.Units = Unit.Find(Output);
          break;
      }

      return true;
    }
  }
}
