import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
import numpy as np

from P2_transformView_model import Camera, Scarecrow

width, height = 800, 600                                                    # width and height of the screen created

# drawing x, y, z axis in world space
def drawAxes():                                                             # draw x-axis and y-axis
    glLineWidth(3.0)                                                        # specify line size (1.0 default)
    glBegin(GL_LINES)                                                       # replace GL_LINES with GL_LINE_STRIP or GL_LINE_LOOP
    glColor3f(1.0, 0.0, 0.0)                                                # x-axis: red
    glVertex3f(0.0, 0.0, 0.0)                                               # v0
    glVertex3f(100.0, 0.0, 0.0)                                             # v1
    glColor3f(0.0, 1.0, 0.0)                                                # y-axis: green
    glVertex3f(0.0, 0.0, 0.0)                                               # v0
    glVertex3f(0.0, 100.0, 0.0)                                             # v1
    glColor3f(0.0, 0.0, 1.0)                                                # z-axis: blue
    glVertex3f(0.0, 0.0, 0.0)                                               # v0
    glVertex3f(0.0, 0.0, 100.0)                                             # v1
    glEnd()

# drawing the ground
def drawGround():
    ground_vertices = [[-500, -12.6, -500],
                       [-500, -12.6, 500],
                       [500, -12.6, 500],
                       [500, -12.6, -500]]

    glColor3f(0.4, 0.4, 0.4)
    glBegin(GL_QUADS)
    for vertex in ground_vertices:
        glVertex3fv(vertex)
    glEnd()


