#! /usr/bin/env python

import re

from lab.parser import Parser

# ------------------- HELPER FUNCTIONS ---------------------- 

def abs_if_negative(props, key):
    if props[key] < 0:
        props[key] = -1

def error(content, props):
    if props['planner_exit_code'] == 0:
        props['error'] = 'plan-found'
    else:
        props['error'] = 'unsolvable-or-error'


def get_plan(content, props):
    # All patterns are parsed before functions are called.
    if props.get('evaluations') is not None:
        props['plan'] = re.findall(r'^(?:step)?\s*\d+: (.+)$', content, re.M)


def get_times(content, props):
    props['times'] = re.findall(r'(\d+\.\d+) seconds', content, re.M)


def get_int_default(content, props, key, regex, default):
    try:
        props[key] = int(re.findall(regex, content, re.M)[0])
    except IndexError:
        props[key] = default;

def get_int(content, props, key, regex):
    get_int_default(content, props, key, regex, -1)

def get_int_if(content, props, key, regex):
    if props[key] == -1:
        get_int(content,props,key,regex)
    
def get_float(content, props, key, regex):
    try:
        props[key] = (float)(re.findall(regex, content, re.M)[0])
    except IndexError:
        props[key] = -1;

def get_str(content, props, key, regex):
    try:
        props[key] = (str)(re.findall(regex, content, re.M)[0])
    except IndexError:
        props[key] = '-'

def get_ratio(content, props, key, divident, divisor):
    if props[divident] <= 0 or props[divisor] <= 0:
        props[key] = -1
    else:
        props[key] = (float)(props[divident])/props[divisor]
    
def get_sum(content, props, key, summand, summand2):
    props[key] = props[summand] + props[summand2]
    abs_if_negative(props, key)
    

print 'Running NBS parser'
parser = Parser()

# ------------------- Adding Variables ----------------------

# Miscellaneous
parser.add_pattern(
    'planner_exit_code', r'^.*run-planner exit code: (.+)$', type=int, file='driver.log')

# Expanded
parser.add_function(lambda x,y : get_int(x,y,'expanded',r'^Expanded (\d+) state\(s\)\.$')) 
parser.add_function(lambda x,y : get_int(x,y,'f_expanded',r'F_Expanded (\d+)')) 
parser.add_function(lambda x,y : get_int(x,y,'b_expanded',r'B_Expanded (\d+)')) 
parser.add_function(lambda x,y : get_int_default(x,y,'f_jump_expanded',r'F_Expanded until last jump: (\d+)',0))
parser.add_function(lambda x,y : get_int_default(x,y,'b_jump_expanded',r'B_Expanded until last jump: (\d+)',0))
parser.add_function(lambda x,y : get_sum(x,y,'jump_expanded','f_jump_expanded','b_jump_expanded'))
parser.add_function(lambda x,y : get_int_if(x,y,'jump_expanded',r'Expanded until last jump: (\d+)'))
parser.add_function(lambda x,y : get_ratio(x,y,'ratio_jump_expanded','jump_expanded','expanded')) 

# Evaluated
parser.add_function(lambda x,y : get_int(x,y,'evaluated',r'^Evaluated (\d+)')) 
parser.add_function(lambda x,y : get_int(x,y,'f_evaluated',r'F_Evaluated (\d+)')) 
parser.add_function(lambda x,y : get_int(x,y,'b_evaluated',r'B_Evaluated (\d+)')) 
parser.add_function(lambda x,y : get_int_default(x,y,'f_jump_evaluated',r'F_Evaluated until last jump: (\d+)',0))
parser.add_function(lambda x,y : get_int_default(x,y,'b_jump_evaluated',r'B_Evaluated until last jump: (\d+)',0))
parser.add_function(lambda x,y : get_sum(x,y,'jump_evaluated','f_jump_evaluated','b_jump_evaluated'))
parser.add_function(lambda x,y : get_ratio(x,y,'ratio_jump_evaluated','jump_evaluated','evaluated')) 

# Generated
parser.add_function(lambda x,y : get_int(x,y,'f_generated',r'F_Generated (\d+)'))
parser.add_function(lambda x,y : get_int(x,y,'b_generated',r'B_Generated (\d+)')) 
parser.add_function(lambda x,y : get_sum(x,y,'generated','b_generated','f_generated'))
parser.add_function(lambda x,y : get_int_default(x,y,'f_jump_generated',r'F_Generated until last jump: (\d+)',0))
parser.add_function(lambda x,y : get_int_default(x,y,'b_jump_generated',r'B_Generated until last jump: (\d+)',0))
parser.add_function(lambda x,y : get_sum(x,y,'jump_generated','f_jump_generated','b_jump_generated'))
parser.add_function(lambda x,y : get_ratio(x,y,'ratio_jump_generated','jump_generated','generated')) 

# Actions
parser.add_function(lambda x,y : get_int(x,y,'f_actions',r'F_Actions: (\d+)')) #
parser.add_function(lambda x,y : get_int(x,y,'b_actions',r'B_Actions: (\d+)')) #
parser.add_function(lambda x,y : get_ratio(x,y,'ratio_fb_actions', 'b_actions','f_actions'))

# Meeting
parser.add_function(lambda x,y : get_int(x,y,'frontier_meetings',r'Frontier Meetings: (\d+)')) #
parser.add_function(lambda x,y : get_int(x,y,'f_ex_before_meeting',r'F_Expansions before Meeting: (\d+)')) #
parser.add_function(lambda x,y : get_int(x,y,'b_ex_before_meeting',r'B_Expansions before Meeting: (\d+)')) #
parser.add_function(lambda x,y : get_str(x,y,'meeting_point',r'Meeting Point - (.+)$'))

#Specific Backward
parser.add_function(lambda x,y : get_int(x,y,'b_initial_goals',r'B_Initial_Goals: (\d+)')) #
parser.add_function(lambda x,y : get_int(x,y,'b_pruned',r'^B_Pruned: (\d+)')) # b_pruned

# Branching Ratio
parser.add_function(lambda x,y : get_float(x,y,'ratio_fb_branching',r'Branching Ratio: (.+)\.$')) #
parser.add_function(lambda x,y : get_float(x,y,'f_branching',r'F_Branching: (.+) generations')) #
parser.add_function(lambda x,y : get_float(x,y,'b_branching',r'B_Branching: (.+) generations')) #

# Missing
# dead_ends, reopened

# Other
#parser.add_function(lambda x,y : get_int(x,y,'',r'X: (\d+)')) #
#parser.add_function(error)
#parser.add_function(coverage)
#parser.add_function(get_plan)
#parser.add_function(get_times)
parser.parse()
