# Safe eval of code.
#
# Copyright (C) 2014 Libor Polčák
# 
# 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/>.

# User defined types transferrable through interfaces
from ..af.hi1intercept import HI1Intercept
from .ini1aintercept import INI1AIntercept
from .cid import CID
from .iri import IRI
from ..iriiif.dhcp_status import DHCPStatus
from IPy import IP

import ast
import sys

from .liexceptions import LIException

pythonVersion = sys.version_info
if pythonVersion[0] == 3 and pythonVersion[1] >= 4:    
    allowed_ast_nodes = [
            ast.Module,
            ast.Expr, ast.Load,
            ast.Str, ast.Num,
            ast.Tuple, ast.List, ast.Dict,
            ast.Call, ast.Name, ast.NameConstant,
        ]
else:
    allowed_ast_nodes = [
            ast.Module,
            ast.Expr, ast.Load,
            ast.Str, ast.Num,
            ast.Tuple, ast.List, ast.Dict,
            ast.Call, ast.Name,
        ]
    

    



allowed_calls = [
        "HI1Intercept",
        "INI1AIntercept",
        "CID",
        "IRI",
        "CCTable",
        "DHCPStatus",
        "IP",
    ]

allowed_constants = [
        "True",
        "False",
    ]

def is_harmful_call(call_node):
    name = call_node.func
    return name.id not in allowed_calls

def is_harmful_name(node):
    return not (node.id in allowed_calls or node.id in allowed_constants)

additional_check = {
        ast.Call: is_harmful_call,
        ast.Name: is_harmful_name,
    }

def lieval(msg):
    atree = ast.parse(msg)
    for node in ast.walk(atree):
        if (node.__class__ not in allowed_ast_nodes or ( \
                node.__class__ in additional_check and \
                additional_check[node.__class__](node))):
            raise LIException("lieval: cannot evaluate %s" % node.__class__)
    return eval(msg)

