import os
import math
import argparse
import tkinter as tk

# グローバル設定
settings = {
    "linecolor": "black",
    "fillcolor": "",
    "fontcolor": "black",
    "linewidth": 1,
    "fillpattern": "",
    "projection": "isometric"
}

def terminate():
    print(f"\nPress ENTER to terminate>>\n")
    exit()

# 等角投影
def isometric_projection(x, y, z):
    angle_x = math.radians(30)
    angle_y = math.radians(30)
    px = x * math.cos(angle_x) - z * math.cos(angle_x)
    py = x * math.sin(angle_y) + y - z * math.sin(angle_y)
    return px, py

# 立方体描画
def draw_cube(canvas, x, y, z, size):
    vertices = []
    for dx in [0, size]:
        for dy in [0, size]:
            for dz in [0, size]:
                px, py = isometric_projection(x+dx, y+dy, z+dz)
                vertices.append((px, py))
    edges = [
        (0,1),(0,2),(0,4),(1,3),(1,5),(2,3),(2,6),(3,7),
        (4,5),(4,6),(5,7),(6,7)
    ]
    for i,j in edges:
        canvas.create_line(vertices[i][0], vertices[i][1],
                           vertices[j][0], vertices[j][1],
                           fill=settings["linecolor"], width=settings["linewidth"])

# ピラミッド描画
def draw_pyramid(canvas, x, y, z, base, height):
    base_pts = []
    for dx, dz in [(0,0), (base,0), (base,base), (0,base)]:
        px, py = isometric_projection(x+dx, y, z+dz)
        base_pts.append((px, py))
    apex = isometric_projection(x + base/2, y - height, z + base/2)
    for i in range(4):
        canvas.create_line(base_pts[i][0], base_pts[i][1],
                           base_pts[(i+1)%4][0], base_pts[(i+1)%4][1],
                           fill=settings["linecolor"], width=settings["linewidth"])
        canvas.create_line(base_pts[i][0], base_pts[i][1],
                           apex[0], apex[1],
                           fill=settings["linecolor"], width=settings["linewidth"])

# コマンド解析
def parse_command(canvas, cmd):
    tokens = cmd.strip().split()
    if not tokens:
        return None, None

    command = tokens[0]

    if command == "canvas":
        width, height = int(tokens[1]), int(tokens[2])
        root = tk.Tk()
        canvas = tk.Canvas(root, width=width, height=height, bg="white")
        canvas.pack()
        return root, canvas

    elif command == "line":
        x1, y1, x2, y2 = map(int, tokens[1:5])
        canvas.create_line(x1, y1, x2, y2, fill=settings["linecolor"], width=settings["linewidth"])

    elif command == "circle":
        x, y, r = map(int, tokens[1:4])
        canvas.create_oval(x-r, y-r, x+r, y+r, outline=settings["linecolor"],
                           fill=settings["fillcolor"], width=settings["linewidth"])

    elif command == "ellipse":
        x, y, w, h = map(int, tokens[1:5])
        canvas.create_oval(x-w//2, y-h//2, x+w//2, y+h//2, outline=settings["linecolor"],
                           fill=settings["fillcolor"], width=settings["linewidth"])

    elif command == "square":
        x, y, size = map(int, tokens[1:4])
        canvas.create_rectangle(x, y, x+size, y+size, outline=settings["linecolor"],
                                fill=settings["fillcolor"], width=settings["linewidth"])

    elif command == "triangle":
        x, y, size = map(int, tokens[1:4])
        h = int(size * math.sqrt(3)/2)
        points = [(x, y), (x+size, y), (x+size//2, y-h)]
        canvas.create_polygon(points, outline=settings["linecolor"],
                              fill=settings["fillcolor"], width=settings["linewidth"])

    elif command == "polygon":
        x, y, sides, radius = int(tokens[1]), int(tokens[2]), int(tokens[3]), int(tokens[4])
        points = []
        for i in range(sides):
            angle = 2 * math.pi * i / sides
            px = x + radius * math.cos(angle)
            py = y + radius * math.sin(angle)
            points.append((px, py))
        canvas.create_polygon(points, outline=settings["linecolor"],
                              fill=settings["fillcolor"], width=settings["linewidth"])

    elif command == "rect":
        x, y, w, h = map(int, tokens[1:5])
        canvas.create_rectangle(x, y, x+w, y+h, outline=settings["linecolor"],
                                fill=settings["fillcolor"], width=settings["linewidth"])

    elif command == "text":
        text = tokens[1].strip('"')
        x, y = int(tokens[2]), int(tokens[3])
        font = tokens[4].split("=")[1]
        size = int(tokens[5].split("=")[1])
        angle = int(tokens[6].split("=")[1])
        canvas.create_text(x, y, text=text, font=(font, size), fill=settings["fontcolor"], angle=angle)

    elif command in ["linecolor", "fillcolor", "fontcolor", "linewidth", "fillpattern"]:
        key = command
        value = tokens[1]
        settings[key] = int(value) if key == "linewidth" else value

    elif command == "spring":
        x, y = int(tokens[1]), int(tokens[2])
        length = int(tokens[3].split("=")[1])
        width = int(tokens[4].split("=")[1])
        cycles = int(tokens[5].split("=")[1])
        angle = math.radians(int(tokens[6].split("=")[1]))
        points = []
        for i in range(cycles * 2 + 1):
            dx = length * i / (cycles * 2)
            dy = width if i % 2 == 0 else -width
            px = x + dx * math.cos(angle) - dy * math.sin(angle)
            py = y + dx * math.sin(angle) + dy * math.cos(angle)
            points.append((px, py))
        canvas.create_line(points, fill=settings["linecolor"], width=settings["linewidth"], smooth=True)

    elif command == "zigzag":
        x, y = int(tokens[1]), int(tokens[2])
        length = int(tokens[3].split("=")[1])
        width = int(tokens[4].split("=")[1])
        cycles = int(tokens[5].split("=")[1])
        angle = math.radians(int(tokens[6].split("=")[1]))
        points = []
        for i in range(cycles + 1):
            dx = length * i / cycles
            dy = width if i % 2 == 0 else -width
            px = x + dx * math.cos(angle)
            py = y + dy * math.sin(angle)
            points.append((px, py))
        canvas.create_line(points, fill=settings["linecolor"], width=settings["linewidth"])

    elif command == "cube3d":
        x, y, z = map(int, tokens[1:4])
        size = int(tokens[4].split("=")[1])
        draw_cube(canvas, x, y, z, size)

    elif command == "pyramid3d":
        x, y, z = map(int, tokens[1:4])
        base = int(tokens[4].split("=")[1])
        height = int(tokens[5].split("=")[1])
        draw_pyramid(canvas, x, y, z, base, height)

    elif command == "project3d":
        settings["projection"] = tokens[1]

    return None, None

# スクリプト実行
def run_cad_script(script):
    root, canvas = None, None
    for line in script.strip().split("\n"):
        if line.startswith("canvas"):
            root, canvas = parse_command(None, line)
        else:
            parse_command(canvas, line)
    if root:
        root.mainloop()

def main():
    parser = argparse.ArgumentParser(description="Simple CAD interpreter")
    parser.add_argument("filename", nargs="?", default="example3d.ecad", help="CAD script file")
    args = parser.parse_args()

    if not os.path.exists(args.filename):
        print(f"ファイルが見つかりません: {args.filename}")
        terminate()

    with open(args.filename, "r", encoding="utf-8") as f:
        script = f.read()

    run_cad_script(script)

if __name__ == "__main__":
    main()