import json
import sys
from optparse import OptionParser

from ..src import pg_logger

# To make regression tests work consistently across platforms,
# standardize display of floats to 3 significant figures
#
# Trick from:
# http://stackoverflow.com/questions/1447287/format-floats-with-standard-json-module
json.encoder.FLOAT_REPR = lambda f: ('%.3f' % f)


def json_finalizer(input_code, output_trace):
    ret = dict(code=input_code, trace=output_trace)
    # sort_keys=True leads to printing in DETERMINISTIC order, but might
    # screw up some old tests ... however, there is STILL non-determinism
    # in Python 3.3 tests, ugh!
    #
    # TODO: for Python 3.6, think about reinstating sort_keys=True as a
    # command-line option for tests only? maybe don't activate it for reals
    # since that might falsely give users the impression that object/dict keys
    # are always sorted
    json_output = json.dumps(ret, indent=INDENT_LEVEL)
    return json_output


def js_var_finalizer(input_code, output_trace):
    global JS_VARNAME
    ret = dict(code=input_code, trace=output_trace)
    json_output = json.dumps(ret, indent=None)
    return "var %s = %s;" % (JS_VARNAME, json_output)


parser = OptionParser(usage="Generate JSON trace for pytutor")
parser.add_option('-c', '--cumulative', default=False, action='store_true',
                  help='output cumulative trace.')
parser.add_option('-p', '--heapPrimitives', default=False, action='store_true',
                  help='render primitives as heap objects.')
parser.add_option('-o', '--compact', default=False, action='store_true',
                  help='output compact trace.')
parser.add_option('--allmodules', default=False, action='store_true',
                  help='allow importing of all installed Python modules.')
parser.add_option('-i', '--input', default=False, action='store',
                  help='JSON list of strings for simulated raw_input.', dest='raw_input_lst_json')
parser.add_option("--create_jsvar", dest="js_varname", default=None,
                  help="Create a JavaScript variable out of the trace")
parser.add_option("--code", dest="usercode", default=None,
                  help="Load user code from a string instead of a file and output compact JSON")
parser.add_option("--probe-exprs", dest="probe_exprs_json", default=None,
                  help="A JSON list of strings representing expressions whose values to probe at each step (advanced)")

(options, args) = parser.parse_args()
INDENT_LEVEL = None if options.compact else 2

if options.usercode:
    INDENT_LEVEL = None

    probe_exprs = None
    if options.probe_exprs_json:
        probe_exprs = json.loads(options.probe_exprs_json)

    allow_all_modules = False
    if options.allmodules:
        allow_all_modules = True

    print(pg_logger.exec_script_str_local(options.usercode,
                                          options.raw_input_lst_json,
                                          options.cumulative,
                                          options.heapPrimitives,
                                          json_finalizer,
                                          probe_exprs=probe_exprs,
                                          allow_all_modules=allow_all_modules))
else:
    fin = sys.stdin if args[0] == "-" else open(args[0])
    if options.js_varname:
        JS_VARNAME = options.js_varname
        print(pg_logger.exec_script_str_local(fin.read(), options.raw_input_lst_json, options.cumulative,
                                              options.heapPrimitives, js_var_finalizer))
    else:
        print(pg_logger.exec_script_str_local(fin.read(), options.raw_input_lst_json, options.cumulative,
                                              options.heapPrimitives, json_finalizer))
