# -*- coding: utf-8 -*-
#
# *********************************************************************************************************************
# TinyJSParser https://github.com/TmpName/TinyJSParser
#
# A basic JS interpreter in python, made for the Kodi addon vStream https://github.com/Kodi-vStream/venom-xbmc-addons
#
# *********************************************************************************************************************


# TODO LIST
# ---------
# Regex will work only for normal name, not for exotic name
# Object
# Global/Local variables/function/object
# In JavaScript arrays/list are objects.
# Use ast.literal_eval(node_or_string)


# help
# https://sarfraznawaz.wordpress.com/2012/01/26/javascript-self-invoking-functions/
# https://nemisj.com/python-api-javascript/
# https://fr.wikiversity.org/wiki/Python/Les_types_de_base
# https://javascriptobfuscator.com/Javascript-Obfuscator.aspx
# https://nemisj.com/python-api-javascript/
# http://stackoverflow.com/questions/1091259/how-to-test-if-a-class-attribute-is-an-instance-method
# https://pro-domo.ddns.net/blog/optimiser-son-code-python.html
# https://www.clips.uantwerpen.be/tutorials/python-performance-optimization

# UNICODE ERROR
# print(a.decode('utf-8').encode('ascii', 'replace'))
# true = 1 instead of true

# phrase=raw_input()
# phrase.xxx


# https://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/


import re
import types
import math
# import time
# import sys

try:
    from types import NoneType
except:
    NoneType = type(None)


REG_NAME = '[\w]+'
REG_OP = '[\/\*\-\+<>\|\&=~^%!]{1,2}'  # not space here, and no bracket
DEBUG = False  # Never enable it in kodi, too big size log
MAX_RECURSION = 50
ALPHA = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_'

# ---------------------------------------------------------------------------------


def logwrite(stri):
    fh = open('G:\\JSparser\\debug.txt', "a")
    fh.write(stri.encode('utf8') + '\n')
    fh.close()


def RemoveGuil(string):
    if not (isinstance(string, types.StringTypes)):
        return string
    # string = string.strip()

    if string.startswith('"') and string.endswith('"'):
        return string[1:-1]
    if string.startswith("'") and string.endswith("'"):
        return string[1:-1]
    return string


def ASCIIDecode(string):
    i = 0
    l = len(string)
    ret = ''
    while i < l:
        c = string[i]
        if string[i:(i+2)] == '\\x':
            c = chr(int(string[(i+2):(i+4)], 16))
            i += 3
        if string[i:(i+2)] == '\\u':
            c = chr(int(string[(i+2):(i+6)], 16))
            i += 5
        ret = ret + c
        i += 1

    return ret


def IsUnicode(s):
    if isinstance(s, unicode):
        return True
    return False


def out(string):
    if DEBUG:
        try:
            string = str(string.encode('ascii', 'replace'))
        except:
            pass
        print(str(string.decode('latin-1').encode('ascii', 'replace')))
        # logwrite(string)


def Ustr(string):
    if isinstance(string, unicode):
        return str(string.encode('ascii', 'replace'))
    return str(string)


def GetNextchar(string, pos):
    try:
        return string[pos+1]
    except:
        return ''


def GetPrevchar(string, pos):
    try:
        return string[pos-1]
    except:
        return ''


def GetNextUsefullchar(string):
    j = 0
    try:
        while string[j].isspace():
            j += 1
    except:
        return '', 0
    return string[j], j


def CheckType(value):
    if isinstance(value, types.StringTypes):
        return 'String'
    if isinstance(value, bool):
        return 'Bool'
    if isinstance(value, (int, long, float)):
        return 'Numeric'
    if type(value) in [list, tuple, dict]:
        return 'Array'
    if isinstance(value, NoneType):
        return 'undefined'
    if isinstance(value, fonction):
        return 'Fonction'
    if isinstance(value, types.UnicodeType):
        return 'String'
    return 'Unknown'


# Fonction to return only one parameter from a string with correct closed [] () "" and ''
def GetItemAlone(string, separator=' '):

    l = len(string) - 1
    ret = ''

    i = -1
    # p = parenthese
    # a = accolade
    # b = bracket
    # c1 = chain with "
    # c2 = chain with '

    p = a = b = c1 = c2 = 0
    n = False
    last_char = ''

    s = False

    while i < l:
        i += 1
        ch = string[i]
        ret = ret + ch
        n = False

        # Return if the is complete and before the char wanted but not if it's the first one
        if (ch in separator) and not p and not a and not b and not c1 and not c2 and not n and (i > 0):
            return ret[:-1]

        # Skip empty space
        if ch.isspace():
            continue

        if ch == '"' and not GetPrevchar(string, i) == '\\' and not c2:
            c1 = 1 - c1
        if ch == "'" and not GetPrevchar(string, i) == '\\' and not c1:
            c2 = 1 - c2

        if not c1 and not c2:
            if ch == '(':
                p += 1
            elif ch == ')':
                p -= 1
            elif ch == '{':
                a += 1
            elif ch == '}':
                a -= 1
            elif ch == '[':
                b += 1
            elif ch == ']':
                b -= 1

            if ch == '.' and not ((last_char in '0123456789') or (string[i+1] in '0123456789')):
                n = True

        # return if the chain is complete but with the char wanted
        if (ch in separator) and not p and not a and not b and not c1 and not c2 and not n and (i > 0):
            return ret

        last_char = ch

    return ret


def MySplit(string, char, NoEmpty=False):
    r = []
    l = len(string)
    e = ""
    i = c1 = c2 = p = b = 0

    if not l:
        if NoEmpty:
            return []

    while l > i:
        c = string[i]
        if c == '"':
            c1 = 1-c1
        if c == "'":
            c2 = 1-c2

        if not c1 and not c2:
            if c == '(':
                p += 1
            if c == ')':
                p -= 1
            if c == '{':
                b += 1
            if c == '}':
                b -= 1

        if (c == char) and not c1 and not p and not b and not c2:
            r.append(e.strip())
            e = ''
        else:
            e += c

        i += 1

    r.append(e.strip())
    return r


def GetConstructor(value):
    if isinstance(value, (int, long)):
        return fonction('Number', '', '\n    [native code]\n', True)
    elif isinstance(value, fonction):
        return fonction('Function', '', '\n    [native code]\n', True)
    elif isinstance(value, types.StringTypes):
        return fonction('String', '', '\n    [native code]\n', True)
    return ''


