# GPLv3 or any later version
# (C) J.Y.Amihud ( blenderdumbass )

# This file will dealwith tools and stuff.

import bge
import bpy
import aud
import math
import mathutils

from Scripts import Reuse

from Scripts.Common import *

from Scripts import Vehicle
from Scripts import Script
from Scripts import Garage

def MainLoop():

    keys = bge.logic.globalDict["keys"]
    mouse = bge.logic.globalDict["mouse"]
    
    scene = bge.logic.getCurrentScene()
    dani  = scene.objects["Dani_Box"]

    if dani.get("driving"):
        return
    
    camera     = scene.active_camera
    hand  = scene.objects["Tool_Hand"]
    hc    = scene.objects["Health_Circle"]

    box = scene.objects["Boxify"]
    if box.get("timer"): box["timer"] -= 1
    else: box.position = [0,0,-1000]
    
    # If dani is using a fix tool
    if str(dani.get("tool")) == "FixTool":

        dis = 10000
        car = None
        
        for thecar in bge.logic.globalDict["allcars"]:
            cd = thecar.getDistanceTo(dani)
            if cd < dis:
                dis = cd
                car = thecar

        ray = DaniPoint(dani, camera)

        found = False
                
        if car:
                
            # First we gonna create a list of all objects
            # that the car can get fixed.

            attachment = dani.get("tool-attachment")
            
            objs = []

            if not Vehicle.OnGround(car):
                objs = [car]
            
            for wheel in car["wheels"]:
                if ( wheel.visible and not attachment ) or  attachment == "Wheels" :
                    objs.append(wheel)
                    
            for door in car.get("doors", []):
                if ( door.visible and not attachment ) or  attachment == "Parts" :
                    objs.append(door)

            if "NitroCanProxy" in car.childrenRecursive and\
               (( not car.get("NitroCan") and attachment == "Nitros") or ( car.get("NitroCan") and not attachment )):
                objs.append(car.childrenRecursive["NitroCanProxy"])

            if "SpoilerProxy" in car.childrenRecursive and\
               ( ( not car.get("Spoiler") and "Spoiler" in str(attachment) ) or ( car.get("Spoiler") and not attachment )):
                objs.append(car.childrenRecursive["SpoilerProxy"])
                        
            if ray[1]:
                
                point = ray[1]
                d = 10
                c = None
                for obj in objs:
                    od = obj.getDistanceTo(point)
                    if od < d:
                        d = od
                        c = obj

                if c:
                    found = True
                        
                    if c not in car["wheels"]:
                        center = Boxify(c)
                    else:
                        center = Boxify(c, True)

                    text = ""
                    if c in car["wheels"]:
                        text = "Wheel"

                    elif str(c) == "NitroCanProxy":
                        text = "Nitros"

                    elif "Spoiler" in str(c):
                        text = "Spoiler"
                        
                    elif c == car:
                        text = "Engine and Chassis"
                        
                    elif c in car["doors"]:
                        text = "Bodywork"

                    orange = range(len(text))
                    text = text + "\n" + str(int(round(c.get("health", 1.0)*100)))+"%"

                    Script.StatusText(text, orange)

                    # Activate the tool
                    if mousecodes["LMB"] in mouse:

                        FixToolSound()

                        if str(c) == "NitroCanProxy":
                            Vehicle.AddNitroCan(car)
                            dani["tool-attachment"] = None
                            car["nitro"] = 10.0

                        if str(c) == "SpoilerProxy" and attachment:
                            spoilertype = Garage.shop.get(attachment, {}).get("usemodel")
                            Vehicle.AddSpoiler(car, spoilertype)
                            dani["tool-attachment"] = None
                        
                        c["health"] = c.get("health", 1.0) + 0.01
                        if c["health"] >= 1.0:
                            c["health"] = 1.0

                            # Replacing mesh, to looks nice.
                            if c.get("Good"):
                                c.replaceMesh(c.get("Good"))
                                
                            # Doors
                            if c in car["doors"]:
                                c["locked"] = True

                                rot = door.orientation.to_euler()
                                for i in range(3):
                                    if i == door.get("axis",2):
                                        rot[i] = door.get("lockat", 0)
                                    else:
                                        rot[i] = 0
                                c.orientation = rot
                                c.suspendPhysics()
        
                                door.orientation = rot

                            if c == car:
                                Vehicle.ChangeBody(car, good=True)
                                
                        if c == car:
                            car["blown"] = False

                        if c["health"] > 0.1:

                            if not c.visible:
                                dani["tool-attachment"] = None    
                                c.visible = True

                    # Removing parts
                    if mousecodes["RMB"] in mouse:

                        FixToolSound()

                        # Removing spoilers
                        if str(c) == "SpoilerProxy" and not attachment:
                            spoilertype = Vehicle.RemoveSpoiler(car)
                            for name in Garage.shop:
                                item = Garage.shop[name]
                                if item.get("usemodel") == spoilertype:
                                    dani["tool-attachment"] = name
                                    
                        # Removing nitros
                        if str(c) == "NitroCanProxy" and not attachment:
                            Vehicle.RemoveNitroCan(car)
                            dani["tool-attachment"] = "Nitros"

                        # Removing bodywork
                        if c in car["doors"] and not attachment:
                            c["health"] = 0.0
                            c.visible = False
                            dani["tool-attachment"] = "Parts"

                        # Removing wheels
                        elif c in car["wheels"] and not attachment:
                            c["health"] = 0.0
                            c.visible = False
                            dani["tool-attachment"] = "Wheels"

                                    
        # Shelf

        if not found:

            tool = dani["tool"]
        
            closest  = 5
            theitem  = ""
            themodel = None
        
            for name in Garage.inventory:

                amount = Garage.inventory[name]
                item   = Garage.shop.get(name, {})
                model  = item.get('model')
                if model: model= scene.objects[model]
            
                if ( amount  or name == dani.get("tool-attachment") ) and model:

                    d = dani.getDistanceTo(model)
                    if d < closest:
                        closest  = d
                        theitem  = name
                        themodel = model
        
            if themodel:

                name = theitem
                amount = Garage.inventory[name]
                item   = Garage.shop.get(name, {})
                printname = item.get("name", name)

                
                Boxify(themodel)
                Script.StatusText(printname+"\nIn Stock: "+str(amount), range(len(printname)))

                if mousecodes["LMB"] in mouse and not tool.get("active-timer"):
                    tool["active-timer"] = 30

                    print("pressed", dani.get("tool-attachment"))

                    if not dani.get("tool-attachment"):

                        dani["tool-attachment"] = name
                        Garage.Use(name)

                    else:

                        name = dani["tool-attachment"]

                        if name not in Garage.inventory: Garage.inventory[name] = 1
                        else: Garage.inventory[name] += 1
                        Garage.UpdateShelfs()
                        
                        dani["tool-attachment"] = None


                
            
            if tool.get("active-timer"): tool["active-timer"] -= 1

        # Tool attachment
        if dani.get("tool-attachment"):

            name = dani["tool-attachment"]
            item   = Garage.shop.get(name, {})
            usemodel = item.get("usemodel")
            
            if not dani.get("tool-attachment-model") and usemodel:
                
                dani["tool-attachment-model"] = Reuse.Create(usemodel)
                dani["tool-attachment-model"].suspendPhysics()
                dani["tool-attachment-model"].blenderObject["MainColor"]      = [1.000000, 0.008796, 0.000000]
                dani["tool-attachment-model"].blenderObject["SecondaryColor"] = [1.000000, 0.500000, 0.000000]

                s = item.get("usescale", 1)
                dani["tool-attachment-model"].scaling = [s,s,s]
                
                
            else:

                usemodel = dani["tool-attachment-model"]
                usemodel.position = Vehicle.RelativePoint(dani, (-0.5,-0.5,0.5))
                usemodel.applyRotation((0.03,-0.01,0.05),False)

        elif dani.get("tool-attachment-model"):
            Reuse.Delete(dani["tool-attachment-model"])
            dani["tool-attachment-model"] = None
            
                                
    # If dani is using a paint tool
    elif str(dani.get("tool")) == "PaintTool":

        ray = DaniPoint(dani, camera)
        tool = dani["tool"]

        if ray[0] in bge.logic.globalDict["allcars"]:

            car = ray[0]
            Boxify(car)
            if mousecodes["LMB"] in mouse:

                PaintToolSound()
                
                if not tool.get("active-timer"):
                    Vehicle.SmartColor(car, "pallete")
                    tool["active-timer"] = 30

            elif mousecodes["RMB"] in mouse:

                PaintToolSound()
                
                if not tool.get("active-timer"):
                    Vehicle.SmartColor(car)
                    tool["active-timer"] = 30
                    
        if tool.get("active-timer"): tool["active-timer"] -= 1
                            
