using System;
using System.Collections;
using System.Diagnostics;
using System.Diagnostics.SymbolStore;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using ArchestrA.QuickScript;
using ArchestrA.QuickScript.Digest;
using ArchestrA.QuickScript.Emit;
using ArchestrA.QuickScript.Model;
using ArchestrA.QuickScript.Runtime;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("5800.0038.7005.1")]
[assembly: AssemblyTitle("ScriptPackage.Net Module")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("AVEVA Software, LLC")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("Copyright 2020 AVEVA Group plc and its subsidiaries. All rights reserved.")]
[assembly: AssemblyTrademark("Refer to: https://sw.aveva.com/legal/trademarks")]
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("..\\..\\..\\SharedComponents\\Internal\\MagellanPublic\\Includes\\WWDotNETPrivateKey\\ww.snk")]
[assembly: AssemblyKeyName("")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("2.0.0.0")]
namespace ArchestrA.Scripting
{
	[Guid("85963980-46DF-459d-8A96-2A2AF70F458F")]
	[ClassInterface(ClassInterfaceType.AutoDual)]
	public class ScriptPackage
	{
		private class NameHierarchy
		{
			public Hashtable Hashtable = new Hashtable();

			public readonly string Name;

			public int Index;

			public NameHierarchy(string name)
			{
				Name = name;
				Index = -1;
			}

			public NameHierarchy()
				: this(null)
			{
			}

			public void Add(string name, int index)
			{
				string text = null;
				string text2 = null;
				int num = name.IndexOf('.');
				if (num < 0)
				{
					text = name;
				}
				else
				{
					text = name.Substring(0, num);
					text2 = name.Substring(num + 1, name.Length - num - 1);
				}
				string key = text.ToLower();
				if (!Hashtable.ContainsKey(key))
				{
					Hashtable[key] = new NameHierarchy(text);
				}
				NameHierarchy nameHierarchy = (NameHierarchy)Hashtable[key];
				if (text2 != null)
				{
					nameHierarchy.Add(text2, index);
				}
				else
				{
					nameHierarchy.Index = index;
				}
			}
		}

		private class TypeResolveHandler
		{
			private Module Module;

			private Hashtable Hashtable;

			public TypeResolveHandler(Module module, Hashtable hashtable)
			{
				Module = module;
				Hashtable = hashtable;
			}

			public Assembly ResolveEvent(object sender, ResolveEventArgs args)
			{
				((TypeBuilder)Hashtable[args.Name]).CreateType();
				return Module.Assembly;
			}
		}

		private string BinFolder;

		private bool DebugEnabled;

		private Parser Parser;

		private string TagName;

		private string ScriptName;

		private Hashtable ReferencedAssemblies;

		private ModuleBuilder ModuleBuilder;

		private TypeBuilder TypeBuilder;

		private ILBuilder ILBuilder;

		private int NestedTypeIndex;

		private string ErrorMessage;

		private int ErrorLine;

		private int ErrorColumn;

		private static readonly FieldInfo ScriptExchange;

		private static readonly Type[] ExpessionParameterTypes;

		private static readonly MethodInfo EnableDebugSupport;

		private static string DebugFolder => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "QuickScriptDebug");

		private static bool DebuggerInfoEnabled => Directory.Exists(DebugFolder);

