import math
import random
import os.path
from OpenGL.GL import *
from OpenGL.GLU import *

import pygame
from pygame.locals import *

from agk.matrix44 import Matrix44
from agk.vector3 import Vector3

import itertools
import pdb

#Import my stuff
import Readers3d
import Objects3d
import Entities



class ModelCollection(dict):
    planet_path = "models/rigid/inside_world.obj"
    goat_path = "models/rigid/goat_statue.obj"

    NEED_DISPLAY_LIST = "rigid"


    def __init__(self):
        self.file_paths = [self.planet_path, self.goat_path]
        dict.__init__(self)
        self.fill_collection()

    def fill_collection(self):
        # shortcuts, (supposed to help with speed if lots of files)
        base = os.path.basename
        dir = os.path.dirname

        for fpath in self.file_paths:
            model = Readers3d.ReadOBJ( fpath )
            model_name = base(fpath).replace(".obj", "", 1)
            model_type = base(dir(fpath))

            if model_type == self.NEED_DISPLAY_LIST:
                model = self.make_display_list( model )     # this returns ID of display list

            self[ model_name ] = model

    def make_display_list(self, objreader):
        list_id = glGenLists(1)
        glNewList(list_id, GL_COMPILE)
        self.draw( objreader )
        glEndList()
        return list_id

    def draw(self, objreader):
        vertices = objreader.vertices
        normals = objreader.normals

        glBegin(GL_TRIANGLES)
        for index_ref in objreader.two_indices:
            glVertex3fv( vertices[index_ref[0]] )
            glNormal3fv( normals[index_ref[1]] )
        glEnd()




class PointsCollection(dict):
    goat_positions = "maps/goat_positions.obj"

    def __init__(self):
        self.file_paths = [ self.goat_positions ]
        dict.__init__(self)
        self.fill_collection()

    def fill_collection(self):
        basename = os.path.basename     # shortcut
        for fpath in self.file_paths:
            reader = Readers3d.ReadPoints( fpath )
            purpose = basename(fpath).replace(".obj", "", 1)
            self[ purpose ] = reader



class Bakery(object):

    def __init__(self):
        self.models = ModelCollection()
        self.points = PointsCollection()

    def make_level(self):
        static, dynamic = {}, {}

        planet = self.make_planet()
        static[ planet.id ] = planet

        for location in self.points["goat_positions"]:
            goat = self.make_goat( location )
            dynamic[ goat.id ] = goat

        return static, dynamic


    def make_planet(self):
        matrix = Matrix44.scale(0.81, 0.81, 0.81)
        display_list_id = self.models["inside_world"]
        color = (0.5, 0.78, 1.0)
        planet = Objects3d.RootedRigidColorMesh( matrix, display_list_id, color )
        return planet


    def make_goat(self, location):      # goat is a static mesh that can move and rotate
        matrix = Matrix44.translation( *location )
        matrix.translate += -Vector3(location)/5.0
        display_list_id = self.models["goat_statue"]
        color = (0.48, 0.6, 1.0)
        move_speed = random.randint(1, 10) * 1.0
        rotate_speed = math.radians(150.0)
        accel_force = random.randint( 12, 110) / 1000.0
        goat = Entities.Goat( accel_force, move_speed, rotate_speed, matrix, display_list_id, color )
        return goat



    def make_pegasus( self ):  # pegasus is an animated mesh, that can move rotate and deform.
        return
        matrix = Matrix44.translation( *location )
        matrix.translate += -Vector3(location)/5.0
        model = self.models["goat"]
        color = (0.48, 0.6, 1.0)
        return Objects3d.MovingAnimatedColorMesh( matrix, model, color )


    def make_windmill( self ):     # windmill is an animated mesh fixed in one place.
        return
        matrix = Matrix44.translation( *location )
        matrix.translate += -Vector3(location)/5.0
        model = self.models["goat"]
        color = (0.48, 0.6, 1.0)
        return Objects3d.RootedAnimatedColorMesh( matrix, model, color )




class cls_Map(Bakery):

    def __init__(self):
        Bakery.__init__(self)
        self.static_display_list = None
        self.static, self.dynamic = self.make_level()       # of type dictionary



    def update_dynamic(self, TimeDelay):
        for obj in self.dynamic.values():
            obj.update( TimeDelay, self.dynamic.values() )
            obj.render()

    def render(self):
        if self.static_display_list is None:
            #get all_objects's vertices and faces and normals and colours
            self.static_display_list = self.create_display_list()
        glCallList(self.static_display_list)


    def create_display_list(self):
        some_list_id = glGenLists(1)
        glNewList(some_list_id, GL_COMPILE)
        self.render_objects( self.static.values() )
        glEndList()
        return some_list_id

    def render_objects(self, things):
        for object in things:
            object.render()

