import mathutils
import math
from mathutils import Vector
from .turtle import Turtle, Instruction
import bpy
from bpy.types import Operator
from bpy.props import FloatVectorProperty
from bpy_extras.object_utils import AddObjectHelper, object_data_add


class PMesh:
    _EPS = 10^-5
    _counter = 1
    def add_to_scene(self, mesh_name, obj_name):
        # clean this method
        mesh_name = mesh_name + str(PMesh._counter)
        obj_name = obj_name + str(PMesh._counter)
        PMesh._counter += 1
        mesh = bpy.data.meshes.new(name=mesh_name)
        mesh.from_pydata(self.v, self.e, [])
        theObj = bpy.data.objects.new(obj_name, mesh)
        bpy.context.collection.objects.link(theObj)
        blender_ob = bpy.context.collection.objects[obj_name]
        blender_ob.select_set(state=True)
        bpy.context.view_layer.objects.active = blender_ob
        bpy.ops.object.convert(target='CURVE')
        blender_ob.data.bevel_depth = self.bevel_depth
    def scale_max_coord(self, const):
        max_coord = self._EPS 
        for vec in self.v:
            max_coord = max(abs(vec.x), abs(vec.y), abs(vec.z), abs(max_coord))
        scale = const/max_coord
        for i, vec in enumerate(self.v):
            self.v[i] = vec*scale
        self.bevel_depth *= scale
        print("pmesh_max_coord="+str(max_coord))
    def __str__(self):
        out = "\nPolygon mesh:\n"
        out+= "   v = "+str(self.v)+"\n"
        out+= "   e = "+str(self.e)+"\n"
        return out
    def __init__(self, v=None, e=None, bevel_depth=0.1):
        if (v is None):
            v = [Vector([0,0,0])]
        if (e is None):
            e = []
        self.bevel_depth = bevel_depth
        self.v = v
        self.e = e

class PTurtle(Turtle):
    def clone(self):
        return PTurtle(self.pos, self.orient, self.v_t)
    def __init__(self, pos=None, orient=None, v_t=0):
        super().__init__(pos, orient)
        self.v_t = v_t
    def follow(self, pt):
        super().follow(pt)
        self.v_t = pt.v_t

class Rot(Instruction):
    def __init__(self, rot):
        self.rot = rot
    def exec(self, pturtle, stack, pmesh):
        pturtle.rot(self.rot)

class Wf(Instruction):
    def __init__(self, dist):
        self.dist = dist
    def exec(self, pturtle, stack, pmesh):
        pturtle.wf(self.dist)
        pturtle.v_t = len(pmesh.v)
        pmesh.v.append(pturtle.pos)

class Df(Instruction):
    def __init__(self, dist):
        self.dist = dist
    def exec(self, pturtle, stack, pmesh):
        pturtle.wf(self.dist)
        pmesh.v.append(pturtle.pos)
        nv = len(pmesh.v)
        pmesh.e.append([pturtle.v_t, nv-1])
        pturtle.v_t = nv-1

class Push(Instruction):
    def exec(self, pturtle, stack, pmesh):
        stack.append(pturtle.clone())

class Pop(Instruction):
    def exec(self, pturtle, stack, pmesh):
        pturtle.follow(stack.pop())
        # blender dk how to draw properly, then we do this hack
        pmesh.v.append(pturtle.pos)
        pturtle.v_t = len(pmesh.v)-1
