###
# Modern Albufeira Prolog Interpreter
#
# Warranty & Liability
# To the extent permitted by applicable law and unless explicitly
# otherwise agreed upon, XLOG Technologies AG makes no warranties
# regarding the provided information. XLOG Technologies AG assumes
# no liability that any problems might be solved with the information
# provided by XLOG Technologies AG.
#
# Rights & License
# All industrial property rights regarding the information - copyright
# and patent rights in particular - are the sole property of XLOG
# Technologies AG. If the company was not the originator of some
# excerpts, XLOG Technologies AG has at least obtained the right to
# reproduce, change and translate the information.
#
# Reproduction is restricted to the whole unaltered document. Reproduction
# of the information is only allowed for non-commercial uses. Selling,
# giving away or letting of the execution of the library is prohibited.
# The library can be distributed as part of your applications and libraries
# for execution provided this comment remains unchanged.
#
# Restrictions
# Only to be distributed with programs that add significant and primary
# functionality to the library. Not to be distributed with additional
# software intended to replace any components of the library.
#
# Trademarks
# Jekejeke is a registered trademark of XLOG Technologies AG.
##

import time
import gc
from nova.core import (add, make_check, get_gc_time,
     exec_unify, real_time, get_gc_enter, get_gc_maxinfs,
     gc_major, size_peek,
     exec_build, check_provable, is_logical, is_stick)


#####################################################################
# File Access                                                       #
#####################################################################

###
# sys_stat_map(M): internal only
# The built-in succeeds in W with the statistics map.
##
def test_sys_stat_map(args):
    res = {}
    res["wall"] = round(time.time() * 1000)
    res["time"] = real_time()
    res["maxinfs"] = get_gc_maxinfs()
    res["calls"] = get_gc_enter()
    res["gctime"] = get_gc_time()
    res["used"] = 0
    return exec_unify(args[0], res)


###
# garbage_collect: internal only
# The built-in succeeds in attempting a garbage colection.
##
def test_garbage_collect(args):
    gc_major()
    gc.collect()
    return True


#####################################################################
# Index Statistics                                                  #
#####################################################################

###
# kb_link_stat_has(Q): internal only
# The built-in succeeds if the provable Q has index statistics.
##
def test_kb_link_stat_has(args):
    alpha = exec_build(args[0])
    check_provable(alpha)
    if is_logical(alpha.func) or is_stick(alpha.func):
        return stats_has(alpha.func)
    return False


def stats_has(peek):
    if is_stick(peek):
        i = 0
        while i < len(peek.maps):
            temp = peek.maps[i]
            if temp is NotImplemented or len(temp) == 0:
                i += 1
                continue
            break
        if not i < len(peek.maps):
            return False
        return True
    else:
        return False


###
# kb_link_stat_get(Q, M): internal only
# The built-in succeeds in M with the index statistics of the provable Q.
##
def test_kb_link_stat_get(args):
    alpha = exec_build(args[0])
    check_provable(alpha)
    res = {}
    if is_logical(alpha.func) or is_stick(alpha.func):
        stats_get(alpha.func, "", 0, res)
    return exec_unify(args[1], res)


def stats_get(peek, path, offset, res):
    if is_stick(peek):
        i = 0
        while i < len(peek.maps):
            temp = peek.maps[i]
            if temp is NotImplemented or len(temp) == 0:
                i += 1
                continue
            path2 = str(i+offset+1)
            if "" != path:
                path2 = path + "+" + path2
            stats_add(path2, len(temp), res)
            for key, val in temp.items():
                stats_get(val, path2, i+offset+1, res)
            stats_get(peek.guards[i], path2, i+offset+1, res)
            i += 1


def stats_add(path, delta, res):
    size = res.get(path, NotImplemented)
    if size is not NotImplemented:
        delta += size
    res[path] = delta


#####################################################################
# Bit Lib Init                                                      #
#####################################################################

def main():
    add("sys_stat_map", 1, make_check(test_sys_stat_map))
    add("garbage_collect", 0, make_check(test_garbage_collect))
    add("kb_link_stat_has", 1, make_check(test_kb_link_stat_has))
    add("kb_link_stat_get", 2, make_check(test_kb_link_stat_get))