import http.client
import json
import time

HOST = 'localhost' #'127.0.0.1'
PORT = 8085
headers = {'Content-type': 'application/json'}

bouncing_scroll = 'http://mathhub.info/FrameIT/frameworld?W3DBouncingScroll'
pos_ref = {'uri': 'http://mathhub.info/FrameIT/frameworld?W3DBouncingScroll/Problem?position'}
vel_ref = {'uri': 'http://mathhub.info/FrameIT/frameworld?W3DBouncingScroll/Problem?velocity'}
G_ref = {'uri': 'http://mathhub.info/FrameIT/frameworld?W3DBouncingScroll/Problem?g_base'}
B_ref = {'uri': 'http://mathhub.info/FrameIT/frameworld?W3DBouncingScroll/Problem?bounce'}
W_ref = {'uri': 'http://mathhub.info/FrameIT/frameworld?W3DBouncingScroll/Problem?wallsr'}

real_list = 'http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory2?real_list'
list_type = 'http://gl.mathhub.info/MMT/LFX/Datatypes?ListSymbols?ListType'
product = 'http://gl.mathhub.info/MMT/LFX/Sigma?Symbols?Product'
real_lit = 'http://mathhub.info/MitM/Foundation?RealLiterals?real_lit'
cons = 'http://gl.mathhub.info/MMT/LFX/Datatypes?ListSymbols?cons'
cons_nil = 'http://gl.mathhub.info/MMT/LFX/Datatypes?ListSymbols?nil_constant'
tuple_mmt = 'http://gl.mathhub.info/MMT/LFX/Sigma?Symbols?Tuple'
point_mmt = 'http://mathhub.info/MitM/core/geometry?3DGeometry?point'


def list_element_4point(p1, p2, p3, p4):
    return {'applicant': {'uri': tuple_mmt, 'kind': 'OMS'},
            'arguments': [{'applicant': {'uri': tuple_mmt, 'kind': 'OMS'},
                           'arguments': [{'float': p1[0], 'kind': 'OMF'},
                                         {'float': p1[1], 'kind': 'OMF'},
										 {'float': p1[2], 'kind': 'OMF'}],
                           'kind': 'OMA'},
                          {'applicant': {'uri': tuple_mmt, 'kind': 'OMS'},
                           'arguments': [{'float': p2[0], 'kind': 'OMF'},
                                         {'float': p2[1], 'kind': 'OMF'},
										 {'float': p2[2], 'kind': 'OMF'}],
                           'kind': 'OMA'},
						  {'applicant': {'uri': tuple_mmt, 'kind': 'OMS'},
                           'arguments': [{'float': p3[0], 'kind': 'OMF'},
                                         {'float': p3[1], 'kind': 'OMF'},
										 {'float': p3[2], 'kind': 'OMF'}],
                           'kind': 'OMA'},
						  {'applicant': {'uri': tuple_mmt, 'kind': 'OMS'},
                           'arguments': [{'float': p4[0], 'kind': 'OMF'},
                                         {'float': p4[1], 'kind': 'OMF'},
										 {'float': p4[2], 'kind': 'OMF'}],
                           'kind': 'OMA'}],
            'kind': 'OMA'}