class JSBuffer(object):
    PRIORITY = {'+': 5, '-': 5, '*': 5, '/': 5, '>': 5, '<': 5, '&': 5, '|': 5, '===': 0, '==': 0}

    def __init__(self):
        self.Reset()

    def Reset(self):
        self.type = None
        self.buffer = ''
        self.__op = ''
        self.__value = None

        # buffers
        self.buf = []
        self.opBuf = []

    def SetOp(self, op):
        if (op == '&') and (self.__op == '&'):
            return
        if (op == '|') and (self.__op == '|'):
            return
        else:
            self.__op = self.__op + op

    def CheckString(self):
        if len(self.buf) >= len(self.opBuf):
            return True
        return False

    # Need 3 values for priority
    def AddValue(self, value):
        if DEBUG:
            out('ADD (operator: ' + self.__op + ') ' + Ustr(value) + ' (' + Ustr(type(value)) + ') a ' + Ustr(self.buf))

        if not self.type:
            self.type = CheckType(value)
            self.Push(value)
            return

        if not self.__op:
            out('op ' + str(self.opBuf) + ' - buff ' + str(self.buf))
            raise Exception("Missing operator")

        self.Push(value)

    def GetPrevious(self):
        ret = None
        if len(self.buf) > 0:
            ret = self.buf[-1]
            del self.buf[-1]
            self.__op = self.opBuf[-1]
            del self.opBuf[-1]
        if not len(self.buf):
            self.type = None

        return ret

    # OP0 BUF0 OP1 BUF1 OP2 BUF2
    def Compute(self):

        # check priority
        # op1 = self.PRIORITY.get(self.opBuf[1], 2)
        # op2 = self.PRIORITY.get(self.opBuf[2], 2)

        # Need convertion type ?
        if len(self.buf) > 1:
            # Need convertion ?
            if not (self.type == CheckType(self.buf[len(self.buf) - 1])):
                # Type different mais juste operation logique
                if self.opBuf[1] == '==' or self.opBuf[1] == '===' or self.opBuf[1] == '!=' or self.opBuf[1] == '!==':
                    self.type = 'Logic'
                # Type different mais JS convertis en string ou int
                else:
                    if self.opBuf[1] == '+':
                        if DEBUG:
                            out('convertion to string')

                        if not CheckType(self.buf[0]) == 'String':
                            self.buf[0] = self.SpecialStr(self.buf[0])
                        if len(self.buf) > 1:
                            if not CheckType(self.buf[1]) == 'String':
                                self.buf[1] = self.SpecialStr(self.buf[1])
                        self.type = 'String'
                    else:
                        if DEBUG:
                            out('convertion to int')

                        if not CheckType(self.buf[0]) == 'Numeric':
                            self.buf[0] = self.SafeEval(self.buf[0])
                        if len(self.buf) > 1:
                            if not CheckType(self.buf[1]) == 'Numeric':
                                self.buf[1] = self.SafeEval(self.buf[1])
                        self.type = 'Numeric'

        # Work for operateur + | !
        if self.type == 'String':

            if '!' in self.opBuf[0]:
                self.buf[0] = not self.buf[0]
                self.opBuf[0] = self.opBuf[0].replace('!', '')
            if len(self.buf) > 1:
                if self.opBuf[1] == '!':
                    self.buf[1] = not self.buf[1]
                    self.opBuf[1] = self.opBuf[1].replace('!', '')
                elif self.opBuf[1] == '+':
                    self.buf[0] = self.buf[0] + self.buf[1]
                elif self.opBuf[1] == '|':
                    if not self.buf[0]:
                        self.buf[0] = self.buf[1]
                elif '!=' in self.opBuf[1]:
                    self.buf[0] = (self.buf[1] != self.buf[0])
                    self.type == 'Logic'
                elif '==' in self.opBuf[1]:
                    self.buf[0] = (self.buf[1] == self.buf[0])
                    self.type == 'Logic'

                # decale
                del self.opBuf[-1]
                del self.buf[-1]

        # work for all operator
        elif self.type == 'Numeric':
            if len(self.buf) > 1:
                self.buf[0] = self.opBuf[0] + str(self.buf[0]) + self.opBuf[1] + str(self.buf[1])
                self.opBuf[0] = ''
                # decale
                del self.opBuf[-1]
                del self.buf[-1]
            else:
                self.buf[0] = self.opBuf[0] + str(self.buf[0])
                self.opBuf[0] = ''

        # work for bool
        elif self.type == 'Bool':
            if len(self.buf) > 1:
                self.buf[0] = self.opBuf[0] + str(self.buf[0]) + self.opBuf[1] + str(self.buf[1])
                self.opBuf[0] = ''
                # decale
                del self.opBuf[-1]
                del self.buf[-1]
            else:
                self.buf[0] = self.opBuf[0] + str(self.buf[0])
                self.opBuf[0] = ''

        # work for Logic and undefined, only == and ===
        elif self.type == 'Logic' or self.type == 'undefined':
            if len(self.buf) > 1:
                if not self.buf[0] == self.buf[1]:
                    self.buf[0] = False
                else:
                    self.buf[0] = True

                if '!' in self.opBuf[1]:
                    self.buf[0] = not self.buf[0]
                # décale
                del self.opBuf[-1]
                del self.buf[-1]

        elif len(self.buf) > 1:
            print(self.type)
            print(self.buf)
            print(self.opBuf)
            raise Exception("Can't compute")

    # on décale tout
    def Push(self, value):

        if len(self.buf) > 1:
            self.Compute()

        self.buf.append(value)
        self.opBuf.append(self.__op)
        self.__op = ''

        return

    def SpecialStr(self, value):
        if CheckType(value) == 'Numeric':
            return str(value)
        if value is None:
            return 'undefined'
        if value is True:
            return 'true'
        if value is False:
            return 'false'
        if type(value) in [list]:
            convert_first_to_generator = (str(w) for w in value)
            return ','.join(convert_first_to_generator)
        if type(value) in [dict]:
            return '[object Object]'
        if CheckType(value) == 'Fonction':
            return value.ToStr()

        return str(value)

    # ok all finished, force compute
    def GetBuffer(self):

        # Force compute
        self.Compute()
        while len(self.buf) > 1:
            self.Compute()

        if self.type == 'Logic':
            return self.buf[0]

        if self.type == 'Numeric':
            ret = self.SafeEval(self.buf[0])
            # There is a bug sometime, long var are signed with L but are int in reality.
            if isinstance(ret, long):
                try:
                    ret = int(ret)
                except:
                    pass
            return ret

        if self.type == 'Bool':
            if self.SafeEval(self.buf[0].replace('True', '1').replace('False', '0')):
                return True
            else:
                return False

        if self.type is None:
            return ''

        return self.buf[0]

    # WARNING : Take care if you edit this function, eval is realy unsafe.
    # better to use ast.literal_eval() but not implemented before python 3
    def SafeEval(self, str):
        if not str:
            raise Exception('Nothing to eval')
        f = re.search('[^0-9\+\-\.\(\)<>=xabcdef\|&%!*\^\/~]', str)
        if f:
            raise Exception('Wrong parameter to Eval : ' + str)
            return 0
        str = str.replace('!', 'not ')
        # str = str.replace('=', '==')
        # print('>>' + str)
        return eval(str)


class fonction(object):
    def __init__(self, name, param, data, c=False):
        self.name = name
        self.code = data
        self.param = param
        self.const = c
        self.tuple = {}

    def ToStr(self):
        return 'function ' + self.name + '(' + str(self.param)[1:-1] + ') {' + self.code + '}'


class Hack(object):
    def __init__(self, var):
        self.var = var

    def text(self):
        return self.var


class JsParserHelper1(object):
    def __init__(self, tmp_var):
        self.reset()
        self.used = False
        self.Tmp_var = tmp_var
        self.op = None

    def reset(self):
        # type = None
        self.name = None
        self.t = None
        self.arg = None
        self.rest_code = ''
        # self.op = None
        self.eval = False
        self.property = False

    def process(self, JScode):

        # IDK why ?
        if self.op:
            return False

        self.reset()

        self.at1 = None

        # If already started
        if JScode.startswith(self.Tmp_var):
            self.name = self.Tmp_var
        else:
            # si on a rien encore trouve on recherche une variable/fonction
            r = re.search('^([\w\$][\w\$]*)', JScode, re.UNICODE)
            if r and not self.used:
                self.name = r.group(1)
            else:
                return False

        self.used = True

        # By defaut
        self.t = 'var'

        JScode = JScode[(len(self.name)):]

        c, p = GetNextUsefullchar(JScode)
        while (c in '.[') and c and not self.at1:
            JScode = JScode[p:]
            if c == '[':
                a = GetItemAlone(JScode, ']')
                JScode = JScode[(len(a)):]
                self.at1 = a[1:-1]
                self.eval = True

            if c == '.':
                a = GetItemAlone(JScode[1:], '[(.\/*-+{}<>|=~^%!')
                JScode = JScode[(len(a)+1):]
                self.at1 = a
                self.property = True

            c, p = GetNextUsefullchar(JScode)

        if c == '(':
            a = GetItemAlone(JScode, ')')
            JScode = JScode[(len(a)):]
            self.arg = a[1:-1]
            self.t = 'fct'

        # operation ?
        if not self.t == 'fct':
            m = re.search('^(' + REG_OP + '|\[|$)', JScode, re.UNICODE)
            if m and JScode:
                self.op = m.group(1).strip()
                if self.op == '[':
                    self.op = None
                else:
                    # prb because the only possible case is ==
                    if len(self.op) > 1 and self.op[0] == '=' and not self.op[1] == '=':
                        self.op = self.op[0]
                    # a +=-2 situation
                    if len(self.op) > 2 and self.op[1] == '=':
                        self.op = self.op[:2]

                    JScode = JScode[(len(self.op)):]

        if self.t == 'fct':
            if DEBUG:
                out('Fonction :' + self.name + ' method: ' + str(self.at1) + ' arg: ' + self.arg)
        elif self.t == 'var':
            if self.property:
                self.at1 = '"' + self.at1 + '"'
            if DEBUG:
                out('Variable :' + Ustr(self.name) + ' []= ' + Ustr(self.at1))
            # Exit if nothing to process
            if (self.name == self.Tmp_var) and not self.at1 and not self.op:
                return False
        if self.op:
            if DEBUG:
                out('operation :' + Ustr(self.name) + ' []= ' + Ustr(self.at1) + ' op: ' + str(self.op))

            # hack for priority
            if '==' in self.op:
                JScode = '(' + JScode + ')'

        self.rest_code = JScode

        return True


