from .turtle.turtle import *
from .turtle.pturtle import *
from .turtle.rpturtle import *
from .turtle.fpturtle import *

class LSystem:
    def __init__(self):
        self.start_word = None
        self.word = None
    def rules(self, i):
        raise NotImplementedError('call to abstract method')
    def iterate(self, n):
        for k in range(n):
            new_word = []
            for i, w in enumerate(self.word):
                aux = self.rules(i)
                for a in aux:
                    new_word.append(a)
            self.word = new_word
    def reset(self):
        self.word = start_word
    def to_vec_instr(self):
        raise NotImplementedError('call to abstract method')
    def add_to_scene(self, turtle):
        raise NotImplementedError('call to abstract method')

class PLSystem(LSystem):
    def add_to_scene(self, turtle):
        stack = []
        pmesh = PMesh()
        Instruction.exec_all(turtle, stack, pmesh, self.to_vec_instr())
        pmesh.scale_max_coord(4)
        pmesh.add_to_scene("mesh barnFern", "obj barnFern")

# Example - Barnesley fern
class BarnFern(PLSystem):
    def __init__(self):
        self.start_word = ['X']
        self.word = self.start_word
    def rules(self, i):
        dic_rules = {
            'X': list('F+[[X]-X]-F[-FX]+X'),
            'F': list('FF'),
            '+' : '+',
            '-' : '-',
            '[':'[', 
            ']':']'}
        return dic_rules[self.word[i]]
    def to_vec_instr(self):
        instr = []
        switcher = {
            'F':Df(1),
            '+':Rot(mathutils.Quaternion((0, 0, 1), math.radians(25))), #left 25
            '-':Rot(mathutils.Quaternion((0, 0, 1), math.radians(-25))),
            '[':Push(),
            ']':Pop(),
        }
        for c in self.word:
            if switcher.get(c, None) is not None:
                instr.append(switcher[c])
        return instr


class KochCurve(PLSystem):
    def __init__(self):
        self.start_word = ['F']
        self.word = self.start_word
    def rules(self, i):
        dic_rules = {
            '+': '+',
            '-': '-',
            'F': list('F+F-F-F+F')}
        print(self.word[i])
        return dic_rules[self.word[i]]
    def to_vec_instr(self):
        instr = []
        switcher = {
            'F':Df(1),
            '+':Rot(mathutils.Quaternion((0, 0, 1), math.radians(90))), #left 90
            '-':Rot(mathutils.Quaternion((0, 0, 1), math.radians(-90))),
            '[':Push(),
            ']':Pop(),
        }
        for c in self.word:
            if switcher.get(c, None) is not None:
                instr.append(switcher[c])
        return instr


class DragonCurve(PLSystem):
    def __init__(self):
        self.start_word = ['F','X']
        self.word = self.start_word
    def rules(self, i):
        dic_rules = {
            'F':'F',
            '+':'+',
            '-':'-',
            'X': list('X+YF+'),
            'Y': list('-FX-Y')}
        return dic_rules[self.word[i]]
    def to_vec_instr(self):
        instr = []
        switcher = {
            'F':Df(1),
            '+':Rot(mathutils.Quaternion((0, 0, 1), math.radians(90))), #left 90
            '-':Rot(mathutils.Quaternion((0, 0, 1), math.radians(-90))),
            '[':Push(),
            ']':Pop(),
        }
        for c in self.word:
            if switcher.get(c, None) is not None:
                instr.append(switcher[c])
        return instr