def list_element_4point_plus_nil(p1, p2, p3, p4):
    return {'applicant': {'uri': cons, 'kind': 'OMS'},
            'arguments': [{'applicant': {'uri': cons_nil, 'kind': 'OMS'},
                           'arguments': [{'applicant': {'uri': product, 'kind': 'OMS'},
                                          'arguments': [{'applicant': {'uri': product, 'kind': 'OMS'},
                                                         'arguments': [{'uri': real_lit, 'kind': 'OMS'},
                                                                       {'uri': real_lit, 'kind': 'OMS'},
																	   {'uri': real_lit, 'kind': 'OMS'}],
                                                         'kind': 'OMA'},
                                                        {'applicant': {'uri': product, 'kind': 'OMS'},
                                                         'arguments': [{'uri': real_lit, 'kind': 'OMS'},
                                                                       {'uri': real_lit, 'kind': 'OMS'},
																	   {'uri': real_lit, 'kind': 'OMS'}],
                                                         'kind': 'OMA'},
														{'applicant': {'uri': product, 'kind': 'OMS'},
                                                         'arguments': [{'uri': real_lit, 'kind': 'OMS'},
                                                                       {'uri': real_lit, 'kind': 'OMS'},
																	   {'uri': real_lit, 'kind': 'OMS'}],
                                                         'kind': 'OMA'},
														{'applicant': {'uri': product, 'kind': 'OMS'},
                                                         'arguments': [{'uri': real_lit, 'kind': 'OMS'},
                                                                       {'uri': real_lit, 'kind': 'OMS'},
																	   {'uri': real_lit, 'kind': 'OMS'}],
                                                         'kind': 'OMA'}],
                                          'kind': 'OMA'}],
                           'kind': 'OMA'},
                          {'applicant': {'uri': tuple_mmt, 'kind': 'OMS'},
                           'arguments': [{'applicant': {'uri': tuple_mmt, 'kind': 'OMS'},
                                          'arguments': [{'float': p1[0], 'kind': 'OMF'},
                                                        {'float': p1[1], 'kind': 'OMF'},
										                {'float': p1[2], 'kind': 'OMF'}],
                                          'kind': 'OMA'},
                                         {'applicant': {'uri': tuple_mmt, 'kind': 'OMS'},
                                          'arguments': [{'float': p2[0], 'kind': 'OMF'},
                                                        {'float': p2[1], 'kind': 'OMF'},
										                {'float': p2[2], 'kind': 'OMF'}],
                                          'kind': 'OMA'},
						                 {'applicant': {'uri': tuple_mmt, 'kind': 'OMS'},
                                          'arguments': [{'float': p3[0], 'kind': 'OMF'},
                                                        {'float': p3[1], 'kind': 'OMF'},
										                {'float': p3[2], 'kind': 'OMF'}],
                                          'kind': 'OMA'},
						                 {'applicant': {'uri': tuple_mmt, 'kind': 'OMS'},
                                          'arguments': [{'float': p4[0], 'kind': 'OMF'},
                                                        {'float': p4[1], 'kind': 'OMF'},
										                {'float': p4[2], 'kind': 'OMF'}],
                                          'kind': 'OMA'}],
                           'kind': 'OMA'}],
            'kind': 'OMA'}

def cons_2elements(e1, e2):
    return {'applicant': {'uri': cons, 'kind': 'OMS'},
            'arguments': [e1, e2],
            'kind': 'OMA'}

def construct_list_4point_df(values):
    # Values needs to be of the form [[[x1, y1, z1], [x2, y2, z2], [x3, y3, z3], [x4, y4, z4]], ...]
    prev_ele = {}
    for ci, cv in enumerate(values[::-1]):
        if ci == 0:
            prev_ele = list_element_4point_plus_nil(cv[0], cv[1], cv[2], cv[3])
        else:
            cur_ele = list_element_4point(cv[0], cv[1], cv[2], cv[3])
            prev_ele = cons_2elements(prev_ele, cur_ele)
    return prev_ele

def create_walls_fact(values):
    # Values needs to be of the form [[x1, y1, x2, y2], [x1, y1, x2, y2], ...]
    return {'ref': W_ref,
            'label': 'Wallsr',
            'tp': {'applicant': {'uri': list_type, 'kind': 'OMS'},
                   'arguments': [{'applicant': {'uri': product, 'kind': 'OMS'},
                                  'arguments': [{'uri': point_mmt, 'kind': 'OMS'},
                                                {'uri': point_mmt, 'kind': 'OMS'},
												{'uri': point_mmt, 'kind': 'OMS'},
												{'uri': point_mmt, 'kind': 'OMS'}],
                                  'kind': 'OMA'}],
                   'kind': 'OMA'},
            'kind': 'general',
            'df': construct_list_4point_df(values)
            }

def create_R_fact(val, ref):
    return {"ref": ref,
            "label": "X",
            "kind": "general",
            "tp": {'uri': real_lit,
                   'kind': 'OMS'},
            "df": {"kind": "OMF", "float": val}
            }