		public void Compile(string libraryPath, string repositoryPath, string tagName, string scriptName, string compilerAssemblyFile, string compilerTypeName, IntPtr outputAssemblyName, IntPtr aliases, IntPtr declarationsText, IntPtr startupText, IntPtr onScanText, IntPtr expression, IntPtr executeText, IntPtr offScanText, IntPtr shutdownText, IntPtr binary, IntPtr errorMessage, IntPtr errorLine, IntPtr errorColumn, IntPtr libaryDependencies, IntPtr externalReferences, IntPtr externalReferenceFlags, IntPtr aliasReferenceFlags)
		{
			IList list = null;
			byte[] array = null;
			ErrorMessage = "";
			BinFolder = Path.GetDirectoryName(Assembly.GetAssembly(GetType()).Location);
			Parser = new Parser();
			ILBuilder = new ILBuilder();
			ReferencedAssemblies = new Hashtable();
			list = new ArrayList();
			TagName = tagName;
			ScriptName = scriptName;
			DebugEnabled = DebuggerInfoEnabled;
			NestedTypeIndex = 0;
			int mxValueElementCount = GetMxValueElementCount(aliases);
			int i;
			for (i = 0; i < mxValueElementCount; i++)
			{
				ExternalReferences.AddAlias(GetMxValueElementString(aliases, i + 1));
			}
			try
			{
				string tempPath = Path.GetTempPath();
				AssemblyName assemblyName = new AssemblyName();
				assemblyName.Name = GetMxValueString(outputAssemblyName);
				string text = assemblyName.Name + ".dll";
				Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
				AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save, tempPath);
				if (DebugEnabled)
				{
					CustomAttributeBuilder customAttribute = new CustomAttributeBuilder(typeof(DebuggableAttribute).GetConstructor(new Type[2]
					{
						typeof(bool),
						typeof(bool)
					}), new object[2] { true, true });
					assemblyBuilder.SetCustomAttribute(customAttribute);
				}
				ModuleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, text, DebugEnabled);
				TypeBuilder = ModuleBuilder.DefineType("ArchestrA.Scripting.Script", TypeAttributes.Public, typeof(ScriptBase), new Type[0]);
				ILGenerator iLGenerator = TypeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[0]).GetILGenerator();
				ILBuilder.ILGenerator = iLGenerator;
				iLGenerator.Emit(OpCodes.Ldarg_0);
				iLGenerator.Emit(OpCodes.Call, typeof(ScriptBase).GetConstructor(new Type[0]));
				ILBuilder.DebugEnabled = false;
				ILBuilder.FieldScriptExchange = ScriptExchange;
				CompileDeclarations(GetMxValueString(declarationsText));
				ILBuilder.Emit(new Return());
				if (ErrorMessage.Length == 0 || ErrorMessage.StartsWith("Warning"))
				{
					CompileExpression(GetMxValueString(expression));
					CompileMethod("Startup", GetMxValueString(startupText));
					CompileMethod("OnScan", GetMxValueString(onScanText));
					CompileMethod("Execute", GetMxValueString(executeText));
					CompileMethod("OffScan", GetMxValueString(offScanText));
					CompileMethod("Shutdown", GetMxValueString(shutdownText));
				}
				if (ErrorMessage.Length == 0 || ErrorMessage.StartsWith("Warning"))
				{
					if (DebugEnabled)
					{
						Hashtable hashtable = new Hashtable();
						ResolveEventHandler value = new TypeResolveHandler(ModuleBuilder, hashtable).ResolveEvent;
						AppDomain.CurrentDomain.TypeResolve += value;
						NameHierarchy nameHierarchy = new NameHierarchy();
						int num = 0;
						foreach (ExternalReference item in ExternalReferences.List)
						{
							nameHierarchy.Add(item.ReferenceString.Split('[')[0], num++);
						}
						Build(nameHierarchy, TypeBuilder, hashtable);
						RecurseNestedTypes(TypeBuilder.CreateType());
						AppDomain.CurrentDomain.TypeResolve -= value;
					}
					else
					{
						TypeBuilder.CreateType();
					}
					assemblyBuilder.Save(text);
				}
				foreach (Assembly key in ReferencedAssemblies.Keys)
				{
					list.Add(key.GetName().Name);
				}
				if (ErrorMessage.Length == 0)
				{
					string path = Path.Combine(tempPath, text);
					using (FileStream fileStream = File.OpenRead(path))
					{
						array = new byte[fileStream.Length];
						fileStream.Read(array, 0, (int)fileStream.Length);
					}
					if (DebugEnabled)
					{
						File.Exists(Path.ChangeExtension(path, "pdb"));
					}
					File.Delete(path);
				}
			}
			catch (Exception ex)
			{
				ErrorMessage = "Internal QuickScript compiler error: " + ex.Message;
			}
			if (ErrorMessage.Length > 0)
			{
				PutMxValueString(errorMessage, ErrorMessage);
				PutMxValueInteger(errorLine, ErrorLine);
				PutMxValueInteger(errorColumn, ErrorColumn);
				return;
			}
			PutMxValueString(errorMessage, "");
			PutMxValueInteger(errorLine, 0);
			PutMxValueInteger(errorColumn, 0);
			PutMxValueBlob(binary, array, array.Length);
			i = 1;
			foreach (string item2 in list)
			{
				PutMxValueElementString(libaryDependencies, i++, item2);
			}
			i = 1;
			int index = 1;
			foreach (ExternalReference item3 in ExternalReferences.List)
			{
				if (item3.IsAlias)
				{
					PutMxValueElementInteger(aliasReferenceFlags, i++, item3.Flags);
					continue;
				}
				PutMxValueElementString(externalReferences, index, item3.ReferenceString);
				PutMxValueElementInteger(externalReferenceFlags, index++, item3.Flags);
			}
		}

		private void RecurseNestedTypes(Type type)
		{
			Type[] nestedTypes = type.GetNestedTypes();
			foreach (Type type2 in nestedTypes)
			{
				RecurseNestedTypes(type2);
			}
		}

		private void GetErrorsAndWarnings(string section)
		{
			if (ErrorMessage.Length > 0 && !ErrorMessage.StartsWith("Warning"))
			{
				return;
			}
			IEnumerator enumerator = Parser.Errors.GetEnumerator();
			try
			{
				if (enumerator.MoveNext())
				{
					ErrorInfo errorInfo = (ErrorInfo)enumerator.Current;
					ErrorLine = errorInfo.Line;
					ErrorColumn = errorInfo.Column;
					ErrorMessage = $"Script {ScriptName} ({section}): {errorInfo.Message} (Line: {errorInfo.Line}, Col: {errorInfo.Column})";
					return;
				}
			}
			finally
			{
				IDisposable disposable = enumerator as IDisposable;
				if (disposable != null)
				{
					disposable.Dispose();
				}
			}
			enumerator = Parser.Warnings.GetEnumerator();
			try
			{
				if (enumerator.MoveNext())
				{
					ErrorInfo errorInfo2 = (ErrorInfo)enumerator.Current;
					ErrorLine = errorInfo2.Line;
					ErrorColumn = errorInfo2.Column;
					ErrorMessage = $"Warning: Script {ScriptName} ({section}): {errorInfo2.Message} (Line: {errorInfo2.Line}, Col: {errorInfo2.Column})";
				}
			}
			finally
			{
				IDisposable disposable2 = enumerator as IDisposable;
				if (disposable2 != null)
				{
					disposable2.Dispose();
				}
			}
		}

		private void CompileDeclarations(string declarationsText)
		{
			if (declarationsText.Length == 0)
			{
				return;
			}
			ILBuilder.DeclarationsAreFields = true;
			Parser.DeclarationsAreFields = true;
			Parser.Parse(declarationsText);
			if (Parser.Tree is Expression)
			{
				CodeSpan codeSpan = (Parser.Tree as Expression).CodeSpan;
				codeSpan = new CodeSpan(codeSpan.End.Line, codeSpan.End.Column + 1, codeSpan.End.Line, codeSpan.End.Column + 1);
				Parser.Errors.Add(new ErrorInfo("Expected ';'", codeSpan.End.Line, codeSpan.End.Column, codeSpan.End.Line, codeSpan.End.Column));
			}
			GetErrorsAndWarnings("Declarations");
			if (Parser.Errors.Count != 0)
			{
				return;
			}
			foreach (Statement item in Parser.Tree as IList)
			{
				Declaration declaration = item as Declaration;
				FieldBuilder value = TypeBuilder.DefineField(declaration.VariableName, declaration.Type, FieldAttributes.Public);
				ILBuilder.Variables[declaration.VariableName] = value;
				ILBuilder.Emit(declaration);
			}
			Parser.GetReferencedAssemblies(ReferencedAssemblies);
		}

		private void CompileExpression(string expressionText)
		{
			if (expressionText.Length != 0)
			{
				ILBuilder.DeclarationsAreFields = false;
				Parser.DeclarationsAreFields = false;
				Parser.Parse(expressionText);
				if (Parser.Tree is Statements)
				{
					CodeSpan codeSpan = ((Parser.Tree as Statements)[0] as Statement).CodeSpan;
					Parser.Errors.Add(new ErrorInfo("Not expecting ';'", codeSpan.End.Line, codeSpan.End.Column, codeSpan.End.Line, codeSpan.End.Column));
				}
				GetErrorsAndWarnings("Expression");
				if (Parser.Errors.Count <= 0)
				{
					MethodAttributes attributes = MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig;
					MethodBuilder methodBuilder = TypeBuilder.DefineMethod("Expression", attributes, typeof(void), ExpessionParameterTypes);
					methodBuilder.DefineParameter(1, ParameterAttributes.Out, null);
					methodBuilder.DefineParameter(2, ParameterAttributes.Out, null);
					ILGenerator iLGenerator = methodBuilder.GetILGenerator();
					ILBuilder.ILGenerator = iLGenerator;
					ILBuilder.Variables.ClearLocals();
					ILBuilder.DebugEnabled = false;
					Expression expression = Parser.Tree as Expression;
					iLGenerator.Emit(OpCodes.Ldarg_1);
					ILBuilder.Emit(Coerce.ChangeType(expression, typeof(object)));
					iLGenerator.Emit(OpCodes.Stind_Ref);
					iLGenerator.Emit(OpCodes.Ldarg_2);
					ILBuilder.Emit(Digester.GetQuality(expression));
					iLGenerator.Emit(OpCodes.Conv_I4);
					iLGenerator.Emit(OpCodes.Stind_I4);
					ILBuilder.Emit(new Return());
					Parser.GetReferencedAssemblies(ReferencedAssemblies);
				}
			}
		}

		private void CompileMethod(string methodName, string methodText)
		{
			if (methodText.Length == 0)
			{
				if (!(methodName == "Startup"))
				{
					return;
				}
				methodText = ";";
			}
			ILBuilder.DeclarationsAreFields = false;
			Parser.DeclarationsAreFields = false;
			Parser.Parse(methodText);
			if (Parser.Tree is Expression)
			{
				CodeSpan codeSpan = (Parser.Tree as Expression).CodeSpan;
				codeSpan = new CodeSpan(codeSpan.End.Line, codeSpan.End.Column + 1, codeSpan.End.Line, codeSpan.End.Column + 1);
				Parser.Errors.Add(new ErrorInfo("Expected ';'", codeSpan.End.Line, codeSpan.End.Column, codeSpan.End.Line, codeSpan.End.Column));
			}
			GetErrorsAndWarnings(methodName);
			if (Parser.Errors.Count > 0)
			{
				return;
			}
			ISymbolDocumentWriter symbolDocumentWriter = null;
			if (DebugEnabled)
			{
				string text = DebugFolder + "\\" + TagName + "." + ScriptName + "." + methodName + ".qs";
				if (methodText.Length > 1)
				{
					using StreamWriter streamWriter = File.CreateText(text);
					streamWriter.Write(methodText);
				}
				symbolDocumentWriter = ModuleBuilder.DefineDocument(text, Guid.Empty, Guid.Empty, Guid.Empty);
			}
			Type[] parameterTypes = new Type[0];
			switch (methodName)
			{
			case "Startup":
				parameterTypes = new Type[1] { typeof(IScriptExchange) };
				break;
			case "Execute":
				parameterTypes = new Type[1] { typeof(ScriptTimer) };
				break;
			}
			MethodAttributes attributes = MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig;
			ILGenerator iLGenerator = TypeBuilder.DefineMethod(methodName, attributes, typeof(void), parameterTypes).GetILGenerator();
			ILBuilder.ILGenerator = iLGenerator;
			ILBuilder.Variables.ClearLocals();
			ILBuilder.SymbolDocumentWriter = symbolDocumentWriter;
			ILBuilder.DebugEnabled = false;
			ILBuilder.CheckForTimeout = methodName == "Execute" && !DebugEnabled;
			if (methodName == "Startup")
			{
				iLGenerator.Emit(OpCodes.Ldarg_0);
				iLGenerator.Emit(OpCodes.Ldarg_1);
				iLGenerator.Emit(OpCodes.Stfld, ScriptExchange);
				if (DebugEnabled)
				{
					Expression destination = new Field(new This(), typeof(ScriptBase).GetField("TagName"));
					Expression source = new ConstantString(TagName);
					ILBuilder.Emit(new Assignment(destination, source));
					ILBuilder.Emit(new ExpressionStatement(new Method(null, EnableDebugSupport, new Expression[1]
					{
						new This()
					})));
				}
			}
			Statements statements = Parser.Tree as Statements;
			ILBuilder.DebugEnabled = DebugEnabled;
			ILBuilder.LineNumber = 0;
			ILBuilder.Emit(statements);
			ILBuilder.Emit(new Return());
			Parser.GetReferencedAssemblies(ReferencedAssemblies);
		}

		static ScriptPackage()
		{
			ScriptExchange = typeof(ScriptBase).GetField("ScriptExchange");
			ExpessionParameterTypes = null;
			EnableDebugSupport = typeof(ArchestrA.QuickScript.Runtime.ExternalReference).GetMethod("EnableDebugSupport");
			ParameterInfo[] parameters = typeof(IScriptObject).GetMethod("Expression").GetParameters();
			ExpessionParameterTypes = new Type[parameters.Length];
			int num = 0;
			ParameterInfo[] array = parameters;
			foreach (ParameterInfo parameterInfo in array)
			{
				ExpessionParameterTypes[num++] = parameterInfo.ParameterType;
			}
		}

		private void Build(NameHierarchy nameHierarchy, TypeBuilder typeBuilder, Hashtable hashtable)
		{
			Type typeFromHandle = typeof(ArchestrA.QuickScript.Runtime.ExternalReference);
			typeFromHandle.GetField("Index");
			if (nameHierarchy.Index == -1)
			{
				TypeBuilder typeBuilder2 = null;
				if (nameHierarchy.Name != null)
				{
					typeBuilder2 = typeBuilder.DefineNestedType("Tag" + ++NestedTypeIndex, TypeAttributes.NestedPublic, typeFromHandle);
				}
				foreach (NameHierarchy value in nameHierarchy.Hashtable.Values)
				{
					Build(value, (typeBuilder2 != null) ? typeBuilder2 : typeBuilder, hashtable);
				}
				if (nameHierarchy.Name != null)
				{
					hashtable[typeBuilder2.Name] = typeBuilder2;
				}
				if (typeBuilder2 != null)
				{
					typeBuilder.DefineField(nameHierarchy.Name, typeBuilder2, FieldAttributes.Public);
				}
			}
			else if (nameHierarchy.Name != null)
			{
				string name = "T" + nameHierarchy.Index;
				TypeBuilder typeBuilder3 = typeBuilder.DefineNestedType(name, TypeAttributes.NestedPublic, typeof(ExternalReferenceDebug));
				typeBuilder.DefineField(nameHierarchy.Name, typeBuilder3, FieldAttributes.Public);
				hashtable[typeBuilder3.Name] = typeBuilder3;
			}
		}

		[DllImport("ScriptPackage.dll", CharSet = CharSet.Unicode)]
		[SuppressUnmanagedCodeSecurity]
		[return: MarshalAs(UnmanagedType.BStr)]
		private static extern string GetMxValueString(IntPtr rawMxValue);

		[DllImport("ScriptPackage.dll")]
		[SuppressUnmanagedCodeSecurity]
		private static extern void PutMxValueInteger(IntPtr rawMxValue, int value);

		[DllImport("ScriptPackage.dll", CharSet = CharSet.Unicode)]
		[SuppressUnmanagedCodeSecurity]
		private static extern void PutMxValueString(IntPtr rawMxValue, string value);

		[DllImport("ScriptPackage.dll")]
		[SuppressUnmanagedCodeSecurity]
		private static extern void PutMxValueBlob(IntPtr rawMxValue, [MarshalAs(UnmanagedType.LPArray)] byte[] value, int size);

		[DllImport("ScriptPackage.dll")]
		[SuppressUnmanagedCodeSecurity]
		private static extern int GetMxValueElementCount(IntPtr rawMxValue);

		[DllImport("ScriptPackage.dll", CharSet = CharSet.Unicode)]
		[SuppressUnmanagedCodeSecurity]
		[return: MarshalAs(UnmanagedType.BStr)]
		private static extern string GetMxValueElementString(IntPtr rawMxValue, int index);

		[DllImport("ScriptPackage.dll", CharSet = CharSet.Unicode)]
		[SuppressUnmanagedCodeSecurity]
		private static extern void PutMxValueElementString(IntPtr rawMxValue, int index, string value);

		[DllImport("ScriptPackage.dll")]
		[SuppressUnmanagedCodeSecurity]
		private static extern void PutMxValueElementInteger(IntPtr rawMxValue, int index, int value);
	}
}
namespace AcmeBuildVersion
{
	internal sealed class Versioning
	{
		public const string Company = "AVEVA Software, LLC";

		public const string Product = "";

		public const string Copyright = "Copyright 2020 AVEVA Group plc and its subsidiaries. All rights reserved.";

		public const string Trademark = "Refer to: https://sw.aveva.com/legal/trademarks";

		public const string Configuration = "Release";

		public const string BuildNumber = "5800";

		public const string BuildMaintenanceNumber = "7005";

		public const string BldRevision = "1";

		private Versioning()
		{
		}
	}
	internal sealed class ComponentVersioning
	{
		public const string ComponentVersion = "0038";

		public const string ComponentMaintenanceVersion = "0000";

		public const string ComponentName = "ScriptPrimitive";

		private ComponentVersioning()
		{
		}
	}
}
