###############################################################################
# STUDENTS:  IGNORE THIS MODULE (file).
# We use it in our testing code to make error messages appear in color.
###############################################################################

###############################################################################
# The code in this module is a simplified version of code written by:
#     dablak  (https://stackoverflow.com/users/1329248/dablak)
# That code appears at:
#    http://xsnippet.org/359377/
# and is referenced in dablak's question/answer at:
#  https://stackoverflow.com/questions/20333674/pycharm-logging-output-colours.

# As with all user content to StackOverflow, it is licensed (by dablak) under:
#     CC BY-SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)
# a Creative Commons Attribution Share Alike license, as is this code.
###############################################################################

import sys
import time

PRECISION = 3  # Round floats to 3 decimal places when comparing vs expected

# Set  USE_COLORING  to False to use the "old" way of printing:
USE_COLORING = True

COLOR_CODES = {"black": 20,
               "red": 31,
               "green": 32,
               "yellow": 33,
               "blue": 34,
               "magenta": 35,
               "cyan": 36,
               "white": 37
               }


def print_function_call_of_test(arguments, test_results, format_string):
    test_number = test_results[0] + test_results[1] + 1
    print()
    print("Test {}:".format(test_number))

    print("  This test case calls:")
    print(format_string.format(*arguments))


def print_expected_result_of_test(arguments, expected, test_results,
                                  format_string, suffix=""):
    print_function_call_of_test(arguments, test_results, format_string)
    print("  Expected:", expected, suffix)


def print_actual_result_of_test(expected, actual, test_results, precision=None):
    print("  Actual:  ", actual)

    if USE_COLORING:
        print_it = print_colored
    else:
        print_it = print_uncolored

    try:
        if precision is not None:
            expected = round(expected, precision)
            actual = round(actual, precision)
        elif type(actual) is float:
            expected = round(expected, PRECISION)
            actual = round(actual, PRECISION)
        if expected == actual:
            print_it("  PASSED the above test -- good!", color="blue")
            test_results[0] = test_results[0] + 1
            return
        else:
            print_it("  *** FAILED the above test. ***", color="red")
    except Exception:
        print_it("  *** FAILED the above test. ***", color="red")
    test_results[1] = test_results[1] + 1


def print_summary_of_test_results(test_results):
    passed_tests = test_results[0]
    failed_tests = test_results[1]
    number_of_tests = failed_tests + passed_tests
    message_for_passed = "\n*** PASSED all {} tests! Good! ***"
    message_for_failed = "\n*** FAILED {} tests! ***"
    if passed_tests == number_of_tests:
        print_colored(message_for_passed.format(number_of_tests),
                      color="blue")
    else:
        print_colored(message_for_failed.format(failed_tests), color="red")


# noinspection PyUnusedLocal
def print_colored(*args, color="black", flush=True, **kwargs):
    text = ""
    for arg in args:
        text = text + " " + str(arg)
    text = text.replace(" ", "", 1)
    sys.stdout.write("\033[%sm%s\033[0m" % (COLOR_CODES[color], text))
    print(**kwargs)


def print_uncolored(*args, color=None, flush=True, **kwargs):
    if color == "red":
        print(end="", flush=flush)
        time.sleep(1)
        print(*args, file=sys.stderr, flush=flush, **kwargs)  # Stderr MIGHT be red
    else:
        print(*args, flush=flush, **kwargs)