def create_point_fact(val, ref):
    return {"ref": ref,
            "label": "P",
            "kind": "general",
	        "tp": {"kind": "OMS", "uri": point_mmt},
	        "df": {"kind": "OMA", "applicant": {"kind": "OMS", "uri": tuple_mmt},
		           "arguments": [{"kind": "OMF", "float": val[0]},
			                     {"kind": "OMF", "float": val[1]},
			                     {"kind": "OMF", "float": val[2]}]}}

g = [0.0, 0.0, -200.0]
pos_fact = create_point_fact([380.0, 0.0, 300.0], pos_ref)
vel_fact = create_point_fact([-490.0, 100.0, 150.0], vel_ref)
G_fact = create_point_fact(g, G_ref)
B_fact = create_R_fact(0.8, B_ref)
#wallsr_list = [[[-400.0, -400.0, 0.0], [400.0, -400.0, 0.0], [400.0, 400.0, 0.0], [-400.0, 400.0, 0.0]]]
wallsr_list = [[[0.0, 0.0, 0.0], [400.0, 0.0, 0.0], [400.0, 0.0, 400.0], [0.0, 0.0, 400.0]],
               [[0.0, 400.0, 0.0], [400.0, 400.0, 0.0], [400.0, 400.0, 400.0], [0.0, 400.0, 400.0]],
               [[0.0, 0.0, 0.0], [0.0, 0.0, 400.0], [0.0, 400.0, 400.0], [0.0, 400.0, 0.0]],
               [[400.0, 0.0, 0.0], [400.0, 0.0, 400.0], [400.0, 400.0, 400.0], [400.0, 400.0, 0.0]],
               [[0.0, 0.0, 400.0], [400.0, 0.0, 400.0], [400.0, 400.0, 400.0], [0.0, 400.0, 400.0]],
               [[0.0, 0.0, 0.0], [400.0, 0.0, 0.0], [400.0, 400.0, 0.0], [0.0, 400.0, 0.0]],
               [[50.0, 0.0, 200.0], [120.7, 0.0, 270.7], [120.7, 200.0, 270.7], [50.0, 200.0, 200.0]],
               [[150.0, 0.0, 100.0], [200.0, 0.0, 100.0], [200.0, 200.0, 100.0], [150.0, 200.0, 100.0]],
               [[150.0, 0.0, 286.6], [200.0, 0.0, 200.0], [200.0, 200.0, 200.0], [150.0, 200.0, 286.6]],
               [[230.7, 0.0, 340.0], [300.0, 0.0, 300.0], [300.0, 200.0, 300.0], [230.7, 200.0, 340.0]],
               [[300.0, 0.0, 100.0], [386.6, 0.0, 150.0], [386.6, 200.0, 150.0], [300.0, 200.0, 100.0]],
               [[50.0, 0.0, 50.0], [100.0, 0.0, 136.6], [100.0, 200.0, 136.6], [50.0, 200.0, 50.0]]]
wallsr_fact = create_walls_fact(wallsr_list)
fact_list = [pos_fact, vel_fact, G_fact, B_fact, wallsr_fact]
fact_list_encoded = json.dumps(fact_list).encode('utf-8')

scroll_assignment_list = [{"fact": pos_ref, "assignment": {"kind": "OMS", "uri": 'http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1'}},
                          {"fact": vel_ref, "assignment": {"kind": "OMS", "uri": 'http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact2'}}, 
                          {"fact": G_ref, "assignment": {"kind": "OMS", "uri": 'http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact3'}},
                          {"fact": B_ref, "assignment": {"kind": "OMS", "uri": 'http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact4'}},
                          {"fact": W_ref, "assignment": {"kind": "OMS", "uri": 'http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact5'}}]
scroll_application = {"scroll": bouncing_scroll,
                      "assignments": scroll_assignment_list}
scroll_encoded = json.dumps(scroll_application).encode('utf-8')

t1 = time.time()
conn = http.client.HTTPConnection(HOST, port=PORT)
conn.request("POST", "/fact/bulkadd", headers=headers, body=fact_list_encoded)
response = conn.getresponse()
data = response.read()
print(response.status, response.reason)
print(time.time() - t1)

