//  
//  GLScript.cs
//  
//  Author:
//       Robert BRACCAGNI alias Gai-Luron <lfsgailuron@free.fr>
// 
//  Copyright (c) 2010 Gai-Luron
// 
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
// 
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections;
using System.Text.RegularExpressions;
using System.Linq;
using Configurator;
using UTILS;

namespace GLScript
{
    public class GLApp
    {
        public class GLScriptException : Exception
        {
            public GLScriptException(string message) : base(message) { }
            public GLScriptException(string message, Exception innerException) : base(message, innerException) { }
        }
        public class functionDef
        {
            public string[] argsNames;
            public int nbArgs = 0;
            public TokenBuffer tkb;
            public int StartLineInSrc;
            public bool retFlag = false;
            public ArrayList functionAttached = new ArrayList();
            public functionDef(string[] pargsNames, int pnbArgs, TokenBuffer ptkb, int pStartLineInSrc)
            {
                this.argsNames = pargsNames;
                this.tkb = ptkb;
                this.StartLineInSrc = pStartLineInSrc;
                this.nbArgs = pnbArgs;
            }
        }
        Stack stk = new Stack(2048);


        bool retFlag = false;
        private string nameApp;
        public SetOfVars GVAR = new SetOfVars( );
        private System.Collections.Hashtable Functions = new System.Collections.Hashtable();
        public delegate void callBackFunction(unionVal var, ArrayList ar);
        Hashtable listOfCallBackFunctions = new Hashtable();
		public long funcTimeOut = 2000; // Function timeOut, limit infinite loop
		private DateTime funcTimeOutTime;
        private GLDebug.Debug myDebug;

        const int R_CONTINUE = 1;
        const int R_BREAK = 2;
        const int R_ERROR = -1;

        public GLApp( GLDebug.Debug pmyDebug, string p_nameApp)
        {
            this.nameApp = p_nameApp;
            this.myDebug = pmyDebug;
        }
        public GLApp(string p_nameApp)
        {
            this.nameApp = p_nameApp;
        }
        public void registerCallBackFunction( string functionName,  callBackFunction pCBF )
        {
            listOfCallBackFunctions[ functionName.ToLower() ] = pCBF;
        }
		public void registerFunction(string funcName, string buffer, string pargsNames, string fileName, int StartLineInSrc, string AttachToEvent, Hashtable localconst, Hashtable globalconst)
        {
            string[] argsNames = null;
            int nbArgs = 0;
            if (pargsNames != "")
            {
                argsNames = pargsNames.Split(',');
                nbArgs = argsNames.Length;
            }
            
            Functions[funcName.ToLower()] = new functionDef(argsNames, nbArgs, new TokenBuffer(buffer, fileName, StartLineInSrc,localconst,globalconst), StartLineInSrc);

			if (AttachToEvent != "")
            {
                if (Functions.Contains(AttachToEvent.ToLower()))
                {
                    functionDef currFunc = (functionDef)( Functions[AttachToEvent.ToLower()] );
                    currFunc.functionAttached.Add(funcName.ToLower()); // Attach a function to this function
                                                                       
                }
            }
        }
        public void registerFunction( string funcName, functionDef myFuncDef )
        {
            Functions[funcName.ToLower()] = myFuncDef;
        }
        public void dumpFunction(string funcName)
        {
            funcName = funcName.ToLower();
            TokenBuffer tkb = (Functions[funcName] as functionDef).tkb;
            for (int i = 0; i < tkb.TokenList.Count; i++)
            {
                token tk = (token)tkb.TokenList[i];
                myDebug.WriteLine("err",tk.typ + " : " + tk.value + " at file " + tk.fileName +" line " + tk.lineNumber);
            }
        }
        public void dumpNamesFunctions()
        {
            foreach (DictionaryEntry d in Functions)
            {
                Console.WriteLine(d.Key);
            }
        }
        public bool existFunction(string funcName)
        {
            funcName = funcName.ToLower();
            return (Functions.ContainsKey(funcName));
        }
        public void setReturnFlagFunction(string funcName, bool flg)
        {
            funcName = funcName.ToLower();
            (Functions[funcName] as functionDef).retFlag = flg;
        }
        public bool isReturnFlagFunction(string funcName)
        {
            funcName = funcName.ToLower();
            return (Functions[funcName] as functionDef).retFlag;
        }

        public bool executeFunction(string funcName, string[] argsVals)
        {
            bool ret;
            ret = privExecuteFunction(funcName, argsVals);
            funcName = funcName.ToLower();
            if (Functions.Contains(funcName))
            {
                functionDef currFunc = (functionDef)Functions[funcName];
                for (int i = 0; i < currFunc.functionAttached.Count; i++)
                {
                    ret = privExecuteFunction((string)currFunc.functionAttached[i], argsVals); // Execute Attached Function
                }
            }
            stk.Clear();
            return ret;
        }

		private bool privExecuteFunction(string funcName, string[] argsVals)
		{
			funcName = funcName.ToLower();
            if (!Functions.Contains(funcName))
				return false;
			(Functions[funcName] as functionDef).retFlag = false;
			SetOfVars LVAR = new SetOfVars();
			int lg = 0;
			if (argsVals != null)
				lg = argsVals.Length;

            if (lg != (Functions[funcName] as functionDef).nbArgs)
			{
				string errorMsg = "Syntax error: Incorrect number of arguments at line #" + (Functions[funcName] as functionDef).StartLineInSrc + " in function '" + funcName + "' script aborted";
				myDebug.WriteLine("err", errorMsg);
				return false;
			}
			for (int i = 0; i < lg; i++)
			{
				LVAR.Set((Functions[funcName] as functionDef).argsNames[i].Substring(1), new unionVal(0, "\"" + argsVals[i] + "\"", typVal.str));
            }
            funcTimeOutTime = DateTime.Now.AddMilliseconds( funcTimeOut );
            if (privExecuteTokensPart(0, funcName, GVAR, LVAR, false, false, -1, -1) == R_ERROR)
                return false;
            else
            {
                return true;
            }
		}

