"""Provides a scripting component.
    Inputs:
        x: The x script variable
        y: The y script variable
    Output:
        a: The a output variable"""

__author__ = "Tina Shi"
__version__ = "2022.04.20"

import rhinoscriptsyntax as rs
import Rhino.Geometry as rg

from random import random

def gen_rect_surf(x, y, w, h):
    p1 = rs.CreatePoint(x, y)
    p2 = rs.CreatePoint(x + w, y)
    p3 = rs.CreatePoint(x + w, y + h)
    p4 = rs.CreatePoint(x, y + h)
    return rg.NurbsSurface.CreateFromCorners(p1, p2, p3, p4)

def gen_rect_surf_from_pts(p1, p2, y=False):
    p3 = None
    p4 = None
    if not y:
        p3 = rs.CreatePoint(p1.X, p2.Y, p2.Z)
        p4 = rs.CreatePoint(p2.X, p1.Y, p1.Z)
    else:
        p3 = rs.CreatePoint(p1.X, p2.Y, p1.Z)
        p4 = rs.CreatePoint(p2.X, p1.Y, p2.Z)
    return rg.NurbsSurface.CreateFromCorners(p1, p3, p2, p4)

def gen_prong_slots(w, l, tol, prong_num, face_w, face_num, start_pt):
    prong_slots = []

    prong_w = w + 2 * tol
    prong_l = l + 2 * tol
    prong_offset = (face_w - prong_w * prong_num) / (prong_num + 1)
    prong_y = start_pt.Y - tol
    for i in range(face_num):
        x_offset = start_pt.X + i * (face_w + 10)

        for j in range(prong_num):
            prong_x = x_offset + prong_offset * (j + 1) + prong_w * j

            prong_slots.append(gen_rect_surf(prong_x, prong_y, prong_w, prong_l))

    return prong_slots

def gen_prongs(w, l, prong_num, face_w, face_h, start_pt, extr_depth):
    prongs = []
    prong_extr_vecs = []

    prong_offset = (face_w - w * prong_num) / (prong_num + 1)
    prong_y = start_pt.Y
    
    for i in range(prong_num):
        prong_x = start_pt.X + prong_offset * (i + 1) + w * i
        p1 = rs.CreatePoint(prong_x, prong_y)
        p2 = rs.CreatePoint(prong_x + w, prong_y)
        p3 = rs.CreatePoint(prong_x + w, prong_y, l)
        p4 = rs.CreatePoint(prong_x, prong_y, l)
        prongs.append(rg.NurbsSurface.CreateFromCorners(p1, p2, p3, p4))

        prong_extr_vecs.append(rs.CreateVector(0.0, extr_depth, 0.0))

    prong_y = start_pt.Y + face_h
    for i in range(prong_num):
        prong_x = start_pt.X + prong_offset * (i + 1) + w * i
        p1 = rs.CreatePoint(prong_x, prong_y)
        p2 = rs.CreatePoint(prong_x + w, prong_y)
        p3 = rs.CreatePoint(prong_x + w, prong_y, l)
        p4 = rs.CreatePoint(prong_x, prong_y, l)
        prongs.append(rg.NurbsSurface.CreateFromCorners(p1, p2, p3, p4))

        prong_extr_vecs.append(rs.CreateVector(0.0, -extr_depth, 0.0))

    prong_x = start_pt.X
    for i in range(prong_num):
        prong_y = start_pt.Y + prong_offset * (i + 1) + w * i
        p1 = rs.CreatePoint(prong_x, prong_y)
        p2 = rs.CreatePoint(prong_x, prong_y + w)
        p3 = rs.CreatePoint(prong_x, prong_y + w, l)
        p4 = rs.CreatePoint(prong_x, prong_y, l)
        prongs.append(rg.NurbsSurface.CreateFromCorners(p1, p2, p3, p4))

        prong_extr_vecs.append(rs.CreateVector(extr_depth, 0.0, 0.0))

    prong_x = start_pt.X + face_w
    for i in range(prong_num):
        prong_y = start_pt.Y + prong_offset * (i + 1) + w * i
        p1 = rs.CreatePoint(prong_x, prong_y)
        p2 = rs.CreatePoint(prong_x, prong_y + w)
        p3 = rs.CreatePoint(prong_x, prong_y + w, l)
        p4 = rs.CreatePoint(prong_x, prong_y, l)
        prongs.append(rg.NurbsSurface.CreateFromCorners(p1, p2, p3, p4))

        prong_extr_vecs.append(rs.CreateVector(-extr_depth, 0.0, 0.0))

    return (prongs, prong_extr_vecs)