class JsParser(object):

    def __init__(self):
        self.Unicode = False
        self.HackVars = []
        self.debug = False
        self.LastEval = ''
        self.SpecialOption = ''

        self.Return = False
        self.ReturnValue = None

        self.Break = False
        self.continu = False

        self.FastEval_vars = []
        self.FastEval_recur = 0

        self.option_ForceTest = False

        self.SystemVars = []
        self.GlobalVar = []

    def SetReturn(self, r, v):
        self.Return = True
        self.RecursionReturn = r
        self.ReturnValue = v

    def SetOption(self, option):
        if option == 'ForceTest':
            self.option_ForceTest = True

    def AddHackVar(self, name, value):
        self.HackVars.append((name, value))

    def GetVarHack(self, name):
        return self.GetVar(self.HackVars, name)

    def PrintVar(self, vars):
        print('-------------------------------')
        for i, j in vars:
            bon = ""
            if isinstance(j, fonction):
                bon = str(j.tuple)  # + " " + str(j.code)
            print(Ustr(i) + ' : ' + Ustr(j) + " " + bon)
        print('\n')
        for i, j in self.HackVars:
            print(Ustr(i) + ' : ' + Ustr(j))
        print('-------------------------------')

    # Need to take care at chain var with " and '
    def ExtractFirstchain(self, string):

        if not len(string.strip()):
            return '', 0

        l = len(string)
        string = string + ' '  # To prevent index out of range, hack

        i = -1
        p = 0  # parenthese
        a = 0  # accolade
        b = 0  # bracket
        f = False  # fonction ?
        r = False  # Regex
        com1 = False
        com2 = False
        prev = ''  # previous char
        c1 = 0  # string with "
        c2 = 0  # string with '

        stringR = ''

        while l > i:

            i += 1

            # ignore comment
            if string[i:(i+2)] == '/*':
                com1 = True
            if com1:
                if string[i:(i+2)] == '*/':
                    com1 = False
                    i += 1
                continue
            if string[i:(i+2)] == '//' and not r and not c1 and not c2:
                com2 = True
            if com2:
                if string[i] == '\n':
                    com2 = False
                else:
                    continue

            ch = string[i]

            # if ch == '"' and not GetPrevchar(string,i) == '\\' and not c2:
            if ch == '"' and not c2:
                c1 = 1 - c1
            if ch == "'" and not c1:
                c2 = 1 - c2

            # if we are in a chain no more thing to do than waiting for end
            if c1 or c2:
                stringR = stringR + ch
                continue

            if ch == '(':
                p += 1
            elif ch == ')':
                p -= 1
            elif ch == '{':
                a += 1
            elif ch == '}':
                a -= 1
            elif ch == '[':
                b += 1
            elif ch == ']':
                b -= 1
            if r and ch == '/':
                r = False
            if ch == '/' and prev == '=':
                r = True

            # vire espace inutile
            if ch.isspace() and not c1 and not c2:
                if not(prev in ALPHA and GetNextchar(string, i) in ALPHA):
                    continue

            stringR = stringR + ch

            # memorise last char
            if not ch.isspace():
                prev = ch

            # Dans tout les cas les parenthses doivent etre fermees, ainsi que les crochet
            if not p and not b:

                # Si on rencontre un ; par defaut
                if (ch == ';') and not f:
                    # Ok, accolade fermees aussi, c'est tout bon
                    if not a:
                        return stringR, i
                    # Accolade non fermee, c'est une fonction
                    else:
                        f = True
                # si c'est une fonction et l'accolade fermee
                if f and not a:

                    # quel est le caractere suivant ?
                    j = i + 1
                    while (string[j].isspace()) and (l > j):
                        j += 1
                    # Si parenthese on repart
                    if string[j] == '(':
                        continue

                    # Mal formated string ?
                    # Sometime, coder forget the last ; before the }
                    # Desactived for the moment, because can bug in 'a = {};'
                    if False:
                        j = -2
                        while (stringR[j].isspace()) or (stringR[j] == '}'):
                            j -= 1
                        if not (stringR[j] == ';'):
                            j += 1
                            stringR = stringR[:j] + ';' + stringR[j:]

                    # if there is a last ; add it
                    if string[i+1] == ';':
                        stringR = stringR + ';'
                        i += 1

                    return stringR, i

        # last check
        if p or b or a or f or c1 or c2:
            out('parenthesis:' + str(p) + ' bracket:' + str(b) + ' accolade:' + str(a) + ' fonction:' + str(f) + ' chain:' + str(c1) + str(c2))
            raise Exception("Can't extract chain " + string)

        # chaine bugguée ?
        if not string[-1:] == ';':
            # out('ERROR Extract chain without ";" > ' + string )
            return string + ';', i

        out('parenthesis:' + str(p) + ' bracket:' + str(b) + ' accolade:' + str(a) + ' fonction:' + str(f) + ' chain:' + str(c1) + str(c2))
        raise Exception("*** Can't extract chain " + string)

    # Everything Without a "Real" is False
    def CheckTrueFalse(self, string):
        # if DEBUG:
            # out('> Check True or false : ' + str(string))

        if isinstance(string, bool):
            if string is True:
                return True
        elif isinstance(string, types.StringTypes):
            if not string == '':
                return True
        if isinstance(string, (int, long, float)):
            if not (string == 0):
                return True
        if isinstance(string, (list, tuple)):
            # if not (string == []):
            return True
        return False

    # Syntax > aaaaaa.bbbbbb(cccccc) ou bbbb(cccc) ou "aaaa".bb(ccc) ou aa[bb](cc)
    # Name = fonction(arg)
    def FonctionParser(self, vars, allow_recursion, name, function, arg2, JScode):

        arg = arg2.strip()

        if isinstance(name, (int, long, float)):
            name = str(name)

        if DEBUG:
            out('*** fonction > Name: ' + Ustr(name) + ' arg: ' + Ustr(arg) + ' function: ' + Ustr(function))

        # hack ?
        if isinstance(name, Hack):
            a = MySplit(arg, ',', True)
            # In this case function = text but useless ATM

            if a:
                # ecriture
                vv = self.evalJS(a[0], vars, allow_recursion)
                self.AddHackVar(name.var, vv)
                return vv, JScode
            else:
                # lecture
                vv = self.GetVarHack(name.var)
                out('Hack vars (set): ' + vv)
                return vv, JScode

        # Definite function ?
        fe = self.IsFunc(vars, function)
        if not fe:
            try:
                fe = self.IsFunc(vars, '%s["%s"]' % (name, function))
            except:
                pass

        if fe:
            if fe == '$':
                a = MySplit(arg, ',', True)
                vv = self.evalJS(a[0], vars, allow_recursion)
                fff = Hack(vv)

                return fff, JScode

            elif isinstance(fe, types.MethodType):
                # print(fe.im_func.__name__ #parseint)
                # print(fe.im_class.__name__ #Basic)
                function = fe.im_func.__name__
                if DEBUG:
                    out("> function (native): " + function + ' arg=' + arg)
                # and continu with native fonction

            elif isinstance(fe, fonction):
                if DEBUG:
                    out('> fonction definie par code : ' + function)

                n, p, c, ct = fe.name, fe.param, fe.code, fe.const
                a = MySplit(arg, ',', True)

                a2 = []
                # out('code de la fonction : ' + c)

                if ct:
                    out('constructor mode')
                    # hack
                    # Make replacement
                    JScode = "%s(%s)%s" % (n, arg, JScode) + ';'

                    NewEval = self.Parse(JScode, vars, allow_recursion)

                    return NewEval, ''

                for i in a:
                    vv = self.evalJS(i, vars, allow_recursion)
                    a2.append(RemoveGuil(vv))

                while len(a2) < len(p):
                    a2.append(None)  # undefined

                # We copy previous variables and function
                # TODO list copy is rly bad for optimisation, need to make variable list by scope
                List_tmpvar = list(vars)

                if (len(p) > 0) and (len(a2) > 0):
                    nv = tuple(zip(p, a2))
                    for z, w in nv:
                        self.SetVar(List_tmpvar, z, w)
                        # List_tmpvar.append(z)

                jjj = self.Parse(c, List_tmpvar, allow_recursion)

                # And delete tmp var
                # for i in List_tmpvar:
                #     self.InitVar(vars, i)

                if self.Return:
                    self.Return = None

                # TODO: REALLY IMPORTANT : Check wich one is good
                # HACK : NEED TO CHECK
                if self.ReturnValue is None:
                    self.ReturnValue = jjj
                # return jjj, JScode
                return self.ReturnValue, JScode

            else:
                raise Exception("Strnage fonction")

        # Native fonction
        s = ''
        if type(name) in [list, tuple, dict, types.MethodType, NoneType]:
            s = name
        else:
            if name.startswith('"') or name.startswith("'"):
                s = RemoveGuil(name)
            else:
                if self.IsVar(vars, name):
                    s = self.GetVar(vars, name)
                else:
                    s = name

        for lib in List_Lib:
            if hasattr(lib, function):

                out('Fonction lib : ' + str(function))

                if not function == "eval":
                    arg = MySplit(arg, ',')
                    for i in range(len(arg)):
                        arg[i] = self.evalJS(arg[i], vars, allow_recursion)

                # for fastcall
                self.FastEval_vars = vars
                self.FastEval_recur = allow_recursion

                cls = lib(self, s)

                r = getattr(cls, function)(arg)

                # set new value if changed
                if hasattr(lib, 'Get'):
                    NV = getattr(cls, 'Get')()
                    if not NV == s:
                        self.SetVar(vars, name, NV)

                return r, JScode

        # constructor
        if function == 'Function':
            NewCode = RemoveGuil(arg) + ';'

            v = self.MemFonction(vars, '', '', False, '{' + NewCode + '}')[2]
            JScode = v + JScode

            NewEval = self.Parse(JScode, vars, allow_recursion)
            return NewEval, ''

        self.PrintVar(vars)
        raise Exception("Unknown fonction : " + function + " Name " + name)

    def Fast_Eval(self, strg):
        r = self.evalJS(strg, self.FastEval_vars, self.FastEval_recur)
        return r

    def VarParser(self, vars, allow_recursion, variable, op, JScode):

        if DEBUG:
            out('Variable : ' + Ustr(variable) + '  operator : ' + op)

        # if it's a creation/modification
        if op == '=':

            if DEBUG:
                out('creation/modification')

            v1 = GetItemAlone(JScode, ',')
            JScode = JScode[(len(v1)):]

            v1 = v1.strip()

            r = self.VarManage(allow_recursion, vars, variable, v1)

            # and return it
            # r = self.GetVar(vars,variable)
            return r, JScode

        if not self.IsVar(vars, variable):
            raise Exception("Can't find var " + str(variable))

        r = self.GetVar(vars, variable)

        # Only modification
        if len(op) == 2:

            # just put var because not managed here
            if op[0] in '=!':
                return r, op + JScode

            # ok so what is it ?
            if DEBUG:
                out("> var " + variable + "=" + str(r))

            # check if it's i++ ou i -- form
            if op == '++':
                self.SetVar(vars, variable, r + 1)
                return r, JScode

            elif op == '--':
                self.SetVar(vars, variable, r-1)
                return r, JScode

            # a+=1 form
            elif op[1] == '=' and op[0] in '+-*/%^':
                n = GetItemAlone(JScode, ';,')
                # out('A rajouter ' + n)
                r = self.evalJS(variable + op[0] + n, vars, allow_recursion)
                # self.SetVar(vars, variable, r)

                if isinstance(r, (int, long, float)):
                    self.VarManage(allow_recursion, vars, variable, str(r))
                if isinstance(r, str):
                    self.VarManage(allow_recursion, vars, variable, '"' + r + '"')
                else:
                    self.VarManage(allow_recursion, vars, variable, str(r))

                JScode = JScode[(len(n)):]
                return r, JScode

        # just var
        # re-ad op if not used
        JScode = op + JScode
        return r, JScode

    def evalJS(self, JScode, vars, allow_recursion):

        if allow_recursion < 0:
            raise Exception('Recursion limit reached')

        allow_recursion -= 1

        # plus que la chaine a evaluer
        JScode = JScode.strip()

        if DEBUG:
            out('-------------')
            out(str(allow_recursion) + ' : A evaluer >' + JScode + '<\n')

        # ********************************************************

        InterpretedCode = JSBuffer()

        while len(JScode) > 0:
            c = JScode[0]

            # print('InterpretedCode > ' + InterpretedCode)
            if DEBUG:
                out('JScode > ' + JScode.encode('ascii', 'replace') + '\n')

            # parentheses
            if c == "(":

                c2 = GetItemAlone(JScode, ')')[1:-1]
                pos2 = len(c2) + 2
                JScode = JScode[pos2:]

                if re.search(REG_OP, c2, re.UNICODE):
                    # usefull parentheses
                    v = self.evalJS(c2, vars, allow_recursion)

                    self.SetVar(vars, 'TEMPORARY_VARS' + str(allow_recursion), v)
                    JScode = 'TEMPORARY_VARS' + str(allow_recursion) + JScode
                else:
                    # print('useless')
                    # useless parentheses
                    JScode = c2 + JScode
                    continue

            # remove "useless" code
            if JScode.startswith('new '):
                JScode = JScode[4:]
                continue
            if JScode.startswith('const '):
                JScode = JScode[6:]
                continue

            # in operator
            if JScode[0:2] == 'in' and not JScode[2].isalpha():
                A = InterpretedCode.GetPrevious()
                B = GetItemAlone(JScode[2:], ',;&|')
                B2 = self.evalJS(B, vars, allow_recursion)

                if type(B2) in [types.MethodType, types.InstanceType]:
                    B2 = str(B2)

                if A in B2:
                    InterpretedCode.AddValue(True)
                else:
                    InterpretedCode.AddValue(False)
                JScode = JScode[(len(B)+2):]
                continue

            # Special value
            m = re.search('^(true|false|null|String)', JScode, re.UNICODE)
            if m:
                if not JScode.startswith('String('):
                    v = m.group(1)
                    JScode = JScode[len(v):]

                    if v == 'true':
                        InterpretedCode.AddValue(True)
                    if v == 'false':
                        InterpretedCode.AddValue(False)
                    if v == 'null':
                        InterpretedCode.AddValue(None)
                    if v == 'String':
                        self.SetVar(vars, 'TEMPORARY_VARS' + str(allow_recursion), '')
                        JScode = 'TEMPORARY_VARS' + str(allow_recursion) + JScode
                    # if v == 'Array':
                        # InterpretedCode.AddValue([])

                    continue

            # hackVars
            r = re.search('^\$\("#([\w]+)"\)\.text\(\)', JScode)
            if r:
                InterpretedCode.AddValue(self.GetVar(self.HackVars, r.group(1)))
                JScode = JScode[(r.end()):]
                continue

            if JScode[0] == '$':
                InterpretedCode.AddValue('$')
                JScode = JScode[1:]
                continue

            # new function declaration ? Need to be before the fonction/variable parser.
            # var x = function (a, b) {return a * b};
            # function myFunction(a, b) {return a * b};
            if JScode.startswith("function"):
                # m = re.search(r'^(\()* *function(?: ([\w]+))* *\(([^\)]*)\) *{', JScode, re.DOTALL)
                m = re.search(r'^function(?: ([\w]+))* *\(([^\)]*)\) *{', JScode, re.DOTALL)
                if m:
                    name = ''
                    openparenthesis = False
                    if m.group(1):
                        name = m.group(1)

                    replac, pos3, v = self.MemFonction(vars, name, m.group(2), openparenthesis, JScode)
                    JScode = replac
                    if not v in replac:
                        InterpretedCode.AddValue(v)

                    continue

            # pointeur vers fonction ?
            try:
                if hasattr(Basic, JScode):
                    fm = getattr(Basic(self, None), JScode)
                    InterpretedCode.AddValue(fm)
                    JScode = ''
                    continue
            except:
                pass

            # 3 - numeric chain
            r = re.search('(^(?:(?:0x[0-9a-f]+)|(?:[0-9]+)))', JScode)
            if r:
                v = JScode[0:r.end()]
                if v.startswith('0x'):
                    v = int(v, 0)
                else:
                    v = int(v)
                InterpretedCode.AddValue(v)

                JScode = JScode[(r.end()):]
                continue  # for this one continue directly

            # 4 - Regex
            r = re.search('^\/.*\/(.*$)', JScode)
            if r:
                reg = r.group(0)
                flag = r.group(1)
                # test if the regex is valid
                if flag:
                    for i in flag:
                        if i not in 'gimuy':
                            reg = None
                            break
                InterpretedCode.AddValue(reg)
                JScode = JScode[(len(r.group(0))):]
                continue  # return directly

            # 0 object
            if c == "{":
                c2 = GetItemAlone(JScode, '}')[1:-1]
                pos2 = len(c2) + 2

                valueT = MySplit(c2, ',', True)

                v = {}
                for k in valueT:
                    l = MySplit(k, ':')
                    # WARNING : no eval here in JS
                    # v2g = self.evalJS(l[0], vars, func, allow_recursion)
                    v2g = RemoveGuil(l[0])
                    v2d = self.evalJS(l[1], vars, allow_recursion)
                    v[v2g] = v2d

                JScode = JScode[pos2:]

                InterpretedCode.AddValue(v)
                continue

            # 1 - Array / method
            if c == "[":
                c2 = GetItemAlone(JScode, ']')[1:-1]
                pos2 = len(c2) + 2

                # all this part is managed away but not for some rare case.
                A = InterpretedCode.GetPrevious()
                if not A:
                    valueT = MySplit(c2, ',', True)

                    v = []
                    for k in valueT:
                        v2 = self.evalJS(k, vars, allow_recursion)
                        v.append(v2)

                    JScode = JScode[pos2:]
                    InterpretedCode.AddValue(v)
                    continue

                # other case
                self.SetVar(vars, 'TEMPORARY_VARS' + str(allow_recursion), A)
                JScode = 'TEMPORARY_VARS' + str(allow_recursion) + JScode

            # 2 - Alpha chain
            elif c == '"' or c == "'":

                ee = GetItemAlone(JScode, c)
                e = len(ee)
                vv = ee[1:-1]

                # raw string cannot end in a single backslash
                # if vv[-1:] == '\\' and  not vv[-2:-1] == '\\':
                    # vv = vv + '\\'

                # warning with this function
                # if not vv.endswith('\\'):
                    # vv = vv.decode('string-escape')

                JScode = JScode[e:]

                # to be faster
                if len(JScode) == 0:
                    InterpretedCode.AddValue(vv)
                    continue
                # normal way
                else:
                    self.SetVar(vars, 'TEMPORARY_VARS' + str(allow_recursion), vv)
                    JScode = 'TEMPORARY_VARS' + str(allow_recursion) + JScode

            item = ''
            # 5 Variable/fonction/object
            P1 = JsParserHelper1('TEMPORARY_VARS' + str(allow_recursion))
            while P1.process(JScode):
                JScode = P1.rest_code
                r = None

                if P1.t == 'var':

                    # special vars
                    if P1.name == 'window' and P1.at1:
                        P1.name = RemoveGuil(P1.at1)
                        P1.at1 = ''

                    Var_string = P1.name
                    if P1.at1:
                        Var_string = "%s[%s]" % (P1.name, P1.at1)

                    # operation / creation ?
                    if P1.op:
                        if DEBUG:
                            out('creation/modification/test ' + Var_string + ' ' + P1.op)
                        r, JScode = self.VarParser(vars, allow_recursion, Var_string, P1.op, JScode)

                    else:
                        if not self.IsVar(vars, P1.name):
                            self.PrintVar(vars)
                            raise Exception('Variable error : ' + Ustr(P1.name))

                        r = self.GetVar(vars, Var_string)

                elif P1.t == 'fct':

                    if P1.at1:
                        fonction = P1.at1
                        name = P1.name
                    else:
                        fonction = P1.name
                        name = ''

                    if P1.eval:
                        fonction = self.evalJS(fonction, vars, allow_recursion)

                    # hack, devrait etre acive tout le temps
                    if 'TEMPORARY_VARS' in name:
                        name = self.evalJS(name, vars, allow_recursion)

                    r, JScode = self.FonctionParser(vars, allow_recursion, name, fonction, P1.arg, JScode)

                # to speed up
                if not JScode:
                    # It speed up but cause some TEMPORARY_VARS stay in code.
                    InterpretedCode.AddValue(r)
                    continue
                # normal way
                else:
                    self.SetVar(vars, 'TEMPORARY_VARS' + str(allow_recursion), r)
                    JScode = 'TEMPORARY_VARS' + str(allow_recursion) + JScode

            # after this part, all TEMPORARY_VARS need to be removed
            if JScode.startswith('TEMPORARY_VARS' + str(allow_recursion)):
                r = self.GetVar(vars, 'TEMPORARY_VARS' + str(allow_recursion))
                self.InitVar(vars, 'TEMPORARY_VARS' + str(allow_recursion))
                JScode = JScode[(len('TEMPORARY_VARS' + str(allow_recursion))):]
                InterpretedCode.AddValue(r)
                continue

            if P1.used:
                continue

            # --var method, HACK
            if JScode[0:2] == '--' or JScode[0:2] == '++':
                m = re.search('^(\({0,1}\w[\w\.]*\){0,1} *(?:\[[^\]]+\])* *)(' + REG_OP + '|\[|$)', JScode[2:], re.UNICODE)
                if m:
                    l = len(m.group(1))
                    JScode = m.group(1) + JScode[0:2] + JScode[(l+2):]
                    continue
                else:
                    bb(mm)

            # Space to remove
            if c == ' ' or c == '\n':
                JScode = JScode[1:]
                continue

            # Escape char
            if c == '\\':
                JScode = JScode[1:]
                continue

            # Special if (A)?(B):(C)
            if c == '?':
                out(" ****** Special if 1 ********* ")
                # need to find all part
                # A = InterpretedCode.GetPrevious()  Not working if parenthesis absent
                A = InterpretedCode.GetBuffer()
                InterpretedCode.Reset()  # and clear them
                B = GetItemAlone(JScode, ':')
                C = GetItemAlone(JScode[(len(B) + 1):])

                Totlen = len(B) + len(C) + 2
                B = B[1:]
                if B.startswith('('):
                    B = B[1:-1]
                if C.startswith('('):
                    C = C[1:-1]
                if A:
                    r = self.evalJS(B, vars, allow_recursion)
                else:
                    r = self.evalJS(C, vars, allow_recursion)

                InterpretedCode.AddValue(r)
                JScode = JScode[Totlen:]
                continue

            # Short-circuiting evaluations
            if JScode[0:2] == '&&' or JScode[0:2] == '||':
                out(" ****** Short-circuiting  ********* ")
                # A = InterpretedCode.GetPrevious()
                A = InterpretedCode.GetBuffer()
                InterpretedCode.Reset()
                if JScode[2:].startswith('('):
                    B = GetItemAlone(JScode[2:], ' )')
                else:
                    B = GetItemAlone(JScode[2:])

                Totlen = len(B) + 2
                if B.startswith('('):
                    B = B[1:-1]

                # for && if the first operand evaluates to false, the second operand is never evaluated
                if JScode[0:2] == '&&':
                    if A:
                        r = self.evalJS(B, vars, allow_recursion)
                        InterpretedCode.AddValue(r)
                    else:
                        InterpretedCode.AddValue(A)
                # for || if the result of the first operand is true, the second operand is never evaluated
                if JScode[0:2] == '||':
                    if not A:
                        r = self.evalJS(B, vars, allow_recursion)
                        InterpretedCode.AddValue(r)
                    else:
                        InterpretedCode.AddValue(A)

                JScode = JScode[Totlen:]
                continue

            # Operation
            if c in '+<>-*/=&%|!^.~':
                InterpretedCode.SetOp(c)
                JScode = JScode[1:]
                continue

            # ???
            if JScode == ';':
                JScode = JScode[1:]
                continue

            # comma
            if c == ',':
                InterpretedCode.GetPrevious()
                JScode = JScode[1:]
                continue

            # Not found part
            # We will make another turn
            self.PrintVar(vars)
            out("Can't eval string :" + JScode)
            out("Last eval : " + str(self.LastEval))

            # print(debug.encode('ascii', 'replace'))
            raise Exception(str(allow_recursion) + " : Can't Eval chain : " + JScode)

        InterpretedCode2 = InterpretedCode.GetBuffer()

        if DEBUG:
            out(str(allow_recursion) + ' : Evalue > ' + Ustr(InterpretedCode2) + " type " + Ustr(type(InterpretedCode2)))
            out('-------------')

        # if str(InterpretedCode2).endswith('51'):
            # ff(mm)

        self.LastEval = InterpretedCode2
        return InterpretedCode2

    def InitVar(self, var, variable):
        variable = variable.strip()

        for j in var:
            if j[0] == variable:
                var.remove(j)
                return

    def GetVar(self, var, variable):

        # variable = variable.strip()

        index = None
        if '[' in variable:
            index = GetItemAlone(variable[(variable.find('[')):], ']')
            index = index[1:-1]
            variable = variable.split('[')[0]
            index = self.evalJS(index, var, 50)

        if '.' in variable:
            index = variable.split('.')[1]
            variable = variable.split('.')[0]

        if DEBUG:
            out('*** Variable Get > var:' + Ustr(variable) + ' index :' + Ustr(index))

        j = None
        # Really bad for optimisation (array concatenation)
        for j in var + self.SystemVars:
            if j[0] == variable:
                break

        # hack Useless
        # if j and index:
        #     k = j[1]
        #     try:
        #         if str(k).startswith('AnonymousFunc'):
        #             for l in var + self.SystemVars:
        #                 if l[0] == k:
        #                     print("Test : " + variable + "[" + index + ']')
        #                     #j = l
        #                     self.PrintVar(var)
        #                     break
        #     except:
        #         pass

        if j:
            k = j[1]
            r = k

            if not (index == None):
                # Special method
                if index == 'length':
                    r = len(k)
                    return r
                if index == 'constructor':
                    if type(k) in [dict]:
                        if not k.get('constructor'):
                            return GetConstructor(k)
                    else:
                        return GetConstructor(k)
                # Object tuple, but using global var for the moment
                f = self.IsFunc(self.GlobalVar, j[1])
                if f:
                    return f.tuple.get(index, None)
                # normal one
                if type(k) in [list, tuple, str, unicode]:
                    if CheckType(index) == 'Numeric':
                        if int(index) < len(k):
                            r = k[int(index)]
                        else:
                            r = 'undefined'
                    elif CheckType(index) == 'String':
                        index = RemoveGuil(index)
                        try:
                            r = k[index]
                        except:
                            try:
                                r = k[int(index)]
                            except:
                                # Need better check
                                # if self.IsFunc(var, j[1]):
                                    # return 'undefined'
                                    # return None
                                return None  # To check
                elif type(k) in [dict]:
                    index = RemoveGuil(index)
                    if CheckType(index) == 'Numeric':
                        index = str(index)

                    # if type(index) in [unicode]:
                        # index = unicode(index, "utf-8")

                    r = k.get(index)

                elif type(k) in [type]:
                    r = getattr(k(self, None), index)

            return r

        # search it in hackvar ?
        for j in self.HackVars:
            if j[0] == variable:
                return j[1]

        # search in fonction in lib, Hack again
        # for lib in List_Lib:
        #     if variable == str(lib.__name__):
        #         return lib
        # self.PrintVar(var)
        raise Exception('Variable not defined: ' + str(variable))

    def SetVar(self, var, variable, value, index=None):

        variable = variable.strip()

        # If not xisting var, create it first ?
        if not self.IsVar(var, variable):
            # Chain or numeric
            if index is None:
                var.append((variable, value))
                return
            # dictionnary
            elif isinstance(index, types.StringTypes):
                var.append((variable, {}))
            # array
            else:
                var.append((variable, []))

        for j in var:
            if j[0] == variable:
                if index is None:
                    # chain ?
                    if isinstance(value, types.StringTypes):
                        var[var.index(j)] = (variable, value)
                    # Numeric
                    else:
                        var[var.index(j)] = (variable, value)
                else:
                    # Array
                    # hack, Variable created as list but used as dictionnary, so need convertion
                    if (isinstance(index, types.StringTypes)) and type(var[var.index(j)][1]) in [list, tuple]:
                        ind = var.index(j)
                        var[ind] = (variable, {})
                        j = (variable, {})

                    if type(var[var.index(j)][1]) in [list, tuple]:
                        Listvalue = var[var.index(j)][1]

                        # ok this place doesn't esist yet
                        l = int(index) - len(Listvalue) + 1
                        while l > 0:
                            Listvalue.append('undefined')
                            l -= 1
                        # Now modify it
                        if type(value) in [list, tuple]:
                            Listvalue = value
                        else:
                            Listvalue[int(index)] = value
                        var[var.index(j)] = (variable, Listvalue)
                    # dictionnary
                    elif type(var[var.index(j)][1]) in [dict]:
                        ind = var.index(j)
                        Listvalue = var[ind][1]
                        Listvalue[Ustr(index)] = value
                        var[ind] = (variable, Listvalue)

                    else:
                        # Variable is fonction so use Object tuple and using global var for the moment
                        f = self.IsFunc(self.GlobalVar, j[1])
                        if f:
                            f.tuple[index] = value

                return

    def GetTypeVar(self, var, variable):
        try:
            variable = variable.split('[')[0]
            variable = variable.split('.')[0]
            for j in var:
                if j[0] == variable:
                    return type(j[1])
            return 'undefined'
        except:
            return 'undefined'

    def IsVar(self, var, variable, index=None):
        try:
            variable = variable.split('[')[0]
            variable = variable.split('.')[0]

            # Normal vars
            for j in var:
                if j[0] == variable:
                    if index is None:
                        return True
                    if index in var[var.index(j)][1]:
                        return True
            # search it in system vars
            for j in self.SystemVars:
                if j[0] == variable:
                    return True
            return False
        except:
            return False

    # Need to use metaclass here
    def IsFunc(self, vars, name):
        bExist = False
        bExist = self.IsVar(vars, name)

        if not bExist:
            return False
        global gg

        f = self.GetVar(vars, name)

        if f == '$':
            return '$'
        if isinstance(f, fonction):
            return f
        elif isinstance(f, types.MethodType):
            return f
        else:
            r = self.IsFunc(vars, f)
            if not r:
                r = self.IsFunc(self.GlobalVar, f)
            return r

    def VarManage(self, allow_recursion, vars, name, value=None):

        index = None
        init = False

        if DEBUG:
            out('*** Variable manager name: ' + Ustr(name) + ' value: ' + Ustr(value) + ' ' + str(type(value)))

        try:
            value = value.strip()
        except:
            pass
        name = name.strip()

        # variable is an object
        if '.' in name:
            if self.GetTypeVar(vars, name) == 'tuple':
                index = name.split('.')[1]
                name = name.split('.')[0]
        # Variable is an array ?
        m = re.search(r'^\({0,1}([\w]+)\){0,1}\[(.+?)\]$', name, re.DOTALL | re.UNICODE)
        if m:
            name = m.group(1)
            index = m.group(2)
            index = self.evalJS(index, vars, allow_recursion)

        # if name.startswith('('):
        #     name = name[1:-1].strip()

        if value:
            if isinstance(value, (int, long, float)):
                value = self.evalJS(value, vars, allow_recursion)
            else:
                value = self.evalJS(value, vars, allow_recursion)
                # to optimise
                if type(value) in [list, tuple]:
                    if index is None:
                        index = 0
                        init = True
                elif type(value) in [dict]:
                    if index is None:
                        init = True

        name = name.strip()

        # Output for debug
        if DEBUG:
            if index is None:
                out('*** Variable in parser => ' + Ustr(name) + ' = ' + Ustr(value))
            else:
                out('*** Variable in parser => ' + Ustr(name) + '[' + Ustr(index) + ']' + ' = ' + Ustr(value))

        # chain
        if isinstance(value, types.StringTypes):
            self.SetVar(vars, name, value, index)
        # number
        elif isinstance(value, (int, long, float)):
            self.SetVar(vars, name, value, index)
        # list
        elif type(value) in [list, tuple, dict]:
            if init:
                self.InitVar(vars, name)
            self.SetVar(vars, name, value, index)
        # fonction
        elif isinstance(value, fonction):
            self.SetVar(vars, name, value, index)
        # undefined
        elif value is None:
            self.SetVar(vars, name, None, index)
        else:
            raise Exception('> ERROR : Var problem >' + str(value))

        # and return value, to avoid double eval
        return value

    # (Function(arg){code})(arg2) Self invoked
    # (Function(arg){code}(arg2)) Self invoked
    # Function(arg){code}(arg2)  Self invoked
    def MemFonction(self, vars, name, parametres, openparenthesis, data):

        if not name:
            n0 = 0
            # Hack : search in global var atm
            while self.IsFunc(self.GlobalVar, 'AnonymousFunc' + str(n0)):
                n0 += 1
            name = 'AnonymousFunc' + str(n0)

        if self.SpecialOption:
            if self.SpecialOption.split('=')[0] == 'Namefunc':
                name = self.SpecialOption.split('=')[1]
            self.SpecialOption = ''

        param = MySplit(parametres, ',', True)

        if DEBUG:
            out('Extract function :' + name + ' ' + str(param))
            # out('data ' + str(data))

        replac = ''

        while not data[0] == '{':
            data = data[1:]

        content = GetItemAlone(data, '}')[1:-1]
        pos2 = len(content) + 2

        fm = fonction(name, param, content.lstrip())

        self.SetVar(vars, name, fm)

        # Hack, memorise it in global var too
        self.SetVar(self.GlobalVar, name, fm)

        data = data[pos2:]

        if openparenthesis:
            c, p = GetNextUsefullchar(data)
            if c == ')':
                data = data[(p+1):]
                openparenthesis = False

        selfinvoked = False
        if len(data) > 0:
            if data[0] == '(':
                selfinvoked = True

        # self invoked ?
        if selfinvoked:
            paraminvoked = GetItemAlone(data, ')')
            out("Self invoked " + str(paraminvoked))
            replac = name + paraminvoked

            data = data[(len(paraminvoked)):]

            if openparenthesis:
                c, p = GetNextUsefullchar(data)
                if c == ')':
                    data = data[(p+1):]
                    openparenthesis = False

        replac = replac + data

        return replac, 0, name

    def Parse(self, JScode, vars, allow_recursion=MAX_RECURSION):

        if allow_recursion < 0:
            raise Exception('Recursion limit reached')

        allow_recursion -= 1

        # ************************
        #    Post traitement
        # ************************

        # Need all functions first, because they can be called first and be at the bottom of the code
        # So we extract all functions first, and replace them by a simple call in the code, if they are self invoked

        # Make this part only if needed
        if 'function' in JScode:

            posG = 0
            Startoff = 0
            Endoff = 0

            while True:

                # out('before ' + JScode[posG:] + '\n')

                chain, pos = self.ExtractFirstchain(JScode[posG:])
                if not chain:
                    break

                # out('after ' + chain + '\n')

                Startoff = posG
                Endoff = posG + pos + 1
                posG = Endoff

                # skip empty char
                chain = chain.strip()

                # out('/////////////////')
                # out('> ' + chain)
                # out('/////////////////')

                # fonction
                m = re.search(r'^(\()* *function(?: ([\w]+))* *\(([^\)]*)\) *{', chain, re.DOTALL)
                if m:
                    name = ''
                    openparenthesis = False
                    if m.group(2):
                        name = m.group(2)
                    if m.group(1):
                        openparenthesis = True

                    replac, pos3, xyz = self.MemFonction(vars, name, m.group(3), openparenthesis, chain)

                    JScode = JScode[:Startoff]+ replac + JScode[Endoff:]

                    posG = Startoff + len(replac)

        # ***********************
        # The real Parser
        # **********************

        Parser_return = None

        while True:

            if self.continu:
                break

            chain, pos = self.ExtractFirstchain(JScode)
            if not chain:
                break

            JScode = JScode[(pos+1):]

            chain = chain.lstrip().rstrip()

            # empty ?
            if chain == ';':
                continue

            if DEBUG:
                out('D++++++++++++++++++')
                out(chain.encode('ascii', 'replace'))
                out('F++++++++++++++++++')

            # useless code
            if chain.startswith('const '):
                chain = chain[6:]

            # hackVars ?
            m = re.search(r'^\$\("#([^"]+)"\)\.text\(([^\)]+)\);', chain)
            if m:
                if DEBUG:
                    out('> hack ' + m.group(0) + ' , variable est ' + m.group(1))
                self.SetVar(self.HackVars, m.group(1), self.GetVar(vars, m.group(2)))
                continue

            # break
            if chain.startswith('break'):
                self.Break = True
                return

            # continue
            if chain.startswith('continue'):
                self.continu = True
                return

            # Return ?
            if chain.startswith('return'):
                m = re.match(r'return *;', chain)
                if m:
                    self.Return = True
                    self.ReturnValue = None
                    return None
                m = re.match(r'^return *([^;]+)', chain)
                if m:
                    chain = m.group(1)
                    r = self.evalJS(chain, vars, allow_recursion)

                    self.Return = True
                    self.ReturnValue = r

                    return self.ReturnValue

            # Variable creation/modification ?
            # m = re.search(r'^\({0,1}([\w\.]+)\){0,1}(?:\[([^\]]+)\])*\){0,1}\s*(?:[\^\/\*\-\+])*=', chain, re.DOTALL | re.UNICODE)
            # m2 = re.search(r'^\({0,1}([\w\.]+)\){0,1}(?:\.([\w]+))*\){0,1}\s*(?:[\^\/\*\-\+])*=', chain, re.DOTALL | re.UNICODE)
            if chain.startswith('var ') or chain.startswith('let '):
                out('var/let')

                chain = chain[4:]

                # Now need to extract all vars from chain
                while chain:
                    v1 = GetItemAlone(chain, ',').strip()
                    chain = chain[(len(v1) + 1):]
                    if v1.endswith(',') or v1.endswith(';'):
                        v1 = v1[:-1]
                    # HACK in case of creation
                    if '=' not in v1:
                        v1 = v1 + '=0'
                    self.evalJS(v1, vars, allow_recursion)
                continue

            # Extraction info
            # Problem, catch fonction too :(
            m = re.search(r'^([\w]+) *(\(|\{)', chain, re.DOTALL)
            # Syntax > aaaaa(bbbbb) .........
            if m:
                name = m.group(1)
                sp = m.group(2)
                if sp == '(':
                    arg = GetItemAlone(chain[(m.end()-1):], ')')[1:-1]
                    pos3 = len(arg) + 1
                    code = chain[(m.end() + pos3):]
                elif sp == '{':
                    arg = ''
                    code = chain[(m.end()-1):]
                else:
                    raise Exception('> Er 74')

                if DEBUG:
                    out('DEBUG > Name: ' + name + ' arg: ' + arg + ' code: ' + code + '\n')

                # Jquery
                if name == 'DOCUMENT_READY':
                    if DEBUG:
                        out('DOCUMENT_READY ' + arg)
                    self.SpecialOption = 'Namefunc=DR'
                    self.Parse(arg, vars, allow_recursion)

                    # It's not the correct place to do that, but for the moment ...
                    self.Parse('DR();', vars, allow_recursion)

                    continue

                # For boucle ?
                if name == 'for':
                    arg = arg.split(';')
                    v = arg[0] + ';'
                    t = arg[1]
                    i = arg[2] + ';'
                    f = code
                    if GetNextUsefullchar(f)[0] == '{':
                        f = GetItemAlone(f, '}')[1:-1]

                    # out('> Boucle for : Var=' + v + ' test=' + t + ' incrementation=' + i + ' code=' + f)

                    # init var
                    self.Parse(v, vars, allow_recursion)
                    # loop
                    while self.CheckTrueFalse(self.evalJS(t, vars, allow_recursion)):
                        # fonction
                        self.Parse(f, vars, allow_recursion)
                        if self.Break:
                            self.Break = False
                            break
                        # incrementation
                        self.Parse(i, vars, allow_recursion)

                    continue

                # boucle while ?
                if name == 'while':
                    f = code
                    if GetNextUsefullchar(f)[0] == '{':
                        f = GetItemAlone(f, '}')[1:-1]

                    # out('> Boucle while : Var=' + v + ' test=' + t + ' incrementation=' + i + ' code=' + f)

                    # loop
                    while self.CheckTrueFalse(self.evalJS(arg, vars, allow_recursion)):
                        # fonction
                        self.Parse(f, vars, allow_recursion)
                        if self.Break:
                            self.Break = False
                            break

                        if self.continu:
                            self.continu = False

                    continue

                # boucle do/while
                if name == 'do':
                    f = code
                    e = ''
                    if sp == '{':
                        f = GetItemAlone(f, '}')

                    if f.startswith('{'):
                        f = f[1:-1]

                    # Need to check the while part ?
                    chain2, pos2 = self.ExtractFirstchain(JScode)
                    if 'while' in chain2:
                        chain2 = chain2.lstrip()
                        JScode = JScode[(pos2 + 1):]
                        m2 = re.search(r'while\s*\((.+?)\);$', chain2, re.DOTALL)
                        if m2:
                            e = m2.group(1)

                    if not e:
                        raise Exception('> While error')

                    out('> Boucle do/while : test :' + e + ' code: ' + f)

                    # loop
                    # 1 forced execution because do/while
                    self.Parse(f, vars, allow_recursion)
                    if self.Break:
                        self.Break = False
                        continue  # stop all

                    if self.continu:
                        self.continu = False
                    # and now the loop
                    while self.CheckTrueFalse(self.evalJS(e, vars, allow_recursion)):
                        # fonction
                        self.Parse(f, vars, allow_recursion)
                        if self.Break:
                            self.Break = False
                            break

                        if self.continu:
                            self.continu = False

                    continue
                # boucle switch
                if name == 'switch':
                    v = self.evalJS(arg, vars, allow_recursion)
                    f = code[1:]

                    if f[-1:] == '}':
                        f = f[:-1]

                    if v == 'undefined':
                        continue

                    # out('> Boucle switch : Case=' + v + ' code= ' + f[0:50] + '\n')
                    # logwrite(str(v) + '\n')

                    out('Switch case ' + str(v))

                    # Search the good case code
                    StrToSearch = "case'%s':" % (str(v))

                    while (not f.startswith(StrToSearch)) and (len(f) > 0):
                        tmp_str = GetItemAlone(f, ';}')
                        f = f[(len(tmp_str)+1):]

                    if len(f) < 1:
                        raise Exception("Can't find switch value " + str(v))

                    f = f[(len(StrToSearch)):]

                    # out('\n> New block : ' + f)

                    self.Parse(f, vars, allow_recursion)

                    continue

                # Boucle if
                if name == 'if':
                    t = arg
                    f = code
                    e = ''

                    if GetNextUsefullchar(f)[0] == '{':
                        f = GetItemAlone(f, '}')[1:-1]

                    # Need to check if there is else statement ?
                    chain2, pos2 = self.ExtractFirstchain(JScode)
                    if 'else' in chain2:
                        chain2 = chain2.lstrip()
                        JScode = JScode[(pos2 + 1):]
                        m2 = re.search(r'else\s*{(.+?)}$', chain2, re.DOTALL)
                        if m2:
                            e = m2.group(1)

                    # out('> Boucle if : test=' + arg + ' code=' + f + ' else=' + e)

                    # hack, need to memorise working test in future
                    if self.option_ForceTest:
                        try:
                            ttt = self.CheckTrueFalse(self.evalJS(t, vars, allow_recursion))
                        except:
                            from random import choice
                            ttt = choice([True, False])

                        if ttt:
                            self.Parse(f, vars, allow_recursion)
                        elif e:
                            self.Parse(e, vars, allow_recursion)
                        continue
                    # normal way
                    else:
                        if self.CheckTrueFalse(self.evalJS(t, vars, allow_recursion)):
                            self.Parse(f, vars, allow_recursion)
                        elif e:
                            self.Parse(e, vars, allow_recursion)
                        continue

                if name == 'with':
                    f = code
                    if GetNextUsefullchar(f)[0] == '{':
                        f = GetItemAlone(f, '}')

                    # list all arg membre.
                    member_list = self.GetVar(vars, arg)

                    out('> With fonction : exp=' + arg + ' values=' + str(member_list))
                    # print('Before: ' + f)

                    # print(member_list)

                    def sub(g):
                        g = g.group()
                        return g[0] + arg + '["' + g[1:-1] + '"]' + g[-1:]

                    # Hack again
                    if type(member_list) in [type]:
                        for i in member_list.__dict__:
                            f = re.sub(r'[^\w]' + str(i) + '[^\w]', sub, f, re.DOTALL)
                    else:
                        for i in member_list:
                            f = re.sub(r'[^\w]' + i + '[^\w]', sub, f, re.DOTALL)

                    # print('after: ' + f)

                    self.Parse(f[1:-1], vars, allow_recursion)
                    # JScode = f[1:-1] + ';' + JScode
                    continue

                if name == 'try':

                    f = code
                    if GetNextUsefullchar(f)[0] == '{':
                        f = GetItemAlone(f, '}')

                    chain2, pos2 = self.ExtractFirstchain(JScode)

                    chain2 = chain2.lstrip()
                    JScode = JScode[(pos2 + 1):]
                    m2 = re.search(r'catch\s*\(([^\)]+)\)\s*{(.+?)}', chain2, re.DOTALL)
                    if m2:
                        a = m2.group(1)
                        b = m2.group(2)
                    else:
                        raise Exception('> ERROR : catch not found , try loop')

                    out('> Try fonction : Block try=' + f + ' block catch=' + b)

                    # For the moment just execute the catch part
                    self.Parse(b, vars, allow_recursion)
                    continue

            # Pas trouve, une fonction ?
            if chain.endswith(';'):
                Parser_return = self.evalJS(chain[:-1], vars, allow_recursion)
                # hack
                # if 'return "ok"' in str(Parser_return):
                #     JScode = str(Parser_return)
                #     continue

            # hack, need to be reenabled
            # Non gere encore
            if not chain.endswith(';'):
                print('> ' + JScode)
                raise Exception('> ERROR : can t parse >' + chain)

        return Parser_return

    def ProcessJS(self, JScode, vars=[]):

        # unicode ?
        # if isinstance(JScode, unicode):
        if False:
            out('Unicode convertion')
            JScode = unicode(JScode, "utf-8")

        # Special Vars
        # libs
        self.SystemVars.append(('Math', Math))
        # hack
        self.SystemVars.append(('String', ''))
        self.SystemVars.append(('undefined', None))
        # DOM
        self.SystemVars.append(('document', {'write': 'ok'}))
        self.SystemVars.append(('window', 'XXX'))

        # Hack
        JScode = JScode.replace('$(document).ready', 'DOCUMENT_READY')

        # Make global var
        self.GlobalVar = vars

        # Start the parsing
        ret = self.Parse(JScode, vars)

        return ret