def UpdateTool(tool):

    
    tool  = tool.owner
    scene = bge.logic.getCurrentScene()
    dani  = scene.objects["Dani_Box"]
    hand  = scene.objects["Tool_Hand"]
    box   = scene.objects["Boxify"]
    icon  = scene.objects["Dani_Tool_Icon"]

    if "taken" not in tool:
        tool["taken"] = None
        tool["wasat"] = tool.position.copy()

    if not tool["taken"]:
    
        if dani.getDistanceTo(tool["wasat"]) < 2 and not tool.get("timer") and not dani.get("tool"):
            tool["taken"] = dani
            tool["timer"] = 100
            dani["tool"]  = tool

            tool.position = hand.position
            tool.orientation = hand.orientation
            tool.setParent(hand, True)

            icon.blenderObject["raw"] = tool.get("icon_raw", 1)
            icon.blenderObject["column"] = tool.get("icon_column", 0)

        tool.applyRotation([0,0,0.1], False)

    elif dani.getDistanceTo(tool["wasat"]) < 2 and not tool.get("timer"):

        tool["taken"] = None
        tool["timer"] = 100
        dani["tool"]  = None
        box.position = [0,0,-1000]

        tool.removeParent()
        
        tool.position = tool["wasat"]
        tool.orientation = [0,0,0]

        Script.StatusText(" ")

        icon.blenderObject["raw"] = 1
        icon.blenderObject["column"] = 0

    if tool.get("timer"): tool["timer"] -= 1