data_dict = json.loads(data.decode('utf-8'))

t2 = time.time()
conn = http.client.HTTPConnection(HOST, port=PORT)
conn.request("POST", "/scroll/apply", headers=headers, body=scroll_encoded)
response = conn.getresponse()
data = response.read()
print(response.status, response.reason)
print(time.time() - t2)


data_dict = json.loads(data.decode('utf-8'))
for i in range(len(data_dict["acquiredFacts"])):
    print(data_dict["acquiredFacts"][i])

rel_fact = data_dict['acquiredFacts'][0]["df"]["arguments"]
values = []
for rf in rel_fact:
    rfa = rf["arguments"]
    cvals = []
    for ri2, rrf in enumerate(rfa):
        if ri2 == len(rfa) - 2:
            cvals.extend([x["float"] for x in rrf["arguments"][0]["arguments"]])
            cvals.append(rrf["arguments"][1]["float"])
        elif ri2 == len(rfa) - 1:
            cvals.append(rrf["float"])
        else:
            cvals.extend([x["float"] for x in rrf["arguments"]])
    values.append(cvals)
print("Step\tX\tY\tZ\tXv\tYv\tZv\tht\tnx\tny\tnz")
for i, v in enumerate(values):
    print("%d\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f" % (i, v[0], v[1], v[2], v[3], v[4], v[5], v[9], v[6], v[7], v[8]))
    

import matplotlib.pyplot as plt
import numpy as np

def get_xyz_wrap(xs, ys, zs, xv, yv, zv):
    def get_xyz(ct):
        rx = xs + ct * xv + 0.5 * g[0] * ct**2
        ry = ys + ct * yv + 0.5 * g[1] * ct**2
        rz = zs + ct * zv + 0.5 * g[2] * ct**2
        return np.array([rx, ry, rz])
    return get_xyz

# plot ---------------------------------------------------- #
def floatRgb(mag, cmin, cmax):
    """ Return a tuple of floats between 0 and 1 for R, G, and B. """
    # Normalize to 0-1
    x = float(mag - cmin) / (cmax - cmin)
    blue  = np.minimum(np.maximum(4*(0.75-x), 0.), 1.)
    red   = np.minimum(np.maximum(4*(x-0.25), 0.), 1.)
    green = np.minimum(np.maximum(4*np.abs(x-0.5)-1., 0.), 1.)
    return red, green, blue

def rgb(mag, cmin, cmax):
    """ Return a tuple of integers, as used in AWT/Java plots. """
    red, green, blue = floatRgb(mag, cmin, cmax)
    return int(red*255), int(green*255), int(blue*255)

def strRgb(mag, cmin, cmax):
    """ Return a hex string, as used in Tk plots. """
    return "#%02x%02x%02x" % rgb(mag, cmin, cmax)

plt.figure()
ax = plt.axes(projection ="3d")

pos3ds = []
colors = []
for w in wallsr_list:
    spos = np.array(w[0])
    in1 = np.array(w[1]) -np.array( w[0])
    in2 = np.array(w[3]) - np.array(w[0])
    for i1 in np.arange(0, 1.01, 0.1):
        for i2 in np.arange(0, 1.01, 0.1):
            cur_pos = spos + i1 * in1 + i2 * in2
            pos3ds.append([cur_pos[0], cur_pos[1], cur_pos[2]])
            colors.append(strRgb(cur_pos[1], 0, 400))
for mii, mi in enumerate(values):
    xyz_func = get_xyz_wrap(mi[0], mi[1], mi[2], mi[3], mi[4], mi[5])
    pos3ds.extend([xyz_func(ct) for ct in np.arange(0, mi[9], 0.01)])
    colors.extend([strRgb(xyz_func(ct)[1], 0, 400) for ct in np.arange(0, mi[9], 0.01)])
pos3ds = np.array(pos3ds)
ax.scatter3D(pos3ds[:, 0], pos3ds[:, 1], pos3ds[:, 2], color=colors)
plt.show()
# plot ---------------------------------------------------- #