# ---------------------------------------------------------------------------------------------------------------------
# fonctions
#

def toStr(str):
    def decorator(f):
        class _temp:
            def __call__(self, *args, **kwargs):
                return f(self.real_self, *args, **kwargs)

            def __str__(self):
                return str % f.__name__
        return _temp()
    return decorator


class Math(object):
    def __init__(self, initV1, initV2):
        pass

    def max(self, arg):
        t1 = arg[0]
        t2 = arg[1]
        return max(t1, t2)

    def min(self, arg):
        t1 = arg[0]
        t2 = arg[1]
        return min(t1, t2)

    def abs(self, arg):
        return abs(arg[0])

    def pow(self, arg):
        t1 = arg[0]
        t2 = arg[1]
        return pow(t1, t2)

    def floor(self, arg):
        return int(math.floor(arg[0]))

    @toStr("function %s() {\n    [native code]\n}")
    def sin(self, arg):
        return math.sin(arg[0])

    @toStr("function %s() {\n    [native code]\n}")
    def atan(self, arg):
        return math.atan(arg[0])

    def __contains__(self, arg):
        if arg in ['max', 'min', 'abs', 'pow', 'sin', 'atan']:
            return True
        return False


class String(object):
    def __init__(self, initV1, initV2=''):
        self._JSParser = initV1
        self._string = initV2

    def Get(self):
        return self._string

    def charCodeAt(self, arg):
        v = arg[0]
        return ord(self._string[int(v)])

    def length(self, arg):
        return len(self._string)

    def reverse(self, arg):
        return self._string[::-1]

    def substring(self, arg):
        p1 = arg[0]
        if len(arg) > 1:
            p2 = arg[1]
            return self._string[int(p1): int(p2)]
        else:
            return self._string[int(p1):]

    def replace(self, arg):
        t1 = arg[0]
        t2 = arg[1]

        # if not t1.startswith('/'):
        #     t1 = self.evalJS(t1, vars, allow_recursion)

        # regex mode ? HACK
        if t1.startswith('/'):
            jr = re.findall(t1.split('/')[1], self._string)

            for k in jr:
                if not self._JSParser.IsFunc(self._JSParser.FastEval_vars, t2):
                    self._string = self._string.replace(k, t2)
                    if DEBUG:
                        out('Replace (F) ' + str(k) + " by " + str(t2))
                else:
                    v = self._JSParser.Fast_Eval(t2 + '(' + k + ')')
                    v = str(v)
                    self._string = self._string.replace(k, v)
                    if DEBUG:
                        out('Replace ' + str(k) + " by " + str(v))
        # String mode
        else:
            # t1 = self.evalJS(t1, vars, func, allow_recursion)
            self._string = s.replace(t1, t2)
        return self._string

    def fromCharCode(self, arg):
        # HACK
        # a = chr(int(arg[0]))
        b = ''.join(map(unichr, arg))
        try:
            return str(b)
        except:
            return b

    def substr(self, arg):
        # self._string = unicode(self._string)
        if len(arg) > 1:
            length = int(arg[1])
            if (arg[0] + length) > 0:
                return self._string[arg[0]:arg[0] + length]
        return self._string[arg[0]:]

    def split(self, arg):
        arg = arg[0].replace('"', '').replace("'", "")
        if arg == '':
            return list(self._string)
        else:
            return self._string.split(arg)

    def indexOf(self, arg):
        start = 0
        if len(arg) > 1:
            start = int(arg[1])
        return self._string.find(arg[0], start)

    def charAt(self, arg):
        p = int(arg[0])
        return self._string[p]