        //Execute a Sub or event
        private int privExecuteTokensPart(int level, string funcName, SetOfVars GCAR, SetOfVars LVAR, bool breakable, bool inSwitchCase, int start, int end)
        {
        string yytext;
            string argLine = "";
            char breakCar;
            int currLine = 0;
            string errorMsg = "";
            bool resultTestCond = false;
            int retVal = R_CONTINUE;

            token tok;
            TokenParse tkparse;

            funcName = funcName.ToLower();
            TokenBuffer CurrTokenBuffer = (Functions[funcName] as functionDef).tkb;
            
            tkparse = new TokenParse(CurrTokenBuffer, start, end);
            while (true)
            {

                tok = tkparse.readNextToken();
				yytext = tok.value;
				currLine = tok.lineNumber;

				if (DateTime.Now > funcTimeOutTime) // TimeOut infinite loop
				{
					errorMsg = "Time Out in Event or Sub-routine: " + funcName + " (" + funcTimeOut.ToString() + " ms)";
					goto endFunction;
				}

                //                                    Console.WriteLine(yytext);
                switch (tok.typ)
                {
                    case Scanner.E_GLOBALVAR:
						#region GLOBALVAR
						{
                            tok = tkparse.readNextToken();
                            if (tok.typ != Scanner.E_VAR)
                            {
                                errorMsg = "var ident need";
                                goto endFunction;
                            }
                            string idVar = tok.value.Substring(1);
                            tok = tkparse.readNextToken();

                            //';' not detected after globalvar, Sub/Event abort
                            if (tok.typ != Scanner.E_SEMICOLON)
                            {
                                errorMsg = "';' needed at end of line";
                                goto endFunction; 
                            }
                            GVAR.globVars[idVar] = true;
                        }
                        break;
						#endregion
					case Scanner.E_FUNCTION:
					case Scanner.E_IDENT:
					case Scanner.E_STRING:
                    case Scanner.E_INTEGER:
                    case Scanner.E_FLOAT:
					case Scanner.E_VAR:
					case Scanner.E_ARVAR:
					case Scanner.E_PAR_OPEN:
						#region STANDARD EVALUATION
						breakCar = ' ';
                        try
                        {
                            argLine = retrieveEvalVar(funcName, tkparse, CurrTokenBuffer, GVAR, LVAR, false, ref breakCar);
                        }
                        catch (GLScriptException e)
                        {
                            errorMsg = e.Message;
                            goto endFunction;
                        }
                        catch
                        {
                            throw;
                        }

                        if (breakCar == '!')
                        {
                            errorMsg = "';' needed";
                            goto endFunction;
                        }
                        if (isReturnFlagFunction(funcName))
                            return R_CONTINUE;
                        //                        Console.WriteLine(argLine);
                        break;
						#endregion
					case Scanner.E_DEFAULT:
                        goto case Scanner.E_CASE;
                    case Scanner.E_CASE:
						#region CASE
						tok = tkparse.readNextToken();
						if (inSwitchCase)
                        {
                            breakCar = ' ';
                            try
                            {
                                argLine = retrieveEvalVar(funcName, tkparse, CurrTokenBuffer, GVAR, LVAR, true, ref breakCar);
                            }
                            catch (GLScriptException e)
                            {
                                errorMsg = e.Message;
                                goto endFunction;
                            }
                            catch (Exception e)
                            {
                                throw e;
                            }
                            if (breakCar != ':')
                            {
                                errorMsg = "Need ':' in a CASE option";
                                goto endFunction;
                            }
                            break;
                        }
                        errorMsg = "CASE or DEFAULT not attempted";
                        goto endFunction;
						#endregion
					case Scanner.E_SWITCH:
						#region SWITCH
						tok = tkparse.readNextToken();
                        breakCar = ' ';
                        try
                        {
                            argLine = retrieveEvalVar(funcName, tkparse, CurrTokenBuffer, GVAR, LVAR, true, ref breakCar);
                        }
                        catch (GLScriptException e)
                        {
                            errorMsg = e.Message;
                            goto endFunction;
                        }
                        catch (Exception e)
                        {
                            throw e;
                        }
                        if (breakCar == '!')
                        {
                            errorMsg = "';' needed";
                            goto endFunction;
                        }

                        string testVal = argLine;
                        int startCasePart = -1;
                        int endCasePart = -1;
                        int nbSwitch = 0;
                        tok = tkparse.readNextToken();
                        while (true)
                        {
                            if (tok.typ != Scanner.E_CASE && tok.typ != Scanner.E_DEFAULT && tok.typ != Scanner.E_ENDSWITCH)
                            {
                                errorMsg = "'CASE or DEFAULT' needed";
                                goto endFunction;
                            }
                            if (tok.typ == Scanner.E_ENDSWITCH)
                            {
                                break;
                            }
                            breakCar = ' ';
							if (tok.typ == Scanner.E_DEFAULT)
							{
								argLine = testVal;
								tok = tkparse.readNextToken();
								if (tok.typ != Scanner.E_DOUBLEDOT)
								{
									errorMsg = "Need ':' in a DEFAULT option";
									goto endFunction;
								}
							}
							else
							{
								tok = tkparse.readNextToken();
								try
								{
									argLine = retrieveEvalVar(funcName, tkparse, CurrTokenBuffer, GVAR, LVAR, true, ref breakCar);
								}
								catch (GLScriptException e)
								{
									errorMsg = e.Message;
									goto endFunction;
								}
								catch (Exception e)
								{
									throw e;
								}

								if (breakCar != ':')
								{
									errorMsg = "Need ':' in a CASE option";
									goto endFunction;
								}
							}
                            if (testVal == argLine)
                            {
                                startCasePart = tkparse.curPos+1;
                                nbSwitch = 0;
                                while (true)
                                {
                                    tok = tkparse.readNextToken();
                                    if (tok.typ == Scanner.E_END)
                                    {
                                        errorMsg = "Switch not terminated";
                                        goto endFunction;
                                    }
                                    if (tok.typ == Scanner.E_SWITCH)
                                        nbSwitch++;
                                    if (tok.typ == Scanner.E_ENDSWITCH && nbSwitch == 0)
                                    {
                                        endCasePart = tkparse.curPos - 1;
                                        break;
                                    }
                                    if (tok.typ == Scanner.E_ENDSWITCH)
                                        nbSwitch--;
                                }
                                if (startCasePart != -1)
                                {
                                    retVal = privExecuteTokensPart(level + 1, funcName, GVAR, LVAR, true, true, startCasePart, endCasePart);
                                    tkparse.curPos = endCasePart + 1;
                                }
                                break;
                            }
                            else
                            {
                                nbSwitch = 0;
                                while (true)
                                {
                                    tok = tkparse.readNextToken();
                                    if (tok.typ == Scanner.E_END)
                                    {
                                        errorMsg = "Switch not terminated";
                                        goto endFunction;
                                    }
                                    if (tok.typ == Scanner.E_SWITCH)
                                        nbSwitch++;
                                    if ((tok.typ == Scanner.E_ENDSWITCH || tok.typ == Scanner.E_CASE || tok.typ == Scanner.E_DEFAULT ) && nbSwitch == 0)
                                        break;
                                    if (tok.typ == Scanner.E_ENDSWITCH)
                                        nbSwitch--;
                                }
                            }
                        }


                        break;
						#endregion
					case Scanner.E_IF:
						#region IF
						token tokIf = tok;
                        resultTestCond = false;
                        tok = tkparse.readNextToken();
                        breakCar = ' ';
                        try
                        {
                            argLine = retrieveEvalVar(funcName, tkparse, CurrTokenBuffer, GVAR, LVAR, true, ref breakCar);
                        }
                        catch (GLScriptException e)
                        {
                            errorMsg = e.Message;
                            goto endFunction;
                        }
                        catch (Exception e)
                        {
                            throw e;
                        }
                        if (breakCar == '!')
                        {
                            errorMsg = "';' needed";
                            goto endFunction;
                        }
                        if (isReturnFlagFunction(funcName))
                            return R_CONTINUE;
                        try
                        {
                            float fvalue = float.Parse(argLine);
                            if (fvalue > 0)
                                resultTestCond = true;
                            else
                                resultTestCond = false;
                        }
                        catch
                        {
                            if (argLine.Length > 0)
                                resultTestCond = true;
                            else
                                resultTestCond = false;
                        }
                        tok = tkparse.readNextToken();
                        //When a ; is detected after a IF statement
                        if (tok.typ == Scanner.E_SEMICOLON)
                        {
                            errorMsg = "no ';' allowed in IF statement";
                            goto endFunction;
                        }

                        if (tok.typ != Scanner.E_THEN)
                        {
                            errorMsg = "'THEN' needed";
                            goto endFunction;
                        }
                        int startThenPart = tkparse.curPos + 1;
                        int endThenPart = tokIf.endThenPart;
                        int startElsePart = tokIf.startElsePart;
                        int endElsePart = tokIf.endElsePart;

						if (tokIf.startThenPart == 0 ) // Find part of if if never finded
						{
							int nbIf = 0;
							while (true)
							{

								tok = tkparse.readNextToken();
								if (tok.typ == Scanner.E_END)
								{
									errorMsg = "'ENDIF' is missing";
									goto endFunction;
								}
								if (tok.typ == Scanner.E_IF)
									nbIf++;
								if (nbIf == 0 && tok.typ == Scanner.E_ELSE)
								{
									endThenPart = tkparse.curPos - 1;
									startElsePart = tkparse.curPos + 1;
								}
								if (nbIf == 0 && tok.typ == Scanner.E_ENDIF)
								{
                                    if (startElsePart != 0)
                                        endElsePart = tkparse.curPos - 1;
                                    else
                                        endThenPart = tkparse.curPos - 1;
									break;
								}
								if (tok.typ == Scanner.E_ENDIF)
									nbIf--;
							}
							tokIf.startThenPart = startThenPart;
							tokIf.endThenPart = endThenPart;
							tokIf.startElsePart = startElsePart;
							tokIf.endElsePart = endElsePart;
						}
						else{
							if (startElsePart != 0)
								tkparse.curPos = endElsePart + 1;
							else
								tkparse.curPos = endThenPart + 1;
						}
                        retVal = R_CONTINUE;
                        if (resultTestCond)
                            retVal = privExecuteTokensPart(level + 1, funcName, GVAR, LVAR, breakable,false, startThenPart, endThenPart);
                        else
                        {
                            if (startElsePart != 0)
                                retVal = privExecuteTokensPart(level + 1, funcName, GVAR, LVAR, breakable, false, startElsePart, endElsePart);
                        }
                        if (retVal == R_BREAK)
                            return R_BREAK;
						if (retVal == R_ERROR)
							return retVal;
						if (isReturnFlagFunction(funcName))
							return R_CONTINUE;
                        break;
						#endregion
					case Scanner.E_WHILE:
						#region WHILE
						resultTestCond = false;

						tok = tkparse.readNextToken();
                        breakCar = ' ';
                        int posTestWhile = tkparse.curPos;
                        try
                        {
                            argLine = retrieveEvalVar(funcName, tkparse, CurrTokenBuffer, GVAR, LVAR, true, ref breakCar); // Only to pos to begin While
                        }
                        catch (GLScriptException e)
                        {
                            errorMsg = e.Message;
                            goto endFunction;
                        }
                        catch (Exception e)
                        {
                            throw e;
                        }

                        if (breakCar == '!')
                        {
                            errorMsg = "';' needed";
                            goto endFunction;
                        }
                        if (isReturnFlagFunction(funcName))
                            return R_CONTINUE;

                        int posStartWhilePart = tkparse.curPos + 1;
                        int endWhilePart = 0;
                        int nbWhile = 0;
                        while (true)
                        {
                            tok = tkparse.readNextToken();
                            if (tok.typ == Scanner.E_END)
                            {
                                errorMsg = "'WHILE' not terminated";
                                goto endFunction;
                            }
                            if (tok.typ == Scanner.E_WHILE)
                                nbWhile++;
                            if (nbWhile == 0 && tok.typ == Scanner.E_ENDWHILE)
                            {
                                endWhilePart = tkparse.curPos - 1;
                                break;
                            }
                            if (tok.typ == Scanner.E_ENDWHILE)
                                nbWhile--;
                        }
                        while (true)
                        {
                            tkparse.curPos = posTestWhile;
                            try
                            {
                                argLine = retrieveEvalVar(funcName, tkparse, CurrTokenBuffer, GVAR, LVAR, true, ref breakCar);
                            }
                            catch (GLScriptException e)
                            {
                                errorMsg = e.Message;
                                goto endFunction;
                            }
                            catch (Exception e)
                            {
                                throw e;
                            }
                            if (breakCar == '!')
                            {
                                errorMsg = "';' needed";
                                goto endFunction;
                            }
                            if (isReturnFlagFunction(funcName))
                                return R_CONTINUE;
                            try
                            {
                                float fvalue = float.Parse(argLine);
                                if (fvalue > 0)
                                    resultTestCond = true;
                                else
                                    resultTestCond = false;
                            }
                            catch
                            {
                                if (argLine.Length > 0)
                                    resultTestCond = true;
                                else
                                    resultTestCond = false;
                            }
                            if (resultTestCond)
                            {
                                retVal = privExecuteTokensPart(level + 1, funcName, GVAR, LVAR, true, false, posStartWhilePart, endWhilePart);
								if (retVal == R_BREAK)
								{
									tkparse.curPos = endWhilePart + 1;
									break;
								}
								if (retVal == R_ERROR)
									return retVal;
								if (isReturnFlagFunction(funcName))
									return R_CONTINUE;
							}
                            else
                            {
                                tkparse.curPos = endWhilePart + 1;
                                break;
                            }
                        }
                        break;
						#endregion
					case Scanner.E_FOR:
                        #region Region FOR...ENDFOR

                        {
							token tokFor = tok;
							resultTestCond = false;

                            int startArg = 1;
                            int endArg = 0;
							tok = tkparse.readNextToken();
                            breakCar = ' ';
                            retrieveArg(tkparse, false, ref breakCar, ref startArg, ref endArg);
                            if (breakCar == '!')
                            {
                                errorMsg = "';' needed";
                                goto endFunction;
                            }
                            endArg++; // Position end in ;

                            privExecuteTokensPart(level + 1, funcName, GVAR, LVAR, true, false, startArg, endArg);

                            tok = tkparse.readNextToken();
							int posTestFor = tkparse.curPos;
                            try
                            {
                                argLine = retrieveEvalVar(funcName, tkparse, CurrTokenBuffer, GVAR, LVAR, false, ref breakCar);
                            }
                            catch (GLScriptException e)
                            {
                                errorMsg = e.Message;
                                goto endFunction;
                            }
                            catch (Exception e)
                            {
                                throw e;
                            }

                            if (breakCar == '!')
                            {
                                errorMsg = "';' needed";
                                goto endFunction;
                            }
                            if (isReturnFlagFunction(funcName))
                                return R_CONTINUE;
                            startArg = 0;
                            endArg = 0;
                            breakCar = ' ';
							tok = tkparse.readNextToken();
							retrieveArg(tkparse, true, ref breakCar, ref startArg, ref endArg);
                            if (breakCar == '!')
                            {
                                errorMsg = "';' needed";
                                goto endFunction;
                            }
                            endArg++; // Position end in )

                            tok = tkparse.readCurrToken();
                            if (tok.typ != Scanner.E_PAR_CLOSE)
                            {
                                errorMsg = "')' is missing";
                                goto endFunction;
                            }
                            int posStartForPart = tkparse.curPos + 1;
                            int posEndForPart = 0;
                            int nbFor = 0;
							if (tokFor.startFor == 0)
							{
								while (true)
								{
									tok = tkparse.readNextToken();
									if (tok.typ == Scanner.E_END)
									{
										errorMsg = "'FOR' not terminated";
										goto endFunction;
									}
									if (tok.typ == Scanner.E_FOR)
										nbFor++;
									if (nbFor == 0 && tok.typ == Scanner.E_ENDFOR)
									{
										posEndForPart = tkparse.curPos - 1;
										break;
									}
									if (tok.typ == Scanner.E_ENDFOR)
										nbFor--;
								}
								tokFor.startFor = posStartForPart;
								tokFor.endFor = posEndForPart;
							}
							else
							{
								posEndForPart = tokFor.endFor;
								tkparse.curPos = posEndForPart + 1;
							}
                            while (true)
                            {
                                tkparse.curPos = posTestFor;
                                try
                                {
                                    argLine = retrieveEvalVar(funcName, tkparse, CurrTokenBuffer, GVAR, LVAR, false, ref breakCar);
                                }
                                catch (GLScriptException e)
                                {
                                    errorMsg = e.Message;
                                    goto endFunction;
                                }
                                catch (Exception e)
                                {
                                    throw e;
                                }
                                if (breakCar == '!')
                                {
                                    errorMsg = "';' needed";
                                    goto endFunction;
                                }
                                if (isReturnFlagFunction(funcName))
                                    return R_CONTINUE;


                                try
                                {
                                    float fvalue = float.Parse(argLine);
                                    if (fvalue > 0)
                                        resultTestCond = true;
                                    else
                                        resultTestCond = false;
                                }
                                catch
                                {
                                    if (argLine.Length > 0)
                                        resultTestCond = true;
                                    else
                                        resultTestCond = false;
                                }
                                if (resultTestCond)
                                {
                                    retVal = privExecuteTokensPart(level + 1, funcName, GVAR, LVAR, true, false, posStartForPart, posEndForPart);
                                    if (retVal == R_BREAK)
                                    {
                                        tkparse.curPos = posEndForPart + 1;
                                        break;
                                    }
									if (retVal == R_ERROR)
										return retVal;
									if (isReturnFlagFunction(funcName))
										return R_CONTINUE;
                                }
                                else
                                {
                                    tkparse.curPos = posEndForPart + 1;
                                    break;
                                }
                                // Un peu crade, je le conçoit, exécution du code d'increment de la boucle FOR
                                tok = (token)CurrTokenBuffer.TokenList[endArg];
                                tok.typ = Scanner.E_SEMICOLON;
                                privExecuteTokensPart(level + 1, funcName, GVAR, LVAR, true, false, startArg, endArg);
                                tok.typ = Scanner.E_PAR_CLOSE;
                            }
                        }
                        #endregion
                        break;
                    case Scanner.E_FOREACH:
                        #region FOREACH...ENDFOREACH
                        {

                            tok = tkparse.readNextToken();
                            if (tok.typ != Scanner.E_VAR)
                            {
                                errorMsg = "'Var' needed";
                                goto endFunction;
                            }
                            string destVar = tok.value;
                            tok = tkparse.readNextToken();
                            if (tok.typ != Scanner.E_IN)
                            {
                                errorMsg = "'Token IN' needed";
                                goto endFunction;
                            }
                            tok = tkparse.readNextToken();
                            if (tok.typ != Scanner.E_VAR)
                            {
                                errorMsg = "'Var' needed";
                                goto endFunction;
                            }
                            string origVar = tok.value;
                            tok = tkparse.readNextToken();
                            if (tok.typ != Scanner.E_PAR_CLOSE)
                            {
                                errorMsg = "')' needed";
                                goto endFunction;
                            }
                            if (isReturnFlagFunction(funcName))
                                return R_CONTINUE;
                            int posStartForPart = tkparse.curPos + 1;
                            int posEndForPart = 0;
                            int nbFor = 0;
                            while (true)
                            {
                                tok = tkparse.readNextToken();
                                if (tok.typ == Scanner.E_END)
                                {
                                    errorMsg = "'FOREACH' not terminated";
                                    goto endFunction;
                                }
                                if (tok.typ == Scanner.E_FOREACH)
                                    nbFor++;
                                if (nbFor == 0 && tok.typ == Scanner.E_ENDFOREACH)
                                {
                                    posEndForPart = tkparse.curPos - 1;
                                    break;
                                }
                                if (tok.typ == Scanner.E_ENDFOREACH)
                                    nbFor--;
                            }

                            SetOfVars.dumpElem[] dumpList;
                            if (GVAR.globalExist(origVar))
                                dumpList = GVAR.listDump(origVar.Substring(1)); //GlobalVar
                            else
                                dumpList = LVAR.listDump(origVar.Substring(1));
                            int idxDump = 0;
                            while (true)
                            {
                                if (idxDump >= dumpList.Length)
                                {
                                    tkparse.curPos = posEndForPart + 1;
                                    break;
                                }
                                string key = dumpList[idxDump].ids;

                                unionVal newVal = new unionVal(dumpList[idxDump].val);
                                if (dumpList[idxDump].val.CallBackGet != null)
                                    newVal = dumpList[idxDump].val.CallBackGet(dumpList[idxDump].id, dumpList[idxDump].val.CallBackArg);
                                newVal.CallBackSet = null;
                                newVal.CallBackGet = null;
                                newVal.CallBackArg = "";

                                if (GVAR.globalExist(destVar))
                                {
                                    GVAR.Set(destVar.Substring(1) + ",\"key\"", new unionVal( 0,"\"" + key + "\"",typVal.str ));
                                    GVAR.Set(destVar.Substring(1) + ",\"value\"", newVal);
                                }
                                else
                                {
                                    LVAR.Set(destVar.Substring(1) + ",\"key\"", new unionVal(0, "\"" + key + "\"", typVal.str));
                                    LVAR.Set(destVar.Substring(1) + ",\"value\"", newVal);
                                }

                                if (isReturnFlagFunction(funcName))
                                    return R_CONTINUE;

                                retVal = privExecuteTokensPart(level + 1, funcName, GVAR, LVAR, true, false, posStartForPart, posEndForPart);
                                if (retVal == R_BREAK)
                                {
                                     tkparse.curPos = posEndForPart + 1;
                                     break;
                                }
								if (retVal == R_ERROR)
									return retVal;
								if (isReturnFlagFunction(funcName))
									return R_CONTINUE;
                                idxDump++;
                            }
                        }
                        #endregion
                        break;
                    case Scanner.E_BREAK:
						#region BREAK
						if (!breakable)
                        {
                            errorMsg = "BREAK not attemped";
                            goto endFunction;
                        }
                        return R_BREAK;
						#endregion
					case Scanner.E_END:
                        if (level == 0) // Push 0 arg for return value
                            stk.Push(0);
                        return R_CONTINUE;
                    default:
                        errorMsg = "Token not catched";
                        goto endFunction;
                }

            }
        endFunction:
            errorMsg = "Syntax error: in file \"" + tok.fileName + "\" at line #" + tok.lineNumber  +"\n\t" + errorMsg + "" + "\n\tFunction '" + funcName + "' script aborted";
            myDebug.WriteLine("err",errorMsg);
            return R_ERROR;
        }
        void retrieveArg(TokenParse tkparse, bool breakFunc, ref char breakCar, ref int start, ref int end)
        {

            int par = 0;
            int brack = 0;

			start = tkparse.curPos;

			token tok = tkparse.readCurrToken();
            while (true)
            {

                if (tok.typ == Scanner.E_PAR_OPEN)
                {
                    par++;
					goto readNext;
                }
                if (tok.typ == Scanner.E_PAR_CLOSE && par > 0)
                {
                    par--;
					goto readNext;
				}
                if (tok.typ == Scanner.E_BRACKET_OPEN)
                {
                    brack++;
					goto readNext;
                }
                if (tok.typ == Scanner.E_BRACKET_CLOSE && brack > 0)
                {
                    brack--;
					goto readNext;
				}
                if (tok.typ == Scanner.E_SEMICOLON)
                {
                    breakCar = ';';
                    break;
                }
                if (tok.typ == Scanner.E_DOUBLEDOT)
                {
                    breakCar = ':';
                    break;
                }
                if (tok.typ == Scanner.E_END)
                {
                    breakCar = '!';
                    break;
                }
                if (( tok.typ == Scanner.E_COLON || tok.typ == Scanner.E_PAR_CLOSE ) && par == 0 && brack == 0 && breakFunc == true)
                {
                    if (tok.typ == Scanner.E_COLON)
                        breakCar = ',';
                    else
                        breakCar = ')';
                    break;
                }
			readNext:
				tok = tkparse.readNextToken();
            }
            end = tkparse.curPos - 1;
            return;

        }
        string retrieveEvalVar(string funcName, TokenParse tkparse, TokenBuffer currTokenBuffer, SetOfVars GVAR, SetOfVars LVAR, bool breakFunc, ref char breakCar)
        {
            System.Collections.ArrayList tokens = new System.Collections.ArrayList();

            int startPos = 0;
            int endPos = 0;

            retrieveArg(tkparse, breakFunc, ref breakCar, ref startPos, ref endPos);
            try
            {
				Parseur p = null;
				if ((currTokenBuffer.TokenList[tkparse.curPos] as token).parsed == null)
				{
					(currTokenBuffer.TokenList[tkparse.curPos] as token).parsed = new Parseur(currTokenBuffer, startPos, endPos);
//					p = (currTokenBuffer.TokenList[tkparse.curPos] as token).parsed;
//Console.WriteLine(p.ToRPN());
			}
				else
				{
//					p = (currTokenBuffer.TokenList[tkparse.curPos] as token).parsed;
//					Console.WriteLine(p.ToRPN());
				}
				p = (currTokenBuffer.TokenList[tkparse.curPos] as token).parsed;
//Console.WriteLine(p.ToRPN());

				Parseur.executeParsedFunction BC = new Parseur.executeParsedFunction(parseBackcall);
                retFlag = false;
                unionVal retVal = p.getval(GVAR, LVAR, BC);

				if (retFlag)
				{
					setReturnFlagFunction(funcName, true);
					retFlag = false;
				}
				if (retVal.typVal == typVal.num)
					return retVal.fval.ToString();
				else
					return retVal.sval;
			}
			catch (ParseException e)
			{
				throw (new GLScriptException(e.Message));
			}
            /*
            catch
            {
                throw new GLScriptException("';' needed");
            }
            */
            
        }
        void parseBackcall(SetOfVars GVAR,SetOfVars LVAR, unionVal val, ArrayList args)
        {
            string tmpStr = "";
            int nbArgs = args.Count;
            string OldString = "";
            string NewString = "";
            string StartIndex = "";


            switch (val.nameFunction.ToLower())
            {

				case "round":
					{
                        if (nbArgs != 2)
                        {
                            throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                        }
                        else
                        {
                            try
                            {
                                //Convert String into a floating number
                                string inputString = args[0].ToString();
                                float numValue;
                                bool parsed = float.TryParse(inputString, out numValue); //Convert String to Number

                                val.typVal = typVal.num;
                                val.fval = numValue;
                            }
                            catch
                            {
                                throw new GLScriptException("Can't convert string \"" + args[0].ToString() + "\" to number " + val.nameFunction);
                            }
                        
                            
                            //Get info Number of decimals.
                            int rnd = 0;
                            try
                            {
                                rnd = getInt((string)args[1]);
                            }
                            catch
                            {
                                throw new GLScriptException("2nd parameter of function:" + val.nameFunction + " is not a valid Integer value");
                            }

                            val.fval = (float)Math.Round(val.fval, rnd);
                            val.typVal = typVal.num;
                            return;
                        }
					}

                case "isnum":
                        if (nbArgs != 1)
                        {
                            throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                        }
                        else
                        {
                            tmpStr = args[0].ToString();
                            val.typVal = typVal.num;
                            try
                            {
                                val.fval = float.Parse(tmpStr);
                                val.fval = 1;
                            }
                            catch
                            {
                                val.fval = 0;
                            }
                            return;
                        }

                case "strformat":
					if (nbArgs < 1)
                        throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                    tmpStr = (string)args[0];
                    args.RemoveAt(0);
// Try to convert to numerical value args
					for (int i = 0; i < args.Count; i++)
					{
						try
						{
							args[i] = float.Parse((string)args[i]);
						}
						catch
						{
						}
					}
					val.sval = "\"" + string.Format(tmpStr, args.ToArray()) + "\"";
					val.typVal = typVal.str;
                    return;
                case "tostring":
                    if (nbArgs != 1)
                        throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                    tmpStr = (string)args[0];
                    val.sval = "\"" + tmpStr + "\"";
                    val.typVal = typVal.str;
                    return;

                case "insert":
                        string OldInsertString = args[0].ToString();
                        StartIndex = args[1].ToString();
                        string StringToAdd = args[2].ToString();
                        string NewInsertString = "";

                    if (OldInsertString != "")
                    {
                        if (Int32.Parse(StartIndex) <= OldInsertString.Length)
                        {
                            NewInsertString = OldInsertString.Insert(Int32.Parse(StartIndex), StringToAdd);

                            val.sval = "\"" + NewInsertString + "\"";
                            val.typVal = typVal.str;
                        }
                        else
                        {
                            throw new GLScriptException("Parameters in function: '" + val.nameFunction + "' Index is larger than the string");
                        }
                    }
                    else
                    {
                        throw new GLScriptException("Parameters in function: '" + val.nameFunction + "' Incorrect first parameter , cant insert characters in a empty string");
                    }
                    return;

                case "replace":
                    try
                    {

                        OldString = args[0].ToString();
                        string OldValue = args[1].ToString();
                        string NewValue = args[2].ToString();

                        NewString = "";
                        if (OldString != "")
                        {
                            NewString = OldString.Replace(OldValue, NewValue);

                            val.sval = "\"" + NewString + "\"";
                            val.typVal = typVal.str;
                        }
                        else
                        {
                            throw new GLScriptException("Parameters in function: '" + val.nameFunction + "' Incorrect first parameter , cant replace a empty string");
                        }
                    }
                    catch
                    {
                        throw new GLScriptException("Parameters in function: '" + val.nameFunction + "' are not correct");
                    }
                    return;

                case "contains":
                    if (nbArgs != 2)
                        throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                    else
                    {
                        try
                        {
                            string Str = args[0].ToString();
                            string Val = args[1].ToString();
                            val.typVal = typVal.num;
                            if (Str.Contains(Val))
                            {
                                val.fval = 1;
                            }
                            else
                            {
                                val.fval = 0;
                            }
                        }
                       catch
                        {
                            throw new GLScriptException("Parameters in function: '" + val.nameFunction + "' are not string values");
                        }
                    }
                    return;

                case "tonum":
                    {
                        if (nbArgs != 1)
                        {
                            throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                        }
                        else
                        {
                            if (args[0].ToString() != "")
                            {
                                try
                                {
                                    val.fval = float.Parse(args[0].ToString());
                                    val.typVal = typVal.num;
                                }
                                catch
                                {
                                    throw new GLScriptException("Can't convert string \"" + args[0].ToString() + "\" to number in function: " + val.nameFunction);
                                }
                            }
                            else
                            {
                                throw new GLScriptException("Can't convert empty string in function: " + val.nameFunction);
                            }
                        }
                        return;
                    }
				case "not":
					if (nbArgs != 1)
						throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
					tmpStr = (string)args[0];
					try
					{
						val.fval = float.Parse(tmpStr);
						if (val.fval > 0)
							val.fval = 0;
						else
							val.fval = 1;
						val.typVal = typVal.num;
					}
					catch
					{
						throw new GLScriptException("Can't convert string \"" + (string)args[0] + "\" to number " + val.nameFunction);
					}
					return;
				case "toupper":
                    if (nbArgs != 1)
                        throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                    tmpStr = (string)args[0];
                    val.typVal = typVal.str;
                    val.sval = "\"" + tmpStr.ToUpper() + "\"";
                    return;
                case "tolower":
                    if (nbArgs != 1)
                        throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                    tmpStr = (string)args[0];
                    val.typVal = typVal.str;
                    val.sval = "\"" + tmpStr.ToLower() + "\"";
                    return;
                case "trim":
                    if (nbArgs != 1)
                        throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                    tmpStr = (string)args[0];
                    val.typVal = typVal.str;
                    val.sval = "\"" + tmpStr.Trim() + "\"";
                    return;
                case "indexof":
                    if (nbArgs != 2)
                        throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                    tmpStr = (string)args[0];
                    string findString = (string)args[1];
                    val.typVal = typVal.num;
                    val.fval = tmpStr.IndexOf(findString);
                    return;
                case "inarray":
                    if (nbArgs != 2)
                        throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                    else
                    {
                        try
                        {
                            //Get values 
                            string NameOfArray = (val.ArgsVals[0] as Parseur).val.nameVar;
                            string Value = args[1].ToString();
                            string ValOfArray;
                            int LengthOfArray;

                            //Get values from Array (NameOfArray)

                            //Get Lenght Of Array
                            //IF Var of Array is a GlobalVar or not
                            if (GVAR.globalExist(NameOfArray))
                                LengthOfArray = GVAR.ArrayCount(NameOfArray);
                            else
                                LengthOfArray = LVAR.ArrayCount(NameOfArray);

                            //Create new Array
                            string[] ValsOfidVar = new string[LengthOfArray];

                            //Get each Value of Array
                            for (int idx = 0; idx < LengthOfArray; idx++)
                            {
                                //function in SetOfVars.cs (GetVal)
                                if (GVAR.globalExist(NameOfArray))
                                    ValOfArray = GVAR.GetVal(NameOfArray, idx);
                                else
                                    ValOfArray = LVAR.GetVal(NameOfArray, idx);

                                //Delete '"' characters in front and end of the value , is they exist
                                ValOfArray = ValOfArray.Trim('"');

                                //Save each value in the new Array: ValsOfidVar
                                ValsOfidVar[idx] = ValOfArray;
                            }

                            //Type of return value (( numeric 0 or 1) True or False)
                            val.typVal = typVal.num;
                            //verify each of the elements in the array with the matching value (Value)
                            //using System.Linq to use ArrayName.Contains() function
                            if (ValsOfidVar.Contains(Value))
                            {
                                val.fval = 1;
                            }
                            else
                            {
                                val.fval = 0;
                            }
                        }
                        catch
                        {
                            throw new GLScriptException("Error in function: '" + val.nameFunction + "' Something goes wrong with one of the parameters");
                        }
                    }
                    return;


                case "remove":
                    string NumberOfChars = "";
                    NewString = "";
                    //Count parameters
                    if (nbArgs >= 2 || nbArgs <= 3)
                    {
                        if (nbArgs == 2)
                        {
                            OldString = args[0].ToString();
                            StartIndex = args[1].ToString();
                        }
                        if (nbArgs == 3)
                        {
                            OldString = args[0].ToString();
                            StartIndex = args[1].ToString();
                            NumberOfChars = args[2].ToString();
                        }

                        if (OldString != "")
                        {
                            //Check stringlength and startindex.
                            if (Int32.Parse(StartIndex) <= OldString.Length)
                            {
                                if (Int32.Parse(StartIndex) >= 0 && StartIndex != "")
                                {
                                    if (NumberOfChars == "")
                                    {
                                        // Removes everything beginning at startindex
                                        NewString = OldString.Remove(Int32.Parse(StartIndex));
                                    }
                                    else
                                    {
                                        // Removes specified number of characters(NumberOfChars) starting at index StartIndex
                                        NewString = OldString.Remove(Int32.Parse(StartIndex), Int32.Parse(NumberOfChars));
                                    }
                                }
                                else
                                {
                                    throw new GLScriptException("Error in function: '" + val.nameFunction + "' Startindex has a wrong value");
                                }
                            }
                            else
                            {
                                throw new GLScriptException("Error in function: '" + val.nameFunction + "' Index is larger than the string");
                            }
                            val.sval = "\"" + NewString + "\"";
                            val.typVal = typVal.str;
                        }
                        else
                        {
                            throw new GLScriptException("Error with Parameters in function: '" + val.nameFunction + "' Incorrect first parameter , String cannot be empty");
                        }
                    }
                    else
                    {
                        throw new GLScriptException("Error in function: '" + val.nameFunction + "' Incorrect number of parameters");
                    }
                    return;
                case "splittoarray":
                    {
                        if (nbArgs != 2)
                            throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                        string tmp = (string)args[1];
                        char splitChar = tmp[0];
                        string[] splited = (args[0] as string).Split(splitChar);
                        if (splited.Length == 0)
                        {
                            val.typVal = typVal.str;
                            val.sval = "\"\"";
                        }
                        else
                        {
                            val.typVal = typVal.setOfVar;
                            val.setVars = new SetOfVars( );
                            for (int i = 0; i < splited.Length; i++)
                            {
                                val.setVars.Set(i.ToString(), new unionVal(0, "\"" + splited[i] + "\"" , typVal.str));
                            }
                        }
                    }
                    return;

                case "split":
                    {
                        int pos = 0;
                        if (nbArgs != 3)
                            throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                        string tmp = (string)args[1];
                        char splitChar = tmp[0];
                        string[] splited = (args[0] as string).Split(splitChar);
                        try
                        {
                            pos = getInt((string)args[2]);
                        }
                        catch
                        {
                            throw new GLScriptException("3rd parameter of function:" + val.nameFunction + " is not a valid Integer value");
                        }
                        if (pos > splited.Length)
                        {
                            val.typVal = typVal.str;
                            val.sval = "\"\"";
                        }
                        else
                        {
                            val.typVal = typVal.str;
                            val.sval = "\"" + splited[pos] + "\"";
                        }
                    }
                    return;
                case "unset":
                    if (nbArgs != 1)
                        throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                    string nameVar = (val.ArgsVals[0] as Parseur).val.nameVar;
                    GVAR.unSet(nameVar);
                    LVAR.unSet(nameVar);

                    return;
                case "return":
                    retFlag = true;
                    if (args.Count > 1)
                        throw new GLScriptException("You can return only one value... ");
                    if (args.Count == 1)
                    {
                        stk.Push(args[0]);
                        stk.Push(1);
                    }
                    else
                        stk.Push(0);
                    return;
                
                case "write":
                    if (nbArgs > 1)
                        throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                    else
                        if (nbArgs == 1)
                    {
                        string Text = utils.ConvertSpecialChars((string)args[0]);  //Convert all specials characters before color encoding
                        string DefaultColor = "^8";
                        char character = '^';

                        string[] splited = (DefaultColor + "" + Text as string).Split(character);
                        if (splited.Length > 1)
                        {
                            for (int i = 0; i < splited.Length; i++)
                            {
                                string Word = splited[i];
                                if (Word.Length > 1)
                                {
                                    string firstCharacter = Word[0].ToString();
                                    //convert ^number to text. LFSColor in Utils.cs
                                    try
                                    {
                                        string Color = Enum.GetName(typeof(UTILS.utils.LFSColor), int.Parse(firstCharacter.ToString()));
                                        Console.ForegroundColor = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), Color);
                                    }
                                    catch
                                    {

                                    }
                                    //Delete first char from each word that contains a LFSColor character
                                    Console.Write(Word.Remove(0, 1));
                                }
                            }
                        }
                        else
                        {
                            Console.Write(splited[0]);
                        }
                    }
                    return;
                case "writeline":
                    if (nbArgs > 1)
                        throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                    else
                    {
                        string Text = utils.ConvertSpecialChars((string)args[0]); //Convert all specials characters before color encoding
                        string DefaultColor = "^8";
                        char character = '^';

                        string[] splited = (DefaultColor+""+Text as string).Split(character); 
                        if (splited.Length > 1)
                        {
                            for (int i = 0; i < splited.Length; i++)
                            {
                                string Word = splited[i];
                                if (Word.Length > 1)
                                {
                                    string firstCharacter = Word[0].ToString();
                                    //convert ^number to text. LFSColor in Utils.cs
                                    try
                                    {
                                        string Color = Enum.GetName(typeof(UTILS.utils.LFSColor), int.Parse(firstCharacter.ToString()));
                                        Console.ForegroundColor = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), Color);
                                    }
                                    catch
                                    {

                                    }
                                    //Delete first char from each word that contains a LFSColor character
                                    Console.Write(Word.Remove(0,1));
                                }
                            }
                            //Create newline
                            Console.WriteLine();
                        }
                        else
                        {
                            Console.WriteLine(splited[0]);
                        }
                    }
                    return;
                
                case "strlen":
                    if (nbArgs != 1)
                        throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);

                    val.typVal = typVal.num;
                    val.fval = (args[0] as string).ToString().Length;
                    return;
                case "substr":
                    if (nbArgs < 2 || nbArgs > 3)
                        throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);

                    int startindex = 0;
                    int nb = 0;

                    //Get string from first parameter
                    try
                    {
                        string str = (string)args[0];
                        //Check length of string with startindex.
                        if (startindex < str.Length)
                        {
                            startindex = getInt((string)args[1]);
                        }
                        else
                        {
                            throw new GLScriptException("2nd parameter of function:" + val.nameFunction + " cannot be higher than the length of the string!");
                        }


                        if (nbArgs == 3)
                        {
                            val.typVal = typVal.str;
                            nb = getInt((string)args[2]); //3rd parameter : lenght

                            if (nb > str.Length - startindex)
                                nb = str.Length - startindex;
                            val.sval = "\"" + str.Substring(startindex, nb) + "\"";

                        }
                        else
                        {
                            val.sval = "\"" + str.Substring(startindex) + "\"";
                        }
                    }
                    catch
                    {

                    }
                    return;

                case "dumpvar":
                    {
                        string idVar = (val.ArgsVals[0] as Parseur).val.nameVar;
                        if (GVAR.globalExist(idVar))
                            GVAR.Dump(idVar);
                        else
                            LVAR.Dump(idVar);
                    }
                    return;
                case "arraycount":
                    {
                        string idVar = (val.ArgsVals[0] as Parseur).val.nameVar;
                        if (GVAR.globalExist(idVar))
                        {
                            val.typVal = typVal.num;
                            val.fval = GVAR.ArrayCount(idVar);
                        }
                        else
                        {
                            val.typVal = typVal.num;
                            val.fval = LVAR.ArrayCount(idVar);
                        }
                    }
                    return;

                case "sort":
                    {
                        string idVar = (val.ArgsVals[0] as Parseur).val.nameVar; //Name of Var
                        string SortType = (string)args[1];
                        string ValOfArray;
                        int LengthOfArray;

                        if (nbArgs != 2)
                            throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);

                        //Get Lenght Of Array
                        if (GVAR.globalExist(idVar))
                            LengthOfArray = GVAR.ArrayCount(idVar);
                        else
                            LengthOfArray = LVAR.ArrayCount(idVar);

                        //Create new Array
                        String[] ValsOfidVar = new String[LengthOfArray];

                        //Get each Value of variable
                        for (int idx = 0; idx < LengthOfArray; idx++)
                        {
                            //function in SetOfVars.cs (GetVal)
                            if (GVAR.globalExist(idVar))
                                ValOfArray = GVAR.GetVal(idVar, idx);
                            else
                                ValOfArray = LVAR.GetVal(idVar, idx);

                            //Save each value in the new Array: ValsOfidVar
                            ValsOfidVar[idx] = ValOfArray;
                        }

                        //Sort array
                        if (SortType != "DESC")
                        {
                            Array.Sort(ValsOfidVar); //ASC
                        }
                        else
                        {
                            Array.Sort(ValsOfidVar); //Sort ASC
                            Array.Reverse(ValsOfidVar);//Reverse List
                        }

                        //Set new Vars
                        val.typVal = typVal.setOfVar;
                        val.setVars = new SetOfVars();
                        for (int i = 0; i < LengthOfArray; i++)
                        {
                            val.setVars.Set(i.ToString(), new unionVal(0, "" + ValsOfidVar[i] + "", typVal.str));
                        }
                    }
                    return;

                case "randomnum":
                    {
                        int startNum = 0;
                        int endNum = 1;
                        if( nbArgs >= 3 || nbArgs == 1 )
                            throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                        if (nbArgs == 2)
                        {
                            startNum = getInt((string)args[0]);
                            endNum = getInt((string)args[1]);
                        }
                        Random random = new Random();
                        val.typVal = typVal.num;

                        val.fval = (float)(random.NextDouble() * ( endNum - startNum ) + startNum);
                    }
                    return;
                case "isregexmatch":
                    {
                        if (nbArgs < 2 )
                            throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);

                        Regex regExp = new Regex((string)args[0]);
                        val.typVal = typVal.num;
                        if (regExp.IsMatch((string)args[1]))
                            val.fval = 1;
                        else
                            val.fval = 0;
                    }
                    return;
				case "sqrt":
					if (nbArgs != 1)
						throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
					tmpStr = (string)args[0];
					try
					{
						val.fval = float.Parse(tmpStr);
						val.typVal = typVal.num;
					}
					catch
					{
						throw new GLScriptException("Can't convert string \"" + (string)args[0] + "\" to number " + val.nameFunction);
					}
					val.fval = (float)Math.Sqrt( val.fval );
					val.typVal = typVal.num;
					return;
                case "mod":
                    {
                        if (nbArgs != 2)
                            throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                        int mod1 = 0;
                        int mod2 = 0;
                        try
                        {
                            mod1 = getInt((string)args[0]);
                        }
                        catch
                        {
                            throw new GLScriptException("1st parameter of function:" + val.nameFunction + " is not a valid Integer value");
                        }
                        try
                        {
                            mod2 = getInt((string)args[1]);
                        }
                        catch
                        {
                            throw new GLScriptException("2nd parameter of function:" + val.nameFunction + " is not a valid Integer value");
                        }
                        val.fval = (float)(mod1 % mod2);
                        val.typVal = typVal.num;
                        return;
                    }
                case "cos":
                    {
                        if (nbArgs != 1)
                        {
                            throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                        }
                        else
                        {
                            try
                            {
                                int num = 0;
                                num = getInt((string)args[0]);
                                val.fval = (float)Math.Cos(num * (Math.PI / 180.0));
                                val.typVal = typVal.num;
                                return;
                            }
                            catch
                            {
                                throw new GLScriptException("Invalid value in function: " + val.nameFunction);
                            }
                        }
                    }
                case "sin":
                    {
                        if (nbArgs != 1)
                        {
                            throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                        }
                        else
                        {
                            try
                            {
                                int num = 0;
                                num = getInt((string)args[0]);
                                val.fval = (float)Math.Sin(num * (Math.PI / 180.0));
                                val.typVal = typVal.num;
                                return;
                            }
                            catch
                            {
                                throw new GLScriptException("Invalid value in function: " + val.nameFunction);
                            }
                        }
                    }
                case "tan": //Calculate Radians
                    {
                        if (nbArgs != 1)
                        {
                            throw new GLScriptException("Incorrect number of parameters in function: " + val.nameFunction);
                        }
                        else
                        {
                            try
                            {
                                int num = 0;
                                num = getInt((string)args[0]);
                                val.fval = (float)Math.Tan(num);
                                val.typVal = typVal.num;
                                return;
                            }
                            catch
                            {
                                throw new GLScriptException("Invalid value in function: " + val.nameFunction);
                            }
                        }
                    }
            }
            if (existFunction(val.nameFunction.ToLower()))
            {
                privExecuteFunction(val.nameFunction.ToLower(), (string[])args.ToArray(typeof(string)));
                if (stk.Count != 0)
				{
					int nbRetStak = (int)stk.Pop();
					if (nbRetStak != 1)
						val.sval = "\"\"";
					else
						val.sval = "\"" + (string)stk.Pop() + "\"";
				}
				else
					val.sval = "\"\"";
				val.typVal = typVal.str;
				return;
            }
            if (listOfCallBackFunctions.Contains(val.nameFunction.ToLower()))
            {
                //Debug info
                if (VLAPPER.DisplayLapperFunction == 1)
                {
                string str = "";
                for(int i = 0;i < args.Count;i++ )
                {
                    if(str != "")
                    str = str + "," + args[i];
                    else
                    str = ""+args[i];
                }
                Console.WriteLine("LapperFunctions: " + val.nameFunction.ToLower()+"("+ str + ")");

                }
                callBackFunction myCBF = (callBackFunction)listOfCallBackFunctions[val.nameFunction.ToLower()];
                    myCBF(val, args);              
                return;
            }
            throw new GLScriptException("The function: " + val.nameFunction + " does not exist");
        }

        private int getInt(string str)
        {
            int ret = 0;
            try
            {
                ret = int.Parse(str);
            }
            catch
            {
                throw new GLScriptException("Integer value is needed!");
            }
            return ret;
        }

    }
}
