//
//  flashlight.js
//
//  Script Type: Entity
//
//  Created by Sam Gateau on 9/9/15.
//  Additions by James B. Pollack @imgntn on 9/21/2015
//  Copyright 2015 High Fidelity, Inc.
//
//  This is a toy script that can be added to the Flashlight model entity:
//  "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx"
//  that creates a spotlight attached with the flashlight model while the entity is grabbed
//
//  Distributed under the Apache License, Version 2.0.
//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//

(function() {

    var ON_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_on.wav';
    var OFF_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_off.wav';

    //we are creating lights that we don't want to get stranded so lets make sure that we can get rid of them
    //if you're going to be using this in a dungeon or something and holding it for a long time, increase this lifetime value.
    var LIFETIME = 100;


    // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember
    // our this object, so we can access it in cases where we're called without a this (like in the case of various global signals)
    function Flashlight() {
        return;
    }

    //if the trigger value goes below this while held, the flashlight will turn off.  if it goes above, it will 
    var DISABLE_LIGHT_THRESHOLD = 0.7;

    // These constants define the Spotlight position and orientation relative to the model 
    var MODEL_LIGHT_POSITION = {
        x: 0,
        y: -0.3,
        z: 0
    };
    var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, {
        x: 1,
        y: 0,
        z: 0
    });

    //there's another small point light we put at the end of the flashlight to make the end glow

    var GLOW_LIGHT_POSITION = {
        x: 0,
        y: -0.1,
        z: 0
    };

    // Evaluate the world light entity positions and orientations from the model ones
    function evalLightWorldTransform(modelPosition, modelRotation) {

        return {
            p: Vec3.sum(modelPosition, Vec3.multiplyQbyV(modelRotation, MODEL_LIGHT_POSITION)),
            q: Quat.multiply(modelRotation, MODEL_LIGHT_ROTATION)
        };
    }

    function glowLightWorldTransform(modelPosition, modelRotation) {
        return {
            p: Vec3.sum(modelPosition, Vec3.multiplyQbyV(modelRotation, GLOW_LIGHT_POSITION)),
            q: Quat.multiply(modelRotation, MODEL_LIGHT_ROTATION)
        };
    }

    Flashlight.prototype = {
        lightOn: false,
        hand: null,
        whichHand: null,
        hasSpotlight: false,
        spotlight: null,

        startNearGrab: function(entityID, args) {
            //this first second parameter in this method contains arguments from the grab script, the first of which is the 'hand' that was used to start the grab
            this.hand = args[0];
            if (!this.hasSpotlight) {

                var modelProperties = Entities.getEntityProperties(this.entityID, ['position', 'rotation']);
                var lightTransform = evalLightWorldTransform(modelProperties.position, modelProperties.rotation);
                var glowLightTransform = glowLightWorldTransform(modelProperties.position, modelProperties.rotation);


                //this light casts the beam
                this.spotlight = Entities.addEntity({
                    type: "Light",
                    isSpotlight: true,
                    dimensions: {
                        x: 2,
                        y: 2,
                        z: 20
                    },
                    parentID: this.entityID,
                    color: {
                        red: 255,
                        green: 255,
                        blue: 255
                    },
                    intensity:  1,
                    falloffRadius:0.9,
                    exponent: 0.5,
                    cutoff: 20,
                    lifetime: LIFETIME,
                    position: lightTransform.p,
                    rotation: lightTransform.q,
                });

                //this light creates the effect of a bulb at the end of the flashlight
                this.glowLight = Entities.addEntity({
                    type: "Light",
                    dimensions: {
                        x: 0.25,
                        y: 0.25,
                        z: 0.25
                    },
                    parentID: this.entityID,
                    isSpotlight: false,
                    color: {
                        red: 255,
                        green: 255,
                        blue: 255
                    },
                    exponent: 0,
                    intensity:1.0,
                    falloffRadius:0.3,
                    lifetime: LIFETIME,
                    cutoff: 90, // in degrees
                    position: glowLightTransform.p,
                    rotation: glowLightTransform.q,

                });

                this.hasSpotlight = true;

            }

        },
        startEquip: function(id, params) {
            this.startNearGrab(id, params);
        },

        setWhichHand: function() {
            this.whichHand = this.hand;
        },

        continueNearGrab: function() {
            if (this.whichHand === null) {
                //only set the active hand once -- if we always read the current hand, our 'holding' hand will get overwritten
                this.setWhichHand();
            } else {
                this.changeLightWithTriggerPressure(this.whichHand);
            }
        },
        continueEquip: function(entityID, args) {
            this.continueNearGrab(entityID, args);
        },

        releaseGrab: function(entityID, args) {
            //delete the lights and reset state
            if (this.hasSpotlight) {
                Entities.deleteEntity(this.spotlight);
                Entities.deleteEntity(this.glowLight);
                this.hasSpotlight = false;
                this.glowLight = null;
                this.spotlight = null;
                this.whichHand = null;
                this.lightOn = false;
            }
        },

        releaseEquip: function(entityID, args) {
            this.releaseGrab(entityID, args);
        },
        
        changeLightWithTriggerPressure: function(flashLightHand) {
            //read the value of the controller trigger and use it to turn the light on / off when the value reaches certain thresholds
            if (flashLightHand === 'LEFT') {
                this.triggerValue = Controller.getValue(Controller.Standard.LT);
            }
            if (flashLightHand === 'RIGHT') {
                this.triggerValue = Controller.getValue(Controller.Standard.RT);

            }

            if (this.triggerValue < DISABLE_LIGHT_THRESHOLD && this.lightOn === true) {
                this.turnLightOff();
            } else if (this.triggerValue >= DISABLE_LIGHT_THRESHOLD && this.lightOn === false) {
                this.turnLightOn();
            }
            return;
        },

        turnLightOff: function() {
            this.playSoundAtCurrentPosition(false);
            Entities.editEntity(this.spotlight, {
                intensity: 0
            });
            Entities.editEntity(this.glowLight, {
                intensity: 0
            });
            this.lightOn = false;
        },

        turnLightOn: function() {
            this.playSoundAtCurrentPosition(true);

            Entities.editEntity(this.glowLight, {
                intensity: 2
            });
            Entities.editEntity(this.spotlight, {
                intensity: 2
            });
            this.lightOn = true;
        },

        playSoundAtCurrentPosition: function(playOnSound) {
            //when someone grabs, play a clicking noise for turning the flashlight on/off
            var position = Entities.getEntityProperties(this.entityID, "position").position;

            var audioProperties = {
                volume: 0.25,
                position: position
            };

            if (playOnSound) {
                Audio.playSound(this.ON_SOUND, audioProperties);
            } else {
                Audio.playSound(this.OFF_SOUND, audioProperties);
            }
        },

        preload: function(entityID) {
            //  preload() will be called when the entity has become visible (or known) to the interface
            //  it gives us a chance to set our local JavaScript object up. In this case it means:
            //  * remembering our entityID, so we can access it in cases where we're called without an entityID
            //  * preloading sounds
            this.entityID = entityID;
            this.ON_SOUND = SoundCache.getSound(ON_SOUND_URL);
            this.OFF_SOUND = SoundCache.getSound(OFF_SOUND_URL);

        },

        unload: function() {
            // unload() will be called when our entity is no longer available. It may be because we were deleted,
            // or because we've left the domain or quit the application.
            if (this.hasSpotlight) {
                Entities.deleteEntity(this.spotlight);
                Entities.deleteEntity(this.glowLight);
                this.hasSpotlight = false;
                this.glowLight = null;
                this.spotlight = null;
                this.whichHand = null;
                this.lightOn = false;
            }

        },

    };

    // entity should return a newly constructed object of our type
    return new Flashlight();
});