def main():
    pygame.init()                                                           # initialize a pygame program
    glutInit()                                                              # initialize glut library 

    screen = (width, height)                                                # specify the screen size of the new program window
    display_surface = pygame.display.set_mode(screen, DOUBLEBUF | OPENGL)   # create a display of size 'screen', use double-buffers and OpenGL
    pygame.display.set_caption('CPSC515: Transform & View - Devyn Miller')     # set title of the program window

    glEnable(GL_DEPTH_TEST)
    glMatrixMode(GL_PROJECTION)                                             # set mode to projection transformation
    glLoadIdentity()                                                        # reset transf matrix to an identity
    gluPerspective(45, (width / height), 0.1, 1000.0)                       # specify perspective projection view volume

    glMatrixMode(GL_MODELVIEW)                                              # set mode to modelview (geometric + view transf)
    initmodelMatrix = glGetFloat(GL_MODELVIEW_MATRIX)
    modelMatrix = glGetFloat(GL_MODELVIEW_MATRIX)

    # initialize the Scarecrow: body dimensions and transformation parameters 
    scarecrow = Scarecrow(version="basic") # by default, draw the basic Scarecrow

    # initialize the camera: camera parameters 
    camera = Camera(view_mode="front") # default view mode is "front"
    
    # Link the camera to the scarecrow for first-person view mode
    camera.scarecrow_ref = scarecrow

    # initialize the states of all the designated keys
    key_i_on = False        # if key 'I' is HELD on now
    key_o_on = False        # if key 'O' is HELD on now
    key_l_on = False        # if key 'L' is PRESSED - Switch to turn on/off arm/leg swinging animation for walk-in-place 
    key_r_on = False        # if key 'R' is PRESSED (not held) - Switch to turn on/off straightline/freeform walking
    key_left_on = False     # if left-arrow key is HELD on now
    key_right_on = False    # if right-arrow key is held on now
    key_a_on = False        # if key 'A' is HELD on now
    key_d_on = False        # if key 'D' is HELD on now
    key_w_on = False        # if key 'W' is HELD on now
    key_s_on = False        # if key 'S' is HELD on now
    key_q_on = False        # if key 'Q' is HELD on now
    key_e_on = False        # if key 'E' is HELD on now

    while True:
        bResetModelMatrix = False
        glPushMatrix()
        glLoadIdentity()
        key_i_on = False
        key_o_on = False

        #--------START: pygame.event.get()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()

            if event.type == pygame.MOUSEMOTION:
                if pygame.mouse.get_pressed()[0]:
                    glRotatef(event.rel[1], 1, 0, 0)
                    glRotatef(event.rel[0], 0, 1, 0)

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_0:                 # Press key '0' to reset the view by resetting the current model-view matrix
                    bResetModelMatrix = True
                elif event.key == pygame.K_SPACE:           # Press the space bar to switch view modes: front/side/back/first_person..
                    camera.switch_view()                    # Task 7: Switch front/side/back views here
                    bResetModelMatrix = True
                elif event.key == pygame.K_u:               # Press key 'U' to switch between the basic and upgraded Scarecrow
                    if scarecrow.version == "basic":
                        scarecrow.version = "upgraded"
                    elif scarecrow.version == "upgraded":
                        scarecrow.version = "basic"

                elif event.key == pygame.K_l:     # Press key 'L' to toggle between walk-in-place and freeform walking
                    key_l_on = not key_l_on

                elif event.key == pygame.K_r:     # Press key 'R' to toggle between straightline and freeform walking
                    key_r_on = not key_r_on
                elif event.key == pygame.K_i:
                    key_i_on = True
                elif event.key == pygame.K_o:
                    key_o_on = True
                elif event.key == pygame.K_LEFT:
                    key_left_on = True
                elif event.key == pygame.K_RIGHT:
                    key_right_on = True
                elif event.key == pygame.K_a:
                    key_a_on = True
                elif event.key == pygame.K_d:
                    key_d_on = True
                elif event.key == pygame.K_w:
                    key_w_on = True
                elif event.key == pygame.K_s:
                    key_s_on = True
                elif event.key == pygame.K_q:
                    key_q_on = True
                elif event.key == pygame.K_e:
                    key_e_on = True
                # add more key events and set key states here...
            
            elif event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT:
                    key_left_on = False
                elif event.key == pygame.K_RIGHT:
                    key_right_on = False
                elif event.key == pygame.K_a:
                    key_a_on = False
                elif event.key == pygame.K_d:
                    key_d_on = False
                elif event.key == pygame.K_w:
                    key_w_on = False
                elif event.key == pygame.K_s:
                    key_s_on = False
                elif event.key == pygame.K_q:
                    key_q_on = False
                elif event.key == pygame.K_e:
                    key_e_on = False
                elif event.key == pygame.K_i:
                    key_i_on = False
                elif event.key == pygame.K_o:
                    key_o_on = False
        
        #--------END: pygame.event.get()

        #Task 2: Update Scarecrow's head angle based on I, O key states

        # Task 4: Update Scarecrow's limb motion parameters (arm_angle, leg_angle) for walk-in-place 
        #        based on L, R key states
        if key_l_on:
            # update arm angle
            scarecrow.arm_angle += scarecrow.arm_direction * scarecrow.swing_speed
            if abs(scarecrow.arm_angle) > 30:
                scarecrow.arm_angle = 30 * scarecrow.arm_direction
                scarecrow.arm_direction *= -1  # reverse swing direction

            # update leg angle
            scarecrow.leg_angle += scarecrow.leg_direction * scarecrow.swing_speed
            if abs(scarecrow.leg_angle) > 30:
                scarecrow.leg_angle = 30 * scarecrow.leg_direction
                scarecrow.leg_direction *= -1  # reverse swing direction            
        
        # Task 5 and Task 6: Update Scarecrow's walk motion parameters 
        #       (walk_angle, walk_direction, walk_vector) for straightline walk and freeform walk  
        #        based on LEFT and RIGHT key states
        #       Call `update_walk_vector()` after updating walk_angle
        if key_r_on:
            if not key_l_on:
                key_l_on = True
            # update walking angle
            if key_left_on:
                scarecrow.walk_angle += 2.0
            if key_right_on:
                scarecrow.walk_angle -= 2.0

            # update the walking vector
            scarecrow.update_walk_vector()
         
        # Task 8: Update viewing parameters to transform (tilt, move forward/backward) the camera
        #       based on W/A/S/D/Q/E key states
        # Only apply these controls if not in first-person mode
        if camera.view_mode != "first_person":
            if key_w_on:
                camera.tilt_angle_vertical -= 3
            if key_s_on:
                camera.tilt_angle_vertical += 3
            if key_a_on:
                camera.tilt_angle_horizontal += 3
            if key_d_on:
                camera.tilt_angle_horizontal -= 3
            if key_q_on:
                camera.zoom_distance += 0.5
            if key_e_on:
                camera.zoom_distance -= 0.5
        # When '0' is tapped, reset the view 
        if (bResetModelMatrix):
            camera.zoom_distance = 0.0
            camera.tilt_angle_vertical = 0.0
            camera.tilt_angle_horizontal = 0.0
            glLoadIdentity()
            modelMatrix = initmodelMatrix
        glMultMatrixf(modelMatrix)
        modelMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)

        glLoadIdentity()
        
        # Task 7: Upate camera parameters: eye_position and look_at point
        new_eye_pos, new_lookat = camera.update_view()

        # Use updated camera parameters to update camera model
        gluLookAt(new_eye_pos[0], new_eye_pos[1], new_eye_pos[2], 
                  new_lookat[0], new_lookat[1],new_lookat[2],
                  camera.view_up[0], camera.view_up[1], camera.view_up[2])


        glMultMatrixf(modelMatrix)        

        # Task 1 & Task 3: Draw Scarecrow
        if key_i_on:
            scarecrow.head_angle = min(scarecrow.head_angle + 1, 85)
        elif key_o_on:
            scarecrow.head_angle = max(scarecrow.head_angle - 1, -85)
        if scarecrow.version == "basic":        
            scarecrow.draw_Scarecrow()
        elif scarecrow.version == "upgraded":
            scarecrow.draw_Scarecrow_Upgrade()
        

        # draw other entities in the scene
        drawAxes()
        drawGround()
        
        # Add landmark objects for better visual reference in first-person mode ( first-person view only)
        if camera.view_mode == "first_person":
            drawLandmarks()

        glPopMatrix()
        pygame.display.flip()
        pygame.time.wait(10)