def gen_miter_planes(face_idx, start_pt, face_w, face_h, miter_h, rev=False):
    miter_planes = []

    x_offset = start_pt.X + face_idx * (face_w + 10)
    plane_orig_x = start_pt.X + i * (face_w + 10)

    # generate planes for trimming miter corners
    if not rev:
        plane_orig = rs.CreatePoint(plane_orig_x, start_pt.Y + miter_h, 0)
        plane_pt1 = rs.CreatePoint(plane_orig_x, start_pt.Y, miter_h)
        plane_pt2 = rs.CreatePoint(plane_orig_x + 1, start_pt.Y + miter_h, 0)

        miter_planes.append(rs.PlaneFromPoints(plane_orig, plane_pt1, plane_pt2))

        plane_orig = rs.CreatePoint(plane_orig_x + miter_h, start_pt.Y, 0)
        plane_pt1 = rs.CreatePoint(plane_orig_x, start_pt.Y, miter_h)
        plane_pt2 = rs.CreatePoint(plane_orig_x + miter_h, start_pt.Y + 1, 0)

        miter_planes.append(rs.PlaneFromPoints(plane_orig, plane_pt1, plane_pt2))

        plane_orig = rs.CreatePoint(plane_orig_x, start_pt.Y + face_h - miter_h, 0)
        plane_pt1 = rs.CreatePoint(plane_orig_x, start_pt.Y + face_h, miter_h)
        plane_pt2 = rs.CreatePoint(plane_orig_x + 1, start_pt.Y + face_h - miter_h, 0)

        miter_planes.append(rs.PlaneFromPoints(plane_orig, plane_pt1, plane_pt2))

        plane_orig = rs.CreatePoint(plane_orig_x + face_w - miter_h, start_pt.Y, 0)
        plane_pt1 = rs.CreatePoint(plane_orig_x + face_w, start_pt.Y, miter_h)
        plane_pt2 = rs.CreatePoint(plane_orig_x + face_w - miter_h, start_pt.Y + 1, 0)

        miter_planes.append(rs.PlaneFromPoints(plane_orig, plane_pt1, plane_pt2))
    else:
        plane_orig = rs.CreatePoint(plane_orig_x, start_pt.Y, 0)
        plane_pt1 = rs.CreatePoint(plane_orig_x, start_pt.Y + miter_h, miter_h)
        plane_pt2 = rs.CreatePoint(plane_orig_x + 1, start_pt.Y, 0)

        miter_planes.append(rs.PlaneFromPoints(plane_orig, plane_pt1, plane_pt2))

        plane_orig = rs.CreatePoint(plane_orig_x, start_pt.Y, 0)
        plane_pt1 = rs.CreatePoint(plane_orig_x + miter_h, start_pt.Y, miter_h)
        plane_pt2 = rs.CreatePoint(plane_orig_x, start_pt.Y + 1, 0)

        miter_planes.append(rs.PlaneFromPoints(plane_orig, plane_pt1, plane_pt2))

        plane_orig = rs.CreatePoint(plane_orig_x, start_pt.Y + face_h, 0)
        plane_pt1 = rs.CreatePoint(plane_orig_x, start_pt.Y + face_h - miter_h, miter_h)
        plane_pt2 = rs.CreatePoint(plane_orig_x + 1, start_pt.Y + face_h, 0)

        miter_planes.append(rs.PlaneFromPoints(plane_orig, plane_pt1, plane_pt2))

        plane_orig = rs.CreatePoint(plane_orig_x + face_w, start_pt.Y, 0)
        plane_pt1 = rs.CreatePoint(plane_orig_x + face_w - miter_h, start_pt.Y, miter_h)
        plane_pt2 = rs.CreatePoint(plane_orig_x + face_w, start_pt.Y + 1, 0)

        miter_planes.append(rs.PlaneFromPoints(plane_orig, plane_pt1, plane_pt2))

    return miter_planes

