using System.Runtime.InteropServices;

namespace coolprop_wrapper.Functions
{
  class CoolProp_PhaseSI : IFunction
  {
    // long PhaseSI(const char *Name1, double Prop1, const char *Name2, double Prop2, const char *Ref, char *phase, int n);
    [DllImport(
      "CoolProp.x86.dll", EntryPoint="PhaseSI",
      CharSet = CharSet.Ansi)]
    internal static extern long PhaseSIx86(
      string Name1,
      double Prop1,
      string Name2,
      double Prop2,
      string FluidName,
      System.Text.StringBuilder phase,
      int n);
    [DllImport(
      "CoolProp.x64.dll", EntryPoint = "PhaseSI",
      CharSet = CharSet.Ansi)]
    internal static extern long PhaseSIx64(
      string Name1,
      double Prop1,
      string Name2,
      double Prop2,
      string FluidName,
      System.Text.StringBuilder phase,
      int n);
    internal static long PhaseSI(
      string Name1,
      double Prop1,
      string Name2,
      double Prop2,
      string FluidName,
      System.Text.StringBuilder phase,
      int n)
    {
      switch (System.IntPtr.Size)
      {
        case 4:
          return PhaseSIx86(Name1, Prop1, Name2, Prop2, FluidName, phase, n);
        case 8:
          return PhaseSIx64(Name1, Prop1, Name2, Prop2, FluidName, phase, n);
      }
      throw new SMath.Manager.EvaluationException(SMath.Manager.Errors.PluginCannotBeEnabled);
    }

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

    public CoolProp_PhaseSI(int childCount)
    {
      inf = new SMath.Manager.Term("CoolProp_PhaseSI", 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 5:
        default:
          funcInfo = "(Name1, Prop1, Name2, Prop2, FluidName) Return a string representation of the phase\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.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 5:
          string Name1     = args[0].obj.ToString().Trim('"');
          double Prop1     = args[1].obj.ToDouble();
          string Name2     = args[2].obj.ToString().Trim('"');
          double Prop2     = args[3].obj.ToDouble();
          string FluidName = args[4].obj.ToString().Trim('"');
          var phase = new System.Text.StringBuilder(10000);
          var Result = PhaseSI(Name1, Prop1, Name2, Prop2, FluidName, phase, phase.Capacity);
          coolpropPlugin.LogInfo(string.Format("[INFO ] [CoolProp_PhaseSI.ExpressionEvaluation()] Name1 = {0}, Prop1 = {1}, Name2 = {2}, Prop2 = {3}, FluidName = {4}, phase = {5}, Result = {6}", Name1, Prop1, Name2, Prop2, FluidName, phase.ToString(), Result));
          if (Result != 1)
            throw new SMath.Manager.EvaluationException(SMath.Manager.Errors.ArgumentDoesNotMatchToExpectedKind);
          result = SMath.Math.Numeric.Expression.Calculate(SMath.Manager.Converter.ToTerms("\"" + phase.ToString() + "\""), null);
          break;
      }

      return true;
    }
  }
}