def drawLandmarks():
    # Red cube at (-40,0,40)
    glPushMatrix()
    glTranslatef(-40, 0, 40)
    glScalef(0.5, 0.5, 0.5)
    glColor3f(1.0, 0.0, 0.0)
    glutSolidCube(5.0)
    glPopMatrix()
    
    # Blue sphere at (-20, 0, 20)
    glPushMatrix()
    glTranslatef(-20, 0, 20)
    glScalef(0.5, 0.5, 0.5)
    glColor3f(0.0, 0.0, 1.0)
    glutSolidSphere(3.0, 16, 16)
    glPopMatrix()
    
    # Green teapot at (-55, -8, 60)
    glPushMatrix()
    glTranslatef(-55, -8, 60)
    glScalef(0.5, 0.5, 0.5)
    glColor3f(0.0, 1.0, 0.0)
    glutSolidTeapot(4.0)
    glPopMatrix()
    
    # Yellow tetrahedron at (30, 0, -50)
    glPushMatrix()
    glTranslatef(-30, 0, 50)
    glScalef(0.5, 0.5, 0.5)
    glColor3f(1.0, 1.0, 0.0)
    glutSolidTetrahedron()
    glPopMatrix()
    
    # Magenta torus at (-30, 0, 25)
    glPushMatrix()
    glTranslatef(-30, 0, 25)
    glScalef(0.5, 0.5, 0.5)
    glColor3f(1.0, 0.0, 1.0)
    glutSolidTorus(1.0, 3.0, 16, 16)
    glPopMatrix()

main()