using System.Collections.Generic;

namespace coolprop_wrapper
{
  public class coolpropPlugin : SMath.Math.IPluginLowLevelEvaluation, SMath.Math.Numeric.IPluginMathNumericEvaluation
  {
    SMath.Manager.AssemblyInfo[] asseblyInfos = new SMath.Manager.AssemblyInfo[] {
      new SMath.Manager.AssemblyInfo("SMath Studio", new System.Version(0, 97), new System.Guid("a37cba83-b69c-4c71-9992-55ff666763bd"))
    };
    SMath.Manager.TermInfo[] termInfos = new SMath.Manager.TermInfo[] {};
    List<IFunction> functions = new List<IFunction>();

    static string AssemblyDirectory {
      get
      {
        var filepath = new System.Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath;
        return System.IO.Path.GetDirectoryName(filepath);
      }
    }
    static string LogFile {
      get { return System.IO.Path.Combine(AssemblyDirectory, "log.txt"); }
    }

    public static void LogInfo(string Text)
    {
      System.IO.File.AppendAllText(
        LogFile,
        string.Format(
          "{0} {1} {2}{3}",
          System.DateTime.Now.ToShortDateString(),
          System.DateTime.Now.ToLongTimeString(),
          Text,
          System.Environment.NewLine),
        System.Text.Encoding.UTF8);
    }

    bool SMath.Math.Numeric.IPluginMathNumericEvaluation.NumericEvaluation(
      SMath.Manager.Term value,
      SMath.Math.Numeric.TNumber[] args,
      ref SMath.Math.Numeric.TNumber result)
    {
      if (value.Type != SMath.Manager.TermType.Function)
        return false;

      foreach (var func in functions) {
        if (!func.Info.Equals(value))
          continue;

        try {
          return func.NumericEvaluation(value, args, ref result);
        }
        catch (System.Exception ex) {
          LogInfo("[ERROR] [Plugin.NumericEvaluation()] " + string.Format("{0}({1}) {2}", value.Text, value.ChildCount, ex.Message));
          throw;
        }
      }

      return false;
    }

    SMath.Manager.TermInfo[] SMath.Manager.IPluginHandleEvaluation.TermsHandled
    {
      get { return termInfos; }
    }

    void System.IDisposable.Dispose()
    {
      try {
        if (System.IO.File.Exists(LogFile))
          System.IO.File.Delete(LogFile);
      }
      catch (System.Exception) {}
    }

    SMath.Manager.AssemblyInfo[] SMath.Manager.IPlugin.Dependences
    {
      get { return asseblyInfos; }
    }

    void SMath.Manager.IPlugin.Initialize()
    {
      var info = new List<SMath.Manager.TermInfo>();

      try {
        foreach (System.Type type in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()) {

          if (!(type.IsClass && typeof(IFunction).IsAssignableFrom(type)))
            continue;

          var arguments = type.GetField( "Arguments", System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public );

          if (arguments == null)
            continue;

          var args = arguments.GetValue(null) as int[];

          foreach (var arg in args) {
            functions.Add((IFunction)System.Activator.CreateInstance(type, new System.Object[] {arg}));
          }
        }

        foreach (var func in functions) {
          var item = func.GetTermInfo(SMath.Manager.GlobalParams.CurLang3Letter);
          info.Add(item);
          LogInfo(string.Format("[INFO ] [Plugin.Initialize()] {0}({1}) - {2}", item.Text, item.ChildCount, item.Description));
        }
      }
      catch (System.Exception ex) {
        LogInfo("[ERROR] [Plugin.Initialize()] " + ex.Message);
      }

      termInfos = info.ToArray();
      LogInfo(string.Format("[INFO ] [Plugin.Initialize()] Successfully. {0} functions loaded.", termInfos.Length));
    }

    bool SMath.Math.IPluginLowLevelEvaluation.ExpressionEvaluation(SMath.Manager.Term root, SMath.Manager.Term[][] args, ref SMath.Math.Store context, ref SMath.Manager.Term[] result)
    {
      return true;
    }
  }
}
