#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys, os
import logging

import unittest
import getopt

from time import time

import operator

def usage():
    print """Unit-testing for the LAAS-CNRS 'Dialogs' module.

All these tests require the ontology server (ORO) running on localhost:6969 and
loaded with commonsense.oro.owl.

Usage:
dialogs_test [OPTIONS] TEST_SUITE
  -h, --help               Displays this message and exits
  -f, --failfast           Stops at first failure or error
  -d, --debug              Verbose output for interactions with knowledge base
  --embedded               Run with an embedded knowledge base (requires MinimalKB)
  -l, --log=[file|stdout]  Where to log: file (in """ + LOG_FILENAME + """) 
                           or stdout (default).
  
  Available test suites (you call several of them):
  
  === Base testing ===
   
  sentence          Tests the sentence creation and merging functions
  parser            Tests the parser
  verbalization     Tests the verbalization module
  statements        First round of simple tests that produces statements
  discrimination    Tests the discrimination code 
  questions         Tests the question handler
  
  all               Runs all base test suites
  
  
  === Complete scenario testing ===
  These scripts test complete interactions, from past HRI scenarii
  
  sc_moving         Scenario "Achille is moving to London"
  
  all_scenarii      Runs all the scenarii
"""


# Add the "examples" directory the the Python path.
EXAMPLES_DIR = os.path.abspath(__file__).split('/bin')[0].split('/scripts')[0] + '/share/examples/dialogs'
sys.path.append(EXAMPLES_DIR)

LOG_FILENAME = "dialog_test.log"

#Set the loggers
logger = logging.getLogger('dialogs')
logger.setLevel(logging.DEBUG)

kb_logger = logging.getLogger('kb')

if len(sys.argv[1:]) == 0:
    usage()
    sys.exit(0)

log_handler = logging.StreamHandler()
formatter = logging.Formatter("%(message)s")

failfast = False
embedded = False
verbosekb = False

try:
    optlist, args = getopt.getopt(sys.argv[1:], 'hfdl:', ['help', 'failfast', 'debug', 'embedded', 'log='])
except getopt.GetoptError, err:
    # print help information and exit:
    print str(err) # will print something like "option -a not recognized"
    usage()
    sys.exit(2)

for o, a in optlist:
    if o in ("-h", "--help"):
        usage()
        sys.exit(0)
    if o in ("-f", "--failfast"):
        print("Failfast mode enabled.")
        failfast = True
    elif o in ("-d", "--debug"):
        verbosekb = True
    elif o in ("--embedded"):
        print("Using embedded knowledge base.")
        embedded = True
    elif o in ("-l", "--log"):
        if a == "file":
            print("The output of the unit-tests will be saved in " + LOG_FILENAME)
            log_handler = logging.FileHandler(LOG_FILENAME)
    else:
        print "Unhandled option " + o
        usage()
        sys.exit(2)

# add formatter to log_handler
log_handler.setFormatter(formatter)
# add log_handler to logger
logger.addHandler(log_handler)
kb_logger.addHandler(log_handler)

if verbosekb:
    kb_logger.setLevel(logging.DEBUG)
else:
    kb_logger.setLevel(logging.WARN)

if embedded:
    minimalkb_logger = logging.getLogger('minimalKB')
    if verbosekb:
        minimalkb_logger.setLevel(logging.DEBUG)
    else:
        minimalkb_logger.setLevel(logging.WARN)

    minimalkb_logger.addHandler(log_handler)


# Loggers are configured. We can load the resources (including the
# ontology).
from dialogs.resources_manager import ResourcePool


#default for ORO_SERVER
ORO_HOST = 'localhost'
ORO_PORT = 6969

# Do all resource management: loading word dictionaries, connecting to
# the ontology server...
ResourcePool().init(ORO_HOST, ORO_PORT, embeddedkb = embedded)

