from pyglet.window import key
from pyglet.window.mouse import LEFT, RIGHT, MIDDLE
from util import get_direction_vectors, get_basis_vectors

class PlotController(object):

    normal_mouse_sensitivity = 4.0
    modified_mouse_sensitivity = 1.0

    normal_key_sensitivity = 160.0
    modified_key_sensitivity = 40.0

    keymap = {
                key.LEFT:'left',
                key.A:'left',
                key.NUM_4:'left',

                key.RIGHT:'right',
                key.D:'right',
                key.NUM_6:'right',

                key.UP:'up',
                key.W:'up',
                key.NUM_8:'up',

                key.DOWN:'down',
                key.S:'down',
                key.NUM_2:'down',

                key.Z:'rotate_z_neg',
                key.NUM_1:'rotate_z_neg',

                key.C:'rotate_z_pos',
                key.NUM_3:'rotate_z_pos',

                key.Q:'spin_left',
                key.NUM_7:'spin_left',
                key.E:'spin_right',
                key.NUM_9:'spin_right',

                key.X:'reset_camera',
                key.NUM_5:'reset_camera',

                key.NUM_ADD:'zoom_in',
                key.PAGEUP:'zoom_in',
                key.R:'zoom_in',

                key.NUM_SUBTRACT:'zoom_out',
                key.PAGEDOWN:'zoom_out',
                key.F:'zoom_out',

                key.RSHIFT:'modify_sensitivity',
                key.LSHIFT:'modify_sensitivity',

                key.F1:'rot_preset_xy',
                key.F2:'rot_preset_xz',
                key.F3:'rot_preset_yz',
                key.F4:'rot_preset_perspective',

                key.F5:'toggle_axes',
                key.F6:'toggle_axe_colors',

                key.F8:'save_image'
             }

    def __init__(self, window, **kwargs):
        self.invert_mouse_zoom = kwargs.pop('invert_mouse_zoom', False)
        self.window = window
        self.camera = window.camera
        self.action = {
                # Rotation around the view Y (up) vector
                'left':False,
                'right':False,
                # Rotation around the view X vector
                'up':False,
                'down':False,
                # Rotation around the view Z vector
                'spin_left':False,
                'spin_right':False,
                # Rotation around the model Z vector
                'rotate_z_neg':False,
                'rotate_z_pos':False,
                # Reset to the default rotation
                'reset_camera':False,
                # Performs camera z-translation
                'zoom_in':False,
                'zoom_out':False,
                # Use alternative sensitivity (speed)
                'modify_sensitivity':False,
                # Rotation presets
                'rot_preset_xy':False,
                'rot_preset_xz':False,
                'rot_preset_yz':False,
                'rot_preset_perspective':False,
                # axes
                'toggle_axes':False,
                'toggle_axe_colors':False,
                # screenshot
                'save_image':False
            }

    def update(self, dt):
        z = 0
        if self.action['zoom_out']: z -= 1
        if self.action['zoom_in']: z += 1
        if z != 0:
            self.camera.zoom_relative(z/10.0, self.get_key_sensitivity()/10.0)

        dx, dy, dz = 0, 0, 0
        if self.action['left']: dx -= 1
        if self.action['right']: dx += 1
        if self.action['up']: dy -= 1
        if self.action['down']: dy += 1
        if self.action['spin_left']: dz += 1
        if self.action['spin_right']: dz -= 1

        if not self.is_2D():
            if dx != 0:
                self.camera.euler_rotate(dx*dt*self.get_key_sensitivity(), *(get_direction_vectors()[1]))
            if dy != 0:
                self.camera.euler_rotate(dy*dt*self.get_key_sensitivity(), *(get_direction_vectors()[0]))
            if dz != 0:
                self.camera.euler_rotate(dz*dt*self.get_key_sensitivity(), *(get_direction_vectors()[2]))
        else:
            self.camera.mouse_translate(0, 0, dx*dt*self.get_key_sensitivity(), -dy*dt*self.get_key_sensitivity())

        rz = 0
        if self.action['rotate_z_neg'] and not self.is_2D(): rz -= 1
        if self.action['rotate_z_pos'] and not self.is_2D(): rz += 1

        if rz != 0:
            self.camera.euler_rotate(rz*dt*self.get_key_sensitivity(), *(get_basis_vectors()[2]))

        if self.action['reset_camera']:
            self.camera.reset()

        if self.action['rot_preset_xy']:
            self.camera.set_rot_preset('xy')
        if self.action['rot_preset_xz']:
            self.camera.set_rot_preset('xz')
        if self.action['rot_preset_yz']:
            self.camera.set_rot_preset('yz')
        if self.action['rot_preset_perspective']:
            self.camera.set_rot_preset('perspective')

        if self.action['toggle_axes']:
            self.action['toggle_axes'] = False
            self.camera.axes.toggle_visible()

        if self.action['toggle_axe_colors']:
            self.action['toggle_axe_colors'] = False
            self.camera.axes.toggle_colors()

        if self.action['save_image']:
            self.action['save_image'] = False
            self.window.plot.saveimage()

        return True

    def get_mouse_sensitivity(self):
        if self.action['modify_sensitivity']:
            return self.modified_mouse_sensitivity
        else:
            return self.normal_mouse_sensitivity

    def get_key_sensitivity(self):
        if self.action['modify_sensitivity']:
            return self.modified_key_sensitivity
        else:
            return self.normal_key_sensitivity

    def on_key_press(self, symbol, modifiers):
        if symbol in self.keymap:
            self.action[self.keymap[symbol]] = True

    def on_key_release(self, symbol, modifiers):
        if symbol in self.keymap:
            self.action[self.keymap[symbol]] = False

    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        if buttons & LEFT:
            if self.is_2D():
                self.camera.mouse_translate(x, y, dx, dy)
            else:
                self.camera.spherical_rotate((x-dx,y-dy),(x,y), self.get_mouse_sensitivity())
        if buttons & MIDDLE:
            self.camera.zoom_relative([1,-1][self.invert_mouse_zoom]*dy, self.get_mouse_sensitivity()/20.0)
        if buttons & RIGHT:
            self.camera.mouse_translate(x, y, dx, dy)

    def on_mouse_scroll(self, x, y, dx, dy):
        self.camera.zoom_relative([1,-1][self.invert_mouse_zoom]*dy, self.get_mouse_sensitivity())

    def is_2D(self):
        functions = self.window.plot._functions
        for i in functions:
            if len(functions[i].i_vars)>1 or len(functions[i].d_vars)>2:
                return False
        return True
