/*
 * User: Ryan
 * Date: 8/17/2017
 * Time: 11:54 AM
 */
using System;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Threading;
using System.Windows.Input;
using FancyPrintCS;
using NAudio.Wave;
using parseManagerCS;
namespace parseManagerCS
{
	/// The parseManager is an Advance Config Script
	/// It allows the user to run code while also definine variables
	/// This also has very flexible flow control meaning you can use it for chat logic and such
	public class parseManager
	{
		public string _VERSION = "1.0";
		standardDefine _invoke = new standardDefine();
		string _filepath;
		bool _active = true;
		string _define = "NO_DEFINE";
		string _entry = "START";
		bool _isInternal;
		Type _defineType;
		bool isThread;
		standardDefine def = new standardDefine();
		MethodInfo _defineMethod;
		object _defineClassObject;
		chunk _currentChunk;
		chunk _lastChunk = null;
		ENV _mainENV = new ENV();
		public ENV _defualtENV;
		Stack<ENV> _fStack = new Stack<ENV>();
		Dictionary<string, bool> _flags = new Dictionary<string, bool>();
		Dictionary<string, chunk> _chunks = new Dictionary<string, chunk>();
		Dictionary<string, string> _methods = new Dictionary<string, string>();
		void INITENV()
		{
			GLOBALS.SetPM(this);
			_mainENV["Color_Black"] = ConsoleColor.Black;
			_mainENV["Color_Blue"] = ConsoleColor.Blue;
			_mainENV["Color_Cyan"] = ConsoleColor.Cyan;
			_mainENV["Color_DarkBlue"] = ConsoleColor.DarkBlue;
			_mainENV["Color_DarkCyan"] = ConsoleColor.DarkCyan;
			_mainENV["Color_DarkGray"] = ConsoleColor.DarkGray;
			_mainENV["Color_DarkGreen"] = ConsoleColor.DarkGreen;
			_mainENV["Color_DarkMagenta"] = ConsoleColor.DarkMagenta;
			_mainENV["Color_DarkRed"] = ConsoleColor.DarkRed;
			_mainENV["Color_DarkYellow"] = ConsoleColor.DarkYellow;
			_mainENV["Color_Gray"] = ConsoleColor.Gray;
			_mainENV["Color_Green"] = ConsoleColor.Green;
			_mainENV["Color_Magenta"] = ConsoleColor.Magenta;
			_mainENV["Color_Red"] = ConsoleColor.Red;
			_mainENV["Color_White"] = ConsoleColor.White;
			_mainENV["Color_Yellow"] = ConsoleColor.Yellow;
		}
		public void _SetDENV(ENV env)
		{
			_mainENV = env;
		}
		public void makeThread(){
			isThread=true;
		}
		public bool isAThread(){
			return isThread;
		}
		public parseManager(string filepath)
		{
			InitFlags();
			_filepath = filepath;
			_defineType = Type.GetType("standardDefine");
			ConstructorInfo defineConstructor = _defineType.GetConstructor(Type.EmptyTypes);
			_defineClassObject = defineConstructor.Invoke(new object[]{ });
			_defualtENV = _mainENV;
			INITENV();
			Parse();
		}
		public parseManager(string filepath, string define)
		{
			InitFlags();
			_define = define;
			_filepath = filepath;
			_defineType = Type.GetType(define);
			ConstructorInfo defineConstructor = _defineType.GetConstructor(Type.EmptyTypes);
			_defineClassObject = defineConstructor.Invoke(new object[]{ });
			_defualtENV = _mainENV;
			INITENV();
			Parse();
		}
		public parseManager(string code, string define, bool c)
		{
			InitFlags();
			_define = define;
			_filepath = code;
			_isInternal = true;
			_defineType = Type.GetType(define);
			ConstructorInfo defineConstructor = _defineType.GetConstructor(Type.EmptyTypes);
			_defineClassObject = defineConstructor.Invoke(new object[]{ });
			_defualtENV = _mainENV;
			INITENV();
			Parse(code, c);
		}
		public parseManager(string code, bool c)
		{
			_isInternal = true;
			InitFlags();
			_filepath = code;
			_defineType = Type.GetType("standardDefine");
			ConstructorInfo defineConstructor = _defineType.GetConstructor(Type.EmptyTypes);
			_defineClassObject = defineConstructor.Invoke(new object[]{ });
			_defualtENV = _mainENV;
			INITENV();
			Parse(code, c);
		}
		public bool IsInternal()
		{
			return _isInternal;
		}
		public string GetFilepath()
		{
			return _filepath;
		}
		public string GetDefine()
		{
			return _define;
		}
		void InitFlags()
		{
			_flags.Add("leaking", false);
			_flags.Add("forseelabels", true);
			_flags.Add("debugging", false);
			_flags.Add("topdown", true);
			_flags.Add("casesensitive", true);
		}
		public ENV Pop()
		{
			return _fStack.Pop();
		}
		public bool GetFlag(string flag)
		{
			bool f;
			if (_flags.TryGetValue(flag, out f)) {
				return f;
			}
			return false;
		}
		public void debug(object msg)
		{
			if (_flags["debugging"])
				Console.WriteLine("DEBUGGING: " + msg);
		}
		void _Parse(string data)
		{
			foreach (Match m in Regex.Matches(data, @"LOAD ([a-zA-Z0-9_\./]+)")) {
				Parse(m.Groups[1].ToString());
			}
			foreach (Match m in Regex.Matches(data, @"ENABLE ([a-zA-Z0-9_\./]+)")) {
				_flags[m.Groups[1].ToString().ToLower()] = true;
			}
			foreach (Match m in Regex.Matches(data, @"DISABLE ([a-zA-Z0-9_\./]+)")) {
				_flags[m.Groups[1].ToString().ToLower()] = false;
			}
			foreach (Match m in Regex.Matches(data, @"ENTRY ([a-zA-Z0-9_\./]+)")) {
				_entry = m.Groups[1].ToString();
			}
			foreach (Match m in Regex.Matches(data, @"VERSION ([a-zA-Z0-9_\./]+)")) {
				if (Version.Parse(m.Groups[1].ToString()) != Version.Parse(_VERSION)) {
					PushError("Attempt to run a code created for a different version of the interperter/compiler!");
				}
			}
//			foreach (Match m in Regex.Matches(data, @"USING ([a-zA-Z0-9_\./]+)")) {
//				m.Groups[1].ToString();
//			}
			data = data + "\n";
			var match = Regex.Matches(data, "\\[(.+)\\][\r\n]*?\\{([^\0]+?)\\}\r?\n");
			var count = 0;
			foreach (Match m in match) {
				string Blck = m.Groups[1].ToString();
				string Cont = m.Groups[2].ToString();
				int loc = Blck.IndexOf(":", StringComparison.Ordinal);
				if (loc != -1) {
					_chunks[Blck.Substring(0, loc)] = new chunk(Blck.Substring(0, loc), Cont, Blck.Substring(loc + 1));
					Blck = Blck.Substring(0, loc);
				} else {
					_chunks[Blck] = new chunk(Blck, Cont);
				}
				count++;
				if (_lastChunk != null)
					_lastChunk.SetNextChunk(_chunks[Blck]);
				_lastChunk = _chunks[Blck];
			}
		}
		void Parse()
		{
			try {
				StreamReader sr = File.OpenText(_filepath);
				_Parse(sr.ReadToEnd());
				sr.Close();
			} catch (FileNotFoundException) {
				Console.WriteLine("File '" + _filepath + "' does not exist! Loading failled!");
			}
		}
		void Parse(string code, bool c)
		{
			_Parse(code);
		}
		void Parse(string filename)
		{
			try {
				StreamReader sr = File.OpenText(filename);
				_Parse(sr.ReadToEnd());
				sr.Close();
			} catch (FileNotFoundException) {
				Console.WriteLine("Load '" + filename + "' File not found. Loading failled!");
			}
		}
		public void ParseCode(string code)
		{
			_Parse(code);
		}
		public chunk[] GetChunks()
		{
			var chunks = _chunks.Values;
			var temp = new chunk[_chunks.Count];
			var i = 0;
			foreach (var item in _chunks) {
				temp[i] = item.Value;
				i++;
			}
			return temp;
		}
		public chunk GetCurrentChunk()
		{
			return _currentChunk;
		}
		public void Deactivate()
		{
			_active = false;
		}
		public bool isRegisteredFunction(string method, out chunk o)
		{
			if (_chunks.TryGetValue(method, out o)) {
				if (o.isFunction()) {
					return true;
				}
				return false;
			}
			return false;
		}
		public object InvokeI(string method, object[] argsV, chunk c,bool rets)
		{
			var ccP = _currentChunk.GetPos();
			var ccN = _currentChunk.GetName();
			var argsN = c.GetArgs();
			var fEnv = new ENV();
			fEnv.SetParent(_defualtENV);
			if (!(argsN.Length == 1 && argsN[0] == "")) {
				for (int i = 0; i < argsN.Length; i++) {
					fEnv[argsN[i]] = argsV[i];
				}
			}
			var tempEnv = new ENV();
			tempEnv[0] = ccN;
			tempEnv[1] = ccP;
			tempEnv[2] = _defualtENV;
			_fStack.Push(tempEnv);
			if (_fStack.Count > 1024) {
				PushError("Stack Overflow!");
			}
			_defualtENV = fEnv;
			def.JUMP(this, method);
			if(rets){
				return fEnv; // TODO Handle returns
			} else {
				return null;
			}
		}
		public object InvokeR(string method, object[] args)
		{
			chunk c;
			if (isRegisteredFunction(method, out c)) {
				return InvokeI(method, args, c, true);
			}
			try {
				_defineMethod = _defineType.GetMethod(method);
				return _defineMethod.Invoke(_defineClassObject, tackBArgs(this, args));
			} catch (Exception e) {
				PushError("Invalid method: " + method + "\n\n" + e);
				return null;
			}
		}
		public int InvokeNR(string method, object[] args)
		{
			chunk c;
			if (isRegisteredFunction(method, out c)) {
				InvokeI(method, args, c, false);
				return 0;
			}
			try {
				_defineMethod = _defineType.GetMethod(method);
				_defineMethod.Invoke(_defineClassObject, tackBArgs(this, args));
				return 0;
			} catch (Exception e) {
				PushError("Invalid method: " + method + "\n\n" + e);
				return -1;
			}
		}
		public object[] tackBArgs(object o, object[] args)
		{
			var len = args.Length;
			var newargs = new object[len + 1];
			for (int i = 0; i < len; i++) {
				newargs[i + 1] = args[i];
			}
			newargs[0] = o;
			return newargs;
		}
		public void SetBlock(string BLOCK)
		{
			chunk cchunk;
			if (_chunks.TryGetValue(BLOCK, out cchunk)) {
				_currentChunk = cchunk;
				_currentChunk.ResetPos();
			} else {
				PushError("Attempt to JUMP to a non existing block!");
			}
		}
		public ENV GetENV()
		{
			if (_defualtENV == null) {
				return _mainENV;
			}
			return _defualtENV;
		}
		public ENV GetDENV()
		{
			return _mainENV;
		}
		public void SetENV()
		{
			_defualtENV = _mainENV;
		}
		public void SetENV(ENV o)
		{
			_defualtENV = o;
		}
		public void SetBlock(chunk BLOCK)
		{
			_currentChunk = BLOCK;
		}
		public void SetBlock()
		{
			chunk cchunk;
			if (_chunks.TryGetValue(_entry, out cchunk)) {
				_currentChunk = cchunk;
				_currentChunk.ResetPos();
			} else {
				PushError("Entrypoint is Invalid!");
			}
		}
		public void PushError(string err)
		{
			Console.WriteLine(err + "\nPress Enter!");
			Console.ReadLine();
			def.EXIT(this);
		}
		public nextType Next(string BLOCK)
		{
			if (_currentChunk == null) {
				SetBlock(BLOCK);
			}
			return Next();
		}
		public nextType Next()
		{
			GLOBALS.SetPM(this);
			var tempReturn = new nextType();
			if (_currentChunk == null) {
				SetBlock();
			}
			var cCMD = _currentChunk.GetCLine();
			object[] stuff;
			if (cCMD == null) {
				if (_flags["leaking"] && _active) {
					var test = _currentChunk.GetNextChunk();
					if (test != null) {
						SetBlock(_currentChunk.GetNextChunk());
						return Next();
					}
				}
				tempReturn.SetCMDType("EOF");
				tempReturn.SetText("Reached the end of the file!");
				return tempReturn;
			}
			if (!_active) {
				tempReturn.SetCMDType("EOF");
				tempReturn.SetText("Reached the end of the file!");
				return tempReturn;
			}
			var type = cCMD.GetCMDType();
			stuff = cCMD.GetArgs();
			if (type == "LOGIC") {//{conds,andors,_funcif,_resultif,_funcelse,_resultelse}
				var conds = (string[])stuff[0];
				var andors = (string[])stuff[1];
				var funcif = (string)stuff[2];
				var argsif = (string[])stuff[3];
				var funcelse = (string)stuff[4];
				var argselse = (string[])stuff[5];
				var objs = new object[conds.Length]; // contain the actual values of what is in the env
				var truths = new bool[conds.Length / 3];
				var c = 0;
				for (int i = 0; i < conds.Length; i += 3) {
					var condA = (object)ResolveVar(new []{ conds[i] })[0];
					var e = conds[i + 1];
					var condB = (object)ResolveVar(new []{ conds[i + 2] })[0];
					if (e == "==") {
						truths[c] = condA.ToString() == condB.ToString();
					} else if (e == ">=") {
						truths[c] = (double)condA >= (double)condB;
					} else if (e == "<=") {
						truths[c] = (double)condA <= (double)condB;
					} else if (e == "!=" || e == "~=") {
						truths[c] = condA.ToString() != condB.ToString();
					} else if (e == ">") {
						truths[c] = (double)condA > (double)condB;
					} else if (e == "<") {
						truths[c] = (double)condA < (double)condB;
					} else {
						PushError("Invalid conditional test! " + e + " is not valid!");
					}
					c++;
				}
				var truth = truths[0];
				if (truths.Length == 1 && truth) {
					InvokeNR(funcif, ResolveVar(argsif));
				} else if (truths.Length == 1) {
					InvokeNR(funcelse, ResolveVar(argselse));
				} else {
					for (int i = 1; i < andors.Length; i++) {
						if (andors[i - 1] == "a") {
							truth = truth && truths[i];
						} else if (andors[i - 1] == "o") {
							truth = truth || truths[i];
						} else {
							PushError("Invalid conditional test! " + andors[i - 1] + " is not valid!");
						}
					}
					if (truth) {
						InvokeNR(funcif, ResolveVar(argsif));
					} else {
						InvokeNR(funcelse, ResolveVar(argselse));
					}
				}
				tempReturn.SetCMDType("conditional");
				tempReturn.SetText("test turned out to be: " + truth);
				return tempReturn;
			} else if (type == "LABEL") {
				tempReturn.SetCMDType("label");
				tempReturn.SetText("Jumped to a label!");
				return tempReturn;
			}
			if (type == "FUNC") {
				var func = (string)stuff[0];
				var args = (string[])stuff[1];
				if (args.Length == 1 && args[0] == "") { // assume no args inserted!
					InvokeNR(func, new object[]{ });
				} else {
					InvokeNR(func, ResolveVar(args));
				}
				tempReturn.SetCMDType("method");
				tempReturn.SetText("INVOKED METHOD: " + func);
				return tempReturn;
			} else if (type == "LINE") {
				tempReturn.SetCMDType("line");
				var test = parseHeader((string)stuff[0]);
				tempReturn.SetText(test.Substring(1, test.Length - 2));
				return tempReturn;
			} else if (type == "FUNC_R") {
				var retargs = (string[])stuff[0];
				var func = (string)stuff[1];
				var args = (string[])stuff[2];
				object data;
				var env = GetENV();
				if (args.Length == 1 && args[0] == "") { // assume no args inserted!
					data = InvokeR(func, new object[]{ });
				} else {
					data = InvokeR(func, ResolveVar(args));
				}
				env[retargs[0]] = data;
				GLOBALS.Add_Var(retargs[0]);
				tempReturn.SetCMDType("method");
				tempReturn.SetText("INVOKED METHOD: " + func);
				return tempReturn;
			} else if (type == "ASSIGN") { // TODO add lists/dictonaries support
				var vars = (string[])stuff[0];
				var vals = (string[])stuff[1];
				var env = GetENV();
				var types = ResolveVar(vals);
				AssignmentHandler(vars, types);
				tempReturn.SetCMDType("assignment");
				tempReturn.SetText(_currentChunk.GetLine());
				return tempReturn;
			}
			return tempReturn;
		}
		public void AssignmentHandler(string[] vars, object[] types)
		{
			var env = GetENV();
			for (int i = 0; i < types.Length; i++) {
				var test = vars[i];
				if (test.EndsWith("]")) {
					var dict = Regex.Match(test, @"(.*)\[(.+)\]");
					var _var = dict.Groups[1].Value;
					var _val = dict.Groups[2].Value;
					var val = ResolveVar(new []{ _val });
					var _e = env[_var];
					if (!_e.GetType().ToString().Contains("ENV")) {
						PushError("Attempted to index a object that isn't a table!");
					} else {
						var e = (ENV)_e;
						if (val[0].GetType().ToString().Contains("Double")) {
							e[int.Parse(val[0].ToString())] = types[i];
						} else if (val[0].GetType().ToString().Contains("String")) {
							e[(string)val[0]] = types[i];
						} else {
							PushError("Invalid index type: " + val[0]);
						}
					}
				} else {
					env[vars[i]] = types[i];
					GLOBALS.Add_Var(vars[i]);
				}
			}
		}
		public string parseHeader(string header)
		{
			var results = Regex.Matches(header, @"(\$.*?\$)");
			int len = results.Count;
			string str;
			object temp;
			for (int i = 0; i < len; i++) {
				str = results[i].ToString();
				if (isVar(str.Substring(1, str.Length - 2), out temp)) {
					header = header.Replace(results[i].ToString(), temp.ToString());
				} else {
					header = header.Replace(results[i].ToString(), "null");
				}
			}
			return header;
		}
		public object[] ResolveVar(string[] v)
		{
			//_defualtENV
			var len = v.Length;
			var args = new object[len];
			object val;
			double num;
			bool boo;
			double ex;
			for (int i = 0; i < len; i++) {
				if (!v[i].StartsWith("[") && !v[i].StartsWith("\""))
					ex = evaluater.Evaluate(v[i]);
				else
					ex = double.NaN;
				if (v[i].Length == 0 && len == 1) {
					return new object[]{ };
				}
				if (v[i] == "[]") {
					args[i] = new ENV();
					continue;
				}
				if (v[i].StartsWith("[")) {
					var result = GLOBALS.Split(v[i].Substring(1, v[i].Length - 2)); // TODO make ENV
					var res = ResolveVar(result);
					var env = new ENV();
					for (int g = 0; g < res.Length; g++) {
						env[g] = res[g];
					}
					args[i] = env;
					debug("TABLE: " + env);
				} else if (v[i].EndsWith("]")) {
					var dict = Regex.Match(v[i], @"(.*)\[(.+)\]");
					var _var = dict.Groups[1].Value;
					var _val = dict.Groups[2].Value;
					var val2 = ResolveVar(new []{ _val });
					var env = GetENV();
					var _e = env[_var];
					if (!_e.GetType().ToString().Contains("ENV")) {
						PushError("Attempted to index a object that isn't a table!");
					} else {
						var e = (ENV)_e;
						if (val2[0].GetType().ToString().Contains("Double")) {
							args[i] = e[int.Parse(val2[0].ToString())];
						} else if (val2[0].GetType().ToString().Contains("String")) {
							args[i] = e[(string)val2[0]];
						} else {
							PushError("Invalid index type: " + val2[0]);
						}
					}
				} else if (isVar(v[i], out val)) {
					args[i] = val;
					debug("RETREVING SAVED VAL");
				} else if (double.TryParse(v[i], out num)) {
					args[i] = num;
					debug("NUMBER: " + num);
				} else if (v[i][0] == '"' && v[i][v[i].Length - 1] == '"') {
					args[i] = parseHeader(v[i].Replace("\"", ""));
					debug("STRING: " + args[i]);
				} else if (bool.TryParse(v[i], out boo)) {
					args[i] = boo;
					debug("BOOL: " + boo);
				} else if (!double.IsNaN(ex)) {
					args[i] = ex;
				} else {
					args[i] = null;
				}
			}
			return args;
		}
		public bool isVar(string val, out object v)
		{
			debug("TESTING: " + val);
			if (_defualtENV == null) {
				_defualtENV = _mainENV;
			}
			debug("GETTING VAL FROM ENV: " + _defualtENV[val]);
			if (_defualtENV[val] != null) {
				v = _defualtENV[val];
				return true;
			}
			if (val.EndsWith("]")) {
				var dict = Regex.Match(val, @"(.*)\[(.+)\]");
				var _var = dict.Groups[1].Value;
				var _val = dict.Groups[2].Value;
				var val2 = ResolveVar(new []{ _val });
				var env = GetENV();
				var _e = env[_var];
				if (!_e.GetType().ToString().Contains("ENV")) {
					PushError("Attempted to index a object that isn't a table!");
				} else {
					var e = (ENV)_e;
					if (val2[0].GetType().ToString().Contains("Double")) {
						v = e[int.Parse(val2[0].ToString())];
						return true;
					} else if (val2[0].GetType().ToString().Contains("String")) {
						v = e[(string)val2[0]];
						return true;
					} else {
						PushError("Invalid index type: " + val2[0]);
					}
				}
			}
			v = null;
			return false;
		}
	}
	/*
	 * Helper Classes
	 */
	public class chunk
	{
		string _BLOCK;
		string _type;
		string _pureType;
		string[] _lines;
		string[] args;
		bool isFunc;
		Dictionary<string, int> _labels = new Dictionary<string, int>();
		List<CMD> _compiledlines = new List<CMD>();
		int _pos = 0;
		chunk _next = null;
		public string[] GetArgs()
		{
			return args;
		}
		public chunk(string name, string cont, string type)
		{
			_BLOCK = name;
			_type = type;
			_clean(cont);
		}
		public bool isFunction()
		{
			return isFunc;
		}
		public chunk(string name, string cont)
		{
			_BLOCK = name;
			_type = "CODEBLOCK";
			_clean(cont);
		}
		void _clean(string cont)
		{
			var m = Regex.Match(_type, @"([a-zA-Z0-9_]+)");
			_pureType = m.Groups[1].ToString();
			var tCont = Regex.Replace(cont, @"\-\-\[\[[\S\s]+\]\]", "", RegexOptions.Multiline);
			tCont = Regex.Replace(tCont, @"\t", "", RegexOptions.Multiline);
			tCont = Regex.Replace(tCont, @"^\-\-.+\r\n", "", RegexOptions.Multiline);
			tCont = Regex.Replace(tCont, @"^\-\-.+\n", "", RegexOptions.Multiline);
			tCont = Regex.Replace(tCont, @"\n\n", "", RegexOptions.Multiline);
			tCont = Regex.Replace(tCont, @"\r\n\r\n", "", RegexOptions.Multiline);
			tCont = Regex.Replace(tCont, @"\-\-\[\[[\S\s]+\]\]", "", RegexOptions.Multiline);
			tCont = Regex.Replace(tCont, @"^\s+$[\r\n]*", "", RegexOptions.Multiline);
			_lines = tCont.Split(new [] { "\r\n", "\n" }, StringSplitOptions.None);
			compile();
		}
		void compile()
		{
			string temp;
			for (int i = 0; i < _lines.Length - 1; i++) {
				temp = _lines[i];
				var pureLine = Regex.Match(temp, "^\"(.+)\"");
				var FuncTest = Regex.Match(temp, @"([a-zA-Z0-9_]+)\s?\((.*)\)");
				var assignment = Regex.Match(temp, "^([a-zA-Z0-9_,\\[\\]\"]+)=([a-zA-Z\\|&\\^\\+\\-\\*/%0-9_\",\\[\\]]+)");
				var FuncWReturn = Regex.Match(temp, "([\\[\\]\"a-zA-Z0-9_,]+)\\s?=\\s?([a-zA-Z0-9_]+)\\s?\\((.*)\\)");
				var FuncWOReturn = Regex.Match(temp, @"^([a-zA-Z0-9_]+)\s?\((.*)\)");
				var label = Regex.Match(temp, "::(.*)::");
				var logic = Regex.Match(temp, @"if\s*(.+)\s*then\s*(.+?\))\s*\|\s*(.+?\))");
				
				if (logic.ToString() != "") {
					var condition = logic.Groups[1].ToString();
					var tempif = logic.Groups[2].ToString();
					var tempelse = logic.Groups[3].ToString();
					var argsif = Regex.Match(tempif, @"^([a-zA-Z0-9_]+)\s?\((.*)\)");
					var argselse = Regex.Match(tempelse, @"^([a-zA-Z0-9_]+)\s?\((.*)\)");
					string _funcif = (argsif.Groups[1]).ToString();
					var _argsif = (argsif.Groups[2]).ToString();
					string[] _resultif = GLOBALS.Split(_argsif);
					string _funcelse = (argselse.Groups[1]).ToString();
					var _argselse = (argselse.Groups[2]).ToString();
					string[] _resultelse = GLOBALS.Split(_argselse);
					var mm = Regex.Matches(condition, "(.+?)([and ]+?[or ]+)");
					var conds = new string[(mm.Count + 1) * 3];
					var andors = new string[mm.Count];
					var count = 0;
					var p = 0;
					var p2 = 0;
					foreach (Match m in mm) {
						var s1 = m.Groups[1].ToString();
						var s1p = Regex.Match(s1, "(.+?)([~!><=]+)+(.+)");
						var s1a = s1p.Groups[1].ToString();
						var s1b = s1p.Groups[2].ToString();
						var s1c = s1p.Groups[3].ToString();
						var s2 = m.Groups[2].ToString();
						conds[p++] = s1a;
						conds[p++] = s1b;
						conds[p++] = s1c;
						andors[p2++] = s2.Substring(1, 1);
						count += s1.Length + s2.Length;
					}
					var s1p2 = Regex.Match(condition.Substring(count, condition.Length - count - 1), "(.+?)([~!><=]+)+(.+)");
					var s1a2 = s1p2.Groups[1].ToString();
					var s1b2 = s1p2.Groups[2].ToString();
					var s1c2 = s1p2.Groups[3].ToString();
					conds[p++] = s1a2;
					conds[p++] = s1b2;
					conds[p++] = s1c2;
					_compiledlines.Add(new CMD("LOGIC", new object[] {
						conds,
						andors,
						_funcif,
						_resultif,
						_funcelse,
						_resultelse
					}));
				} else if (label.ToString() != "") {
					_labels[label.Groups[1].ToString()] = i;
					_compiledlines.Add(new CMD("LABEL", new object[]{ }));
				} else if (FuncWReturn.ToString() != "") {
					var var1 = (FuncWReturn.Groups[1]).ToString();
					var func = (FuncWReturn.Groups[2]).ToString();
					var args2 = (FuncWReturn.Groups[3]).ToString();
					var retargs = GLOBALS.Split(var1);
					var result = GLOBALS.Split(args2);
					_compiledlines.Add(new CMD("FUNC_R", new object[] {
						retargs,
						func,
						result
					}));
				} else if (FuncWOReturn.ToString() != "") {
					var func = (FuncWOReturn.Groups[1]).ToString();
					var args2 = (FuncWOReturn.Groups[2]).ToString();
					var result = GLOBALS.Split(args2);
					_compiledlines.Add(new CMD("FUNC", new object[]{ func, result }));
				} else if (pureLine.ToString() != "") {
					_compiledlines.Add(new CMD("LINE", new object[]{ pureLine.ToString() }));
				} else if (assignment.ToString() != "") {
					var vars = GLOBALS.Split(assignment.Groups[1].ToString());
					var tabTest = assignment.Groups[2].ToString();
					string[] vals = GLOBALS.Split(tabTest);
					//vals = Regex.Split(assignment.Groups[2].ToString(), ",(?=(?:[^\"'\\[\\]]*[\"'\\[\\]][^\"'\\[\\]]*[\"'\\[\\]])*[^\"'\\[\\]]*$)");
					_compiledlines.Add(new CMD("ASSIGN", new object[]{ vars, vals }));
				} else {
					_compiledlines.Add(new CMD("UNKNOWN", new object[]{ }));
				}
			}
			if (_type.Contains("function")) {
				isFunc = true;
				var func = Regex.Match(_type, @"\((.+)\)");
				args = GLOBALS.Split(func.Groups[1].Value);
				_compiledlines.Add(new CMD("FUNC", new object[] {
					"TRACEBACK",
					new string[]{ }
				})); // Append the traceback method to the chunk
			}
		}
		public string GetName()
		{
			return _BLOCK;
		}
		public int GetLabel(string lab)
		{
			return _labels[lab];
		}
		public bool TryGetLabel(string lab, out int pos)
		{
			int p;
			if (_labels.TryGetValue(lab, out p)) {
				pos = p;
				return true;
			}
			pos = -1;
			return false;
		}
		public void RemoveNextChunk()
		{
			_next = null;
		}
		public void SetNextChunk(chunk next)
		{
			_next = next;
		}
		public chunk GetNextChunk()
		{
			return _next;
		}
		public chunk SetNextChunk()
		{
			return _next;
		}
		public string[] GetLines()
		{
			return _lines;
		}
		public string GetLine()
		{
			string temp = _lines[_pos];
			if (_pos == _lines.Length) {
				return null;
			}
			return temp;
		}
		public CMD GetCLine()
		{
			if (_pos < _compiledlines.Count) {
				return _compiledlines[_pos++];
			}
			return null;
		}
		public int GetPos()
		{
			return _pos;
		}
		public void SetPos(int n)
		{
			_pos = n;
		}
		public void ResetPos()
		{
			_pos = 0;
		}
		public string GetChunkPType()
		{
			return _pureType;
		}
		public string GetChunkType()
		{
			return _type;
		}
	}
	public static class evaluater
	{
		static double helper(ENV env, parseManager PM, string o, object _v, object _r)
		{
			double v = 0;
			double r = 0;
			if (_v.GetType().ToString() == "System.String") {
				object temp;
				if (env.TryGetValue((string)_v, out temp)) {
					v = (double)temp;
				} else if (double.TryParse((string)_v, out v)) {
					// We good!
				} else {
					PM.PushError("Attempt to do arithmetic on a null value: " + _v);
				}
			} else {
				v = (double)_v;
			}
			if (_r.GetType().ToString() == "System.String") {
				object temp;
				if (env.TryGetValue((string)_r, out temp)) {
					r = (double)temp;
				} else if (double.TryParse((string)_r, out r)) {
					// We good!
				} else {
					PM.PushError("Attempt to do arithmetic on a null value: " + _r);
				}
			} else {
				v = (double)_v;
			}
			// Constructs?
			if (o == "+") {
				return r + v;
			} else if (o == "-") {
				return r - v;
			} else if (o == "/") {
				return r / v;
			} else if (o == "*") {
				return r * v;
			} else if (o == "^") {
				return Math.Pow(r, v);
			} else if (o == "%") {
				return r % v;
			}
			return 0;
		}
		public static double Evaluate(string cmd)
		{
			return Evaluate(cmd, 0);
		}
		public static double Evaluate(string cmd, double v)
		{
			double test;
			if (cmd.Length == 0) {
				return double.NaN;
			}
			if (double.TryParse(cmd, out test)) {
				return test;
			}
			var loop = false;
			if (cmd.Substring(0, 1) == "-") {
				cmd = "0" + cmd;
			}
			var PM = GLOBALS.GetPM();
			var env = PM.GetENV();
			var count = 0;
			var para = Regex.Match(cmd, @"(\(.+\))");
			if (para.ToString() != "") {
				return Evaluate(para.Groups[1].Value.Substring(1, para.Groups[1].Value.Length - 2));
			}
			foreach (Match m in Regex.Matches(cmd,@"(.*)([/%\+\^\-\*])(.*)")) {
				loop = true;
				count++;
				var l = m.Groups[1].Value;
				var o = m.Groups[2].Value;
				var r = m.Groups[3].Value;
				if (Regex.Match(l, @"([/%\+\^\-\*])").ToString() != "") {
					v = Evaluate(l, v);
					v = helper(env, PM, o, r, v);
				} else if (count == 1) {
					v = helper(env, PM, o, r, l);
				}
			}
			if (!loop) {
				object t;
				if (env != null)
				if (env.TryGetValue(cmd, out t)) {
					double te;
					if (t.GetType().ToString().Contains("Double"))
						return (double)t;
					if (t.GetType().ToString().Contains("String"))
					if (double.TryParse((string)t, out te)) {
						return te;
					}
					return double.NaN;
				} else {
					t = double.NaN; // It couldn't be done :'(
				}
			}
			return v; // TODO grab current ENV and does the calculation
		}
	}
	[Serializable]
	public class ENV
	{
		ENV _Parent;
		Dictionary<string, object> _vars = new Dictionary<string, object>();
		Dictionary<int, object> _varsI = new Dictionary<int, object>();
		public void SetParent(ENV other)
		{
			_Parent = other;
		}
		public object[] GetList()
		{
			var temp = new object[_varsI.Count];
			var count = 0;
			foreach (KeyValuePair<int, object> entry in _varsI) {
				temp[count] = entry.Value;
				count++;
			}
			return temp;
		}
		public override string ToString()
		{
			string str = "(";
			foreach (KeyValuePair<string, object> entry in _vars) {
				var val = entry.Value;
				if (val.GetType().ToString().Contains("ENV")) {
					val = "ENV";
				}
				str += "[\"" + entry.Key + "\"] = " + val + ", ";
			}
			foreach (KeyValuePair<int, object> entry in _varsI) {
				str += "[" + entry.Key + "] = " + entry.Value + ", ";
			}
			return str + ")";
		}
		public bool TryGetValue(string ind, out object obj)
		{
			if (this[ind] != null) {
				obj = this[ind];
				return true;
			}
			obj = null;
			return false;
		}
		public bool TryGetValue(int ind, out object obj)
		{
			if (this[ind] != null) {
				obj = this[ind];
				return true;
			}
			obj = null;
			return false;
		}
		public object this[string ind] {
			get {
				object obj;
				if (!GLOBALS.GetFlag("casesensitive")) {
					ind = ind.ToLower();
				}
				if (_vars.TryGetValue(ind, out obj)) {
					return obj;
				}
				if (_Parent != null) {
					return _Parent[ind];
				}
				return null;
			}
			set {
				if (!GLOBALS.GetFlag("casesensitive")) {
					ind = ind.ToLower();
				}
				_vars[ind] = value;
			}
		}
		public object this[int ind] {
			get {
				object obj;
				if (_varsI.TryGetValue(ind, out obj)) {
					return obj;
				}
				if (_Parent != null) {
					return _Parent[ind];
				}
				return null;
			}
			set {
				_varsI[ind] = value;
			}
		}
	}
	public class nextType
	{
		string _type;
		string _text;
		Dictionary<string, object> _other = new Dictionary<string, object>();
		public nextType()
		{
			_type = "UNSET";
		}
		public nextType(string type)
		{
			_type = type;
		}
		public string GetCMDType()
		{
			return _type;
		}
		public void SetText(string text)
		{
			_text = text;
		}
		public void SetCMDType(string type)
		{
			_type = type;
		}
		public string GetText()
		{
			return _text;
		}
		public object GetData(string name)
		{
			return _other[name];
		}
		public void AddData(string varname, object data)
		{
			_other[varname] = data;
		}
	}