class Array(object):
    def __init__(self, initV1, initV2=[]):
        self._JSParser = initV1
        self._array = initV2

    def Get(self):
        return self._array

    def join(self, arg):
        t = arg[0].replace('"', '').replace("'", "")
        return t.join(self._array)

    def push(self, arg):
        t1 = arg[0]
        if len(arg) > 1:
            # use s.extend-[array]);
            raise Exception("Not implemented - push")
        self._array.append(t1)

        v = len(self._array)
        return v

    def slice(self, arg):
        p1 = arg[0]
        if len(arg) > 1:
            p2 = arg[1]
            sr = self._array[int(p1):int(p2)]
        else:
            sr = self._array[int(p1):]
        # sr = '"' + sr + '"'
        return sr

    def splice(self, arg):
        t1 = arg[0]
        t2 = arg[1]
        if len(arg) > 2:
            raise Exception("Not implemented - splice")
        tab = self._array[:t1] + self._array[(t1 + t2):]
        tabsup = self._array[t1:(t1 + t2)]

        self._array = tab
        return tabsup

    def shift(self, arg):
        if len(self._array) == 0:
            return None
        return self._array.pop(0)

    def map(self, arg):

        tab = []

        self._JSParser.PrintVar(self._JSParser.FastEval_vars)

        fe = self._JSParser.IsFunc(self._JSParser.FastEval_vars, arg[0])

        for i in self._array:
            v = [(fe.param[0], i)]
            vv = self._JSParser.Parse(fe.code, v, 100)

            tab.append(vv)

        return tab