def Boxify(obj, orcenter=False):

    # This function will draw a box around the object
    
    scene = bge.logic.getCurrentScene()
    box = scene.objects["Boxify"]
    box["timer"] = 10

    if not orcenter:
        
        # Finding bounding box
        bbox = obj.blenderObject.bound_box
    
        # finding the center of the box
        center = 0.125 * sum((mathutils.Vector(b) for b in bbox), mathutils.Vector())
        
        center.rotate(obj.orientation)
        center * obj.scaling
        center = obj.position + center
        box.position    = center

        
    else:
        box.position    = obj.position
        center = obj.position
    box.orientation = obj.orientation
    box.scaling     = obj.blenderObject.dimensions
    

    return center

def DaniPoint(dani, camera):

    # Then we want to see if any of them are pointed at
    fro = dani.position.copy()
    fro.z += 1

    to = fro.copy()
    to.z -= 1
    to -= fro
    to.rotate(camera.worldOrientation.to_euler())
    to += fro

    ray = Vehicle.BeautyRayCast(dani, "tool", to, fro, dist=5)

    return ray


#### SOUNDS #####

def FixToolSound():

    # Engine Sound
    
    device = bge.logic.globalDict["SoundDevice"]

    code = "//sfx/fixtool.ogg"
    if code not in bge.logic.globalDict["sounds"]:
        bge.logic.globalDict["sounds"][code] = {"sound":aud.Sound(bge.logic.expandPath(code)),
                                             "play":None}
    
    sound = bge.logic.globalDict["sounds"][code]

    if not sound["play"] or not sound["play"].status:
        sound["play"] =  device.play(sound["sound"])
        
    sound["play"].volume = 1

def PaintToolSound():

    # Engine Sound
    
    device = bge.logic.globalDict["SoundDevice"]

    code = "//sfx/painttool.ogg"
    if code not in bge.logic.globalDict["sounds"]:
        bge.logic.globalDict["sounds"][code] = {"sound":aud.Sound(bge.logic.expandPath(code)),
                                             "play":None}
    
    sound = bge.logic.globalDict["sounds"][code]

    if not sound["play"] or not sound["play"].status:
        sound["play"] =  device.play(sound["sound"])
        
    sound["play"].volume = 1