#Import unit-tests
import dialogs.verbalization.verbalization_test as verbalization
import dialogs.parsing.parser_test as parser
import dialogs.sentence_test as sentence
import dialogs.interpretation.discrimination_test as discrimination
import dialogs.interpretation.statements_builder_test as statements_builder
import dialogs.interpretation.questions_handler_test as questions_handler

#Complete scenarii
#import scenario_moving


def check_results(res, expected):
    def check_triplets(tr , te):
        tr_split = tr.split()
        te_split = te.split()
        
        return (tr_split[0] == te_split[0] or te_split[0] == '*') and\
                (tr_split[1] == te_split[1]) and\
                (tr_split[2] == te_split[2] or te_split[2] == '*')       
    while res:
        r = res.pop()
        for e in expected:
            if check_triplets(r, e):
                expected.remove(e)
    return expected == res

def getTestRunner(failsafe, verbosity = 2):
    if sys.version_info >= (2,7,0):
        return unittest.TextTestRunner(verbosity=2, failfast = failfast)
    else:
        if failsafe:
            print ("Running Python < 2.7. Failsafe mode not possible.")
        #failsafe not handled
        return unittest.TextTestRunner(verbosity=2)

results = {}

starttime = time()

if 'parser' in args or 'all' in args:
    suite = parser.test_suite()
    result = getTestRunner(failfast).run(suite)
    results['parser'] = (suite.countTestCases(), result.testsRun, len(result.failures) , len(result.errors), result.testsRun - len(result.failures) - len(result.errors))

if 'sentence' in args or 'all' in args:
    suite = sentence.test_suite()
    result = getTestRunner(failfast).run(suite)
    results['sentence'] = (suite.countTestCases(), result.testsRun, len(result.failures) , len(result.errors), result.testsRun - len(result.failures) - len(result.errors))

if 'verbalization' in args or 'all' in args:
    suite = verbalization.test_suite()
    result = getTestRunner(failfast).run(suite)
    results['verbalization'] = (suite.countTestCases(), result.testsRun, len(result.failures) , len(result.errors), result.testsRun - len(result.failures) - len(result.errors))

if 'statements' in args or 'all' in args:
    suite = statements_builder.test_suite()
    result = getTestRunner(failfast).run(suite)
    results['statements'] = (suite.countTestCases(), result.testsRun, len(result.failures) , len(result.errors), result.testsRun - len(result.failures) - len(result.errors))
    
if 'discrimination' in args or 'all' in args:
    suite = discrimination.test_suite()
    result = getTestRunner(failfast).run(suite)
    results['discrimination'] = (suite.countTestCases(), result.testsRun, len(result.failures) , len(result.errors), result.testsRun - len(result.failures) - len(result.errors))
    
if 'questions' in args or 'all' in args:
    suite = questions_handler.test_suite()

    result = getTestRunner(failfast).run(suite)
    results['questions'] = (suite.countTestCases(), result.testsRun, len(result.failures) , len(result.errors), result.testsRun - len(result.failures) - len(result.errors))

if 'sc_moving' in args or 'all_scenarii' in args:
    suite = scenario_moving.test_suite()
    result = getTestRunner(failfast).run(suite)
    results['scenario: moving'] = (suite.countTestCases(), result.testsRun, len(result.failures) , len(result.errors), result.testsRun - len(result.failures) - len(result.errors))

total = (0,0,0,0,0)
total_ok = 0
print("\n\n======================================================================")
print("| suite            | nb tests | tests run | failures | errors ||  OK |")
print("|--------------------------------------------------------------------|")
for name in results:
    total = map(operator.add, total, results[name])
    print(  "| " + name + (" "* (17 - len(name))) + \
            "|   % 3d    |    % 3d    |   % 3d    |  % 3d   || % 3d |" % (results[name]))
    print("|--------------------------------------------------------------------|")
    
print("| TOTAL            |  % 4d    |   % 4d    |   % 3d    |  % 3d   || % 3d |" % (tuple(total)))
print("======================================================================")
print("\nTotal time: %fsec" % (time() - starttime))

ResourcePool().close()