def gen_miter_surfs(face_idx, start_pt, face_w, face_h, miter_h, rev=False):
    miter_surfs = []
    miter_vecs = []

    x_offset = start_pt.X + face_idx * (face_w + 10)
    surf_x = start_pt.X + i * (face_w + 10)
    surf_y = start_pt.Y

    z1 = 0.0 if not rev else miter_h
    z2 = miter_h if not rev else 0.0

    p1 = rs.CreatePoint(surf_x, surf_y + miter_h, z1)
    p2 = rs.CreatePoint(surf_x + face_w, surf_y, z2)
    miter_surfs.append(gen_rect_surf_from_pts(p1, p2))
    miter_vecs.append(rs.CreateVector(0.0, -miter_h, 0.0))

    p1 = rs.CreatePoint(surf_x + miter_h, surf_y, z1)
    p2 = rs.CreatePoint(surf_x, surf_y + face_h, z2)
    miter_surfs.append(gen_rect_surf_from_pts(p1, p2, True))
    miter_vecs.append(rs.CreateVector(-miter_h, 0.0, 0.0))

    p1 = rs.CreatePoint(surf_x, surf_y + face_h - miter_h, z1)
    p2 = rs.CreatePoint(surf_x + face_w, surf_y + face_h, z2)
    miter_surfs.append(gen_rect_surf_from_pts(p1, p2))
    miter_vecs.append(rs.CreateVector(0.0, miter_h, 0.0))

    p1 = rs.CreatePoint(surf_x + face_w - miter_h, surf_y, z1)
    p2 = rs.CreatePoint(surf_x + face_w, surf_y + face_h, z2)
    miter_surfs.append(gen_rect_surf_from_pts(p1, p2, True))
    miter_vecs.append(rs.CreateVector(miter_h, 0.0, 0.0))

    return miter_surfs, miter_vecs

pts = []
grids = []
extr_v = []

w = p2.X - p1.X
h = p2.Y - p1.Y

grid_w = w / grid_num
grid_h = h / grid_num

miter_height = grid_extr_max

for k in range(face_num):
    x_offset = k * (w + 10)

    for i in range(grid_num):
        x = p1.X + i * grid_w + x_offset
        for j in range(grid_num):
            y = p1.Y + j * grid_h

            grids.append(gen_rect_surf(x, y, grid_w, grid_h))

            rng_h = grid_extr_min + random() * grid_extr_max
            if rng_h < miter_height:
                miter_height = rng_h

            extr_v.append(rs.CreateVector(0.0, 0.0, rng_h))

base_x = (w + 10) * face_num
base_y = p1.Y

base = gen_rect_surf(base_x, base_y, w, h)
base_start_pt = rs.CreatePoint(base_x, base_y)
prongs, prong_extr_vecs = gen_prongs(prong_w, prong_l, prong_num, w, h, base_start_pt, miter_height)


miter_planes = []
miter_surfs = []
miter_vecs = []
# base/bottom face miter goes in a different direction
# b/c other faces have outside upwards, bottom face has inside upwards
for i in range(face_num + 1):
    rev = False
    if i == face_num:
        rev = True
    miter_planes.extend(gen_miter_planes(i, p1, w, h, miter_height, rev))

    surfs, vecs = gen_miter_surfs(i, p1, w, h, miter_height, rev)
    miter_surfs.extend(surfs)
    miter_vecs.extend(vecs)

a_grid_surfs = grids
b_extr_vecs = extr_v
c_miter_planes = miter_planes

d_base_surf = base
e_base_vec = rs.CreateVector(0.0, 0.0, miter_height)

f_prong_slot_surfs = gen_prong_slots(prong_w, prong_l, prong_tol, prong_num, w, face_num - 1, p1)
g_prong_slot_vec = rs.CreateVector(0.0, 0.0, miter_height + prong_tol)

h_prong_surfs = prongs
i_prong_vecs = prong_extr_vecs

j_miter_surfs = miter_surfs
k_miter_vecs = miter_vecs