	public class CMD
	{
		string _type;
		object[] _args;
		public CMD(string type, object[] args)
		{
			_type = type;
			_args = args;
		}
		public string GetCMDType()
		{
			return _type;
		}
		public object[] GetArgs()
		{
			return _args;
		}
	}
	/*
	 * The Standard Methods!
	 */
	static class GLOBALS
	{
		static standardDefine _define = new standardDefine();
		static parseManager _current;
		static readonly ENV _env = new ENV();
		static List<string> _numvars = new List<string>();
		static List<parseManager> _Threads = new List<parseManager>();
		public static void AddThread(parseManager PM)
		{
			_Threads.Add(PM);
		}
		public static void FixThreads(parseManager PM)
		{
			var PMS = _Threads.ToArray();
			var env = PM.GetDENV();
			for (int i = 0; i < PMS.Length; i++) {
				PMS[i]._SetDENV(env);
				PMS[i].SetENV(env);
			}
		}
		public static void WriteToBinaryFile(string filePath, ENV objectToWrite, bool append = false)
		{
			using (Stream stream = File.Open(filePath, append ? FileMode.Append : FileMode.Create)) {
				var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
				binaryFormatter.Serialize(stream, objectToWrite);
			}
		}
		public static ENV ReadFromBinaryFile(string filePath)
		{
			using (Stream stream = File.Open(filePath, FileMode.Open)) {
				var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
				return (ENV)binaryFormatter.Deserialize(stream);
			}
		}
		public static object GetData(string ind)
		{
			return _env[ind];
		}
		public static standardDefine GetDefine()
		{
			return _define;
		}
		public static void AddData(string ind, object data)
		{
			_env[ind] = data;
		}
		public static void SetPM(parseManager o)
		{
			_current = o;
		}
		public static parseManager GetPM()
		{
			return _current;
		}
		public static bool GetFlag(string flag)
		{
			var PM = GetPM();
			return PM.GetFlag(flag);
		}
		public static void Add_Var(string var)
		{
			if (!_numvars.Contains(var)) {
				_numvars.Add(var);
			}
		}
		public static void Remove_Var(string var)
		{
			_numvars.Remove(var);
		}
		public static string[] GetVars()
		{
			return _numvars.ToArray();
		}
		public static string[] Split(string split)
		{
			var res = new List<string>();
			var state = 0;
			var c = ".";
			var elem = "";
			for (int gg = 0; gg < split.Length; gg++) {
				c = split.Substring(gg, 1);
				if (state == 3 || state == 0) {
					if (state == 3 && c == " ") {
						state = 0;
					} else {
						state = 0;
						if (c == "\"" || c == "'") {
							state = 1;
							elem += "\"";
						} else if (c == "[") {
							state = 1;
							elem += "[";
						} else if (c == ",") {
							res.Add(elem);
							elem = "";
							state = 3;
						} else {
							elem += c;
						}
					}
				} else if (state == 1) {
					if (c == "\"" || c == "'") {
						state = 0;
						elem += "\"";
					} else if (c == "]") {
						state = 0;
						elem += "]";
					} else if (c == "\\") {
						state = 2;
					} else {
						elem += c;
					}
				} else if (state == 2) {
					elem += c;
					state = 1;
				}
			}
			res.Add(elem);
			return res.ToArray();
		}
	}
}
public class standardDefine
{
	List<IWavePlayer> devices = new List<IWavePlayer>();
	int count = -1;
	Random rnd = new Random();
	int origRow = Console.CursorTop;
	int origCol = Console.CursorLeft;
	public void newThread(parseManager PM, string Block)
	{
		var thread = new Thread(() => _THREAD(Block, PM));
		thread.Start();
	}
	public void _THREAD(string block, parseManager _PM)
	{
		var define = _PM.GetDefine();
		var path = _PM.GetFilepath();
		parseManager PM;
		if (_PM.IsInternal()) {
			if (define == "NO_DEFINE") {
				PM = new parseManager(path, true);
			} else {
				PM = new parseManager(path, define, true);
			}
		} else {
			if (define == "NO_DEFINE") {
				PM = new parseManager(path);
			} else {
				PM = new parseManager(path, define);
			}
		}
		GLOBALS.AddThread(PM);
		PM.makeThread();
		PM._SetDENV(_PM.GetDENV());
		PM.SetENV(_PM.GetENV());
		nextType next = PM.Next(block);
		string type;
		while (next.GetCMDType() != "EOF") {
			type = next.GetCMDType();
			next = PM.Next();
		}
	}
	public void SAVE(parseManager PM)
	{
		if(PM.isAThread()){
			PM.PushError("Cannot Call SAVE() in a thread!");
		}
		var env = PM.GetDENV();
		var c = PM.GetCurrentChunk();
		env["__CurrentChunkName"] = c.GetName();
		env["__CurrentChunkPos"] = c.GetPos();
		env["__DefualtENV"] = PM.GetENV();
		GLOBALS.WriteToBinaryFile("savedata.dat", env);
	}
	public bool LOAD(parseManager PM)
	{
		if(PM.isAThread()){
			PM.PushError("Cannot Call LOAD() in a thread!");
		}
		try {
			ENV env = GLOBALS.ReadFromBinaryFile("savedata.dat");
			var name = (string)env["__CurrentChunkName"];
			var pos = (int)env["__CurrentChunkPos"];
			var denv = (ENV)env["__DefualtENV"];
			PM._SetDENV(env);
			PM.SetENV(denv);
			PM.SetBlock(name);
			PM.GetCurrentChunk().SetPos(pos);
			GLOBALS.FixThreads(PM);
			return true;
		} catch {
			return false;
		}
	}
	public void TRACEBACK(parseManager PM)
	{
		ENV env = PM.Pop();
		PM.SetBlock((string)env[0]);
		var c = PM.GetCurrentChunk();
		c.SetPos((int)env[1]);
		setENV(PM, (ENV)env[3]);
	}
	public void EXIT(parseManager PM)
	{
		cleanUpAudio();
		PM.Deactivate();
	}
	public void QUIT(parseManager PM)
	{
		cleanUpAudio();
		Environment.Exit(0);
	}
	public void setENV(parseManager PM, ENV env)
	{
		PM.SetENV(env);
	}
	public ENV getENV(parseManager PM)
	{
		return PM.GetENV();
	}
	public ENV getDefualtENV(parseManager PM)
	{
		return PM.GetDENV();
	}
	public ENV createENV(parseManager PM)
	{
		var temp = new ENV();
		temp.SetParent(PM.GetENV());
		return temp;
	}
	public string getInput(parseManager PM)
	{
		return Console.ReadLine();
	}
	public void setCC(parseManager PM)
	{
		Console.SetCursorPosition(0, Console.CursorTop - 1);
	}
	public void whiteOut(parseManager PM)
	{
		for (int i = 0; i < Console.BufferWidth; i++) {
			Console.Write(" ");
		}
	}
	public void setBG(parseManager PM, ConsoleColor BG)
	{
		Console.BackgroundColor = BG;
	}
	public void setFG(parseManager PM, ConsoleColor FG)
	{
		Console.ForegroundColor = FG;
	}
	public void resetColor(parseManager PM)
	{
		Console.ResetColor();
	}
	public int GOTO(parseManager PM, string label)
	{
		var c = PM.GetCurrentChunk();
		int pos;
		if (c.TryGetLabel(label, out pos)) {
			c.SetPos(pos);
			return 0;
		} else if (PM.GetFlag("forseelabels")) {
			var chunks = PM.GetChunks();
			for (int i = 0; i < chunks.Length; i++) {
				if (chunks[i].TryGetLabel(label, out pos)) {
					PM.SetBlock(chunks[i].GetName());
					chunks[i].SetPos(pos);
					return 0;
				}
			}
		}
		PM.PushError("Unable to GOTO a non existing label: " + label + "!");
		return 0;
	}
	public double len(parseManager PM, object o)
	{
		string type = o.GetType().ToString();
		if (type.Contains("String")) {
			return (double)((string)o).Length;
		}
		if (type.Contains("ENV")) {
			return (double)((ENV)o).GetList().Length;
		}
		return 0;
	}
	public void JUMP(parseManager PM, string block)
	{
		var c = PM.GetCurrentChunk();
		c.ResetPos();
		PM.SetBlock(block);
	}
	public void SKIP(parseManager PM, double n)
	{
		var c = PM.GetCurrentChunk();
		var pos = c.GetPos();
		c.SetPos(pos + (int)n);
	}
	public double tonumber(parseManager PM, string strn)
	{
		double d;
		if (double.TryParse(strn, out d)) {
			return d;
		}
		PM.debug("Cannot convert to a number!");
		return double.NaN;
	}
	public void sleep(parseManager PM, double n)
	{
		Thread.Sleep((int)n);
	}
	public void setVar(parseManager PM, string var, object value)
	{
		var env = PM.GetDENV();
		env[var] = value;
	}
	public double ADD(parseManager PM, double a, double b)
	{
		return a + b;
	}
	public double SUB(parseManager PM, double a, double b)
	{
		return a - b;
	}
	public double MUL(parseManager PM, double a, double b)
	{
		return a * b;
	}
	public double DIV(parseManager PM, double a, double b)
	{
		return a / b;
	}
	public double MOD(parseManager PM, double a, double b)
	{
		return a % b;
	}
	public double CALC(parseManager PM, string ex)
	{
		return evaluater.Evaluate(ex);
	}
	public void pause(parseManager PM)
	{
		Console.ReadLine();
	}
	public void print(parseManager PM, object o)
	{
		Console.WriteLine(o);
	}
	public double random(parseManager PM, double s, double e)
	{
		return (double)rnd.Next((int)s, (int)e);
	}
	public double rand(parseManager PM)
	{
		return rnd.NextDouble();
	}
	public double round(parseManager PM, double num, double n)
	{
		return Math.Round(num, (int)n);
	}
	public void clear(parseManager PM)
	{
		Console.Clear();
	}
	public void write(parseManager PM, object o)
	{
		Console.Write(o);
	}
	public void backspace(parseManager PM)
	{
		Console.Write("\b");
	}
	public void beep(parseManager PM)
	{
		Console.Beep();
	}
	public void fancy(parseManager PM, string msg)
	{
		Fancy.Print(msg);
	}
	public void setFancyForm(parseManager PM, string form)
	{
		Fancy.SetForm(form);
	}
	public void setFancyType(parseManager PM, double f)
	{
		Fancy.SetFVar((int)f);
	}
	public void stopSong(parseManager PM, double id)
	{
		devices[(int)id].Stop();
	}
	public void playSong(parseManager PM, double id)
	{
		devices[(int)id].Play();
	}
	public void resumeSong(parseManager PM, double id)
	{
		devices[(int)id].Play();
	}
	public void setSongVolume(parseManager PM, double id, double vol)
	{
		devices[(int)id].Volume = (float)vol;
	}
	public void pauseSong(parseManager PM, double id)
	{
		devices[(int)id].Pause();
	}
	public void replaySong(parseManager PM, double id)
	{
		devices[(int)id].Stop();
		devices[(int)id].Play();
	}
	public double loadSong(parseManager PM, string filepath)
	{
		count++;
		devices.Add(new WaveOut());
		var temp = new AudioFileReader(filepath);
		devices[count].Init(temp);
		return count;
	}
	void cleanUpAudio()
	{
		for (int i = 0; i < devices.Count; i++) {
			devices[i].Stop();
			devices[i].Dispose();
		}
	}
	public void setPosition(parseManager PM, double x, double y)
	{
		Console.SetCursorPosition((int)x, (int)y);
	}
	public void writeAt(parseManager PM, string s, double x, double y)
	{
		try {
			Console.SetCursorPosition(origCol + (int)x, origRow + (int)y);
			Console.Write(s);
		} catch (ArgumentOutOfRangeException e) {
			Console.Clear();
			Console.WriteLine(e.Message);
		}
	}
	public bool isDown(parseManager PM, string key)
	{
		if (!ApplicationIsActivated()) {
			return false;
		}
		Key kk = Key.Zoom;
		var k = key.ToUpper();
		if (k == "A") {
			kk = Key.A;
		} else if (k == "B") {
			kk = Key.B;
		} else if (k == "C") {
			kk = Key.C;
		} else if (k == "D") {
			kk = Key.D;
		} else if (k == "E") {
			kk = Key.E;
		} else if (k == "F") {
			kk = Key.F;
		} else if (k == "G") {
			kk = Key.G;
		} else if (k == "H") {
			kk = Key.H;
		} else if (k == "I") {
			kk = Key.I;
		} else if (k == "J") {
			kk = Key.J;
		} else if (k == "K") {
			kk = Key.K;
		} else if (k == "L") {
			kk = Key.L;
		} else if (k == "M") {
			kk = Key.M;
		} else if (k == "N") {
			kk = Key.N;
		} else if (k == "O") {
			kk = Key.O;
		} else if (k == "P") {
			kk = Key.P;
		} else if (k == "Q") {
			kk = Key.Q;
		} else if (k == "R") {
			kk = Key.R;
		} else if (k == "S") {
			kk = Key.S;
		} else if (k == "T") {
			kk = Key.T;
		} else if (k == "U") {
			kk = Key.U;
		} else if (k == "V") {
			kk = Key.V;
		} else if (k == "W") {
			kk = Key.W;
		} else if (k == "X") {
			kk = Key.X;
		} else if (k == "Y") {
			kk = Key.Y;
		} else if (k == "Z") {
			kk = Key.Z;
		} else if (k == "{UP}") {
			kk = Key.Up;
		} else if (k == "{DOWN}") {
			kk = Key.Down;
		} else if (k == "{LEFT}") {
			kk = Key.Left;
		} else if (k == "{RIGHT}") {
			kk = Key.Right;
		} else if (k == "{ENTER}") {
			kk = Key.Enter;
		} else if (k == "{LSHIFT}") {
			kk = Key.LeftShift;
		} else if (k == "{RSHIFT}") {
			kk = Key.RightShift;
		} else if (k == "0") {
			kk = Key.D0;
		} else if (k == "1") {
			kk = Key.D1;
		} else if (k == "2") {
			kk = Key.D2;
		} else if (k == "3") {
			kk = Key.D3;
		} else if (k == "4") {
			kk = Key.D4;
		} else if (k == "5") {
			kk = Key.D5;
		} else if (k == "6") {
			kk = Key.D6;
		} else if (k == "7") {
			kk = Key.D7;
		} else if (k == "8") {
			kk = Key.D8;
		} else if (k == "9") {
			kk = Key.D9;
		} else if (k == "{SPACE}") {
			kk = Key.Space;
		}
		return Keyboard.IsKeyDown(kk);
	}
	public string isPressing(parseManager PM)
	{
		return Console.ReadKey(true).Key.ToString();
	}
	public static bool ApplicationIsActivated()
	{
		var activatedHandle = GetForegroundWindow();
		if (activatedHandle == IntPtr.Zero) {
			return false;       // No window is currently activated
		} else {
			var procId = Process.GetCurrentProcess().Id;
			int activeProcId;
			GetWindowThreadProcessId(activatedHandle, out activeProcId);
			return activeProcId == procId;
		}
	}
	[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
	static extern IntPtr GetForegroundWindow();

	[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
	static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
}