class Basic(object):
    def __init__(self, initV1, initV2):
        self._JSParser = initV1
        self._name = initV2
        pass

    def Setting(self, vars):
        self._vars = vars

    def parseInt(self, arg):
        t1 = arg[0]
        if len(arg) > 1:
            t2 = arg[1]
        else:
            t2 = 10
        if t1 == '':
            return None
        r = int(str(t1), int(t2))
        return r

    def typeof(self, arg):
        return type(arg)

    def debug(self, arg):
        self._JSParser.PrintVar(self._JSParser.FastEval_vars)
        r = ''
        if len(arg) > 0:
            r = arg[0]
        raise Exception("DEBUG : " + r)
        return

    def eval(self, arg):
        if DEBUG:
            out('To eval >' + arg)
        r = self._JSParser.Parse(RemoveGuil(arg), self._JSParser.FastEval_vars, self._JSParser.FastEval_recur)
        return r

    def Array(self, arg):
        if arg[0]:
            if isinstance(arg[0], (int, long)):
                return []
            return arg
        return []

    def alert(self, arg):
        # t1 = self.evalJS(arg, vars, allow_recursion)
        # logwrite(str(arg))
        print('------------ALERT-------------------')
        print(arg)
        print('------------------------------------')
        return ''

    def RegExp(self, arg):
        t1 = RemoveGuil(arg[0])
        t2 = RemoveGuil(arg[1])
        return '/' + t1 + '/' + t2

    # this function is for object normally
    def toString(self, arg):
        t1 = arg[0]
        v = self._name

        if t1 == 16:
            v = hex(int(self._name))[2:].replace('L', '')

        if isinstance(self._name, (int, long)):
            return str(v)
        elif isinstance(self._name, types.StringTypes):
            return str(v)

        try:
            f = self._name.im_func.__name__
        except:
            f = "HACK'"
        t = "function %s() {\n    [native code]\n}" % f
        return t

    def String(self, arg):
        return str(arg[0])

    def atob(self, arg):
        import base64
        return base64.b64decode(arg[0])

    def decodeURIComponent(self, arg):
        # Python 3
        # from urllib.parse import unquote
        # return unquote(arg[0])

        # Python 3
        from resources.lib.util import Unquote
        return Unquote(arg[0]).decode('utf8')


List_Lib = [Basic, Array, String, Math]
