//  ambientSound.js
//
//  This entity script will allow you to create an ambient sound that loops when a person is within a given
//  range of this entity.  Great way to add one or more ambisonic soundfields to your environment.  
//
//  In the userData section for the entity, add/edit three values:  
//      userData.soundURL should be a string giving the URL to the sound file.  Defaults to 100 meters if not set.  
//      userData.range should be an integer for the max distance away from the entity where the sound will be audible.
//      userData.volume is the max volume at which the clip should play.  Defaults to 1.0 full volume)
//
//  The rotation of the entity is copied to the ambisonic field, so by rotating the entity you will rotate the 
//  direction in-which a certain sound comes from.  
//  
//  Remember that the entity has to be visible to the user for the sound to play at all, so make sure the entity is
//  large enough to be loaded at the range you set, particularly for large ranges.  
//   
//  Copyright 2016 High Fidelity, Inc.
//
//  Distributed under the Apache License, Version 2.0.
//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//

(function(){ 
    //  This sample clip and range will be used if you don't add userData to the entity (see above)
    var DEFAULT_RANGE = 100;
    var DEFAULT_URL = "http://hifi-content.s3.amazonaws.com/ken/samples/forest_ambiX.wav";
    var DEFAULT_VOLUME = 1.0;

    var soundURL = "";
    var range = DEFAULT_RANGE;
    var maxVolume = DEFAULT_VOLUME;
    var UPDATE_INTERVAL_MSECS = 100;
    var rotation;

    var entity;
    var ambientSound;
    var center;
    var soundPlaying = false;
    var checkTimer = false;
    var _this;

    var WANT_COLOR_CHANGE = false;
    var COLOR_OFF = { red: 128, green: 128, blue: 128 };
    var COLOR_ON = { red: 255, green: 0, blue: 0 };

    var WANT_DEBUG = false;
    function debugPrint(string) {
        if (WANT_DEBUG) {
            print(string);
        }
    }

    this.updateSettings = function() {
        //  Check user data on the entity for any changes
        var oldSoundURL = soundURL;
        var props = Entities.getEntityProperties(entity, [ "userData" ]);
        if (props.userData) {
            var data = JSON.parse(props.userData);
            if (data.soundURL && !(soundURL === data.soundURL)) {
                soundURL = data.soundURL;
                debugPrint("Read ambient sound URL: " + soundURL);    
            } else if (!data.soundURL) {
                soundURL = DEFAULT_URL;
            }
            if (data.range && !(range === data.range)) {
                range = data.range;
                debugPrint("Read ambient sound range: " + range);
            }
            if (data.volume && !(maxVolume === data.volume)) {
                maxVolume = data.volume;
                debugPrint("Read ambient sound volume: " + maxVolume);
            }
        }
        if (!(soundURL === oldSoundURL) || (soundURL === "")) {
            debugPrint("Loading ambient sound into cache");
            ambientSound = SoundCache.getSound(soundURL);
            if (soundPlaying && soundPlaying.playing) {
                soundPlaying.stop();
                soundPlaying = false;
                if (WANT_COLOR_CHANGE) {
                    Entities.editEntity(entity, { color: COLOR_OFF });
                }
                debugPrint("Restarting ambient sound");
            }
        }   
    }

    this.preload = function(entityID) { 
        //  Load the sound and range from the entity userData fields, and note the position of the entity.
        debugPrint("Ambient sound preload");
        entity = entityID;
        _this = this;
        checkTimer = Script.setInterval(this.maybeUpdate, UPDATE_INTERVAL_MSECS);
    }; 

    this.maybeUpdate = function() {
        // Every UPDATE_INTERVAL_MSECS, update the volume of the ambient sound based on distance from my avatar
        _this.updateSettings();
        var HYSTERESIS_FRACTION = 0.1;
        var props = Entities.getEntityProperties(entity, [ "position", "rotation" ]);
        center = props.position;
        rotation = props.rotation;
        var distance = Vec3.length(Vec3.subtract(MyAvatar.position, center));
        if (distance <= range) {
            var volume = (1.0 - distance / range) * maxVolume;
            if (!soundPlaying && ambientSound.downloaded) {
                soundPlaying = Audio.playSound(ambientSound,  { loop: true, 
                                                                localOnly: true, 
                                                                orientation: rotation,
                                                                volume: volume });
                debugPrint("Starting ambient sound, volume: " + volume);
                if (WANT_COLOR_CHANGE) {
                    Entities.editEntity(entity, { color: COLOR_ON });
                }
                
            } else if (soundPlaying && soundPlaying.playing) {
                soundPlaying.setOptions( { volume: volume, orientation: rotation } );
            }

        } else if (soundPlaying && soundPlaying.playing && (distance > range * HYSTERESIS_FRACTION)) {
            soundPlaying.stop();
            soundPlaying = false;
            Entities.editEntity(entity, { color: { red: 128, green: 128, blue: 128 }});
            debugPrint("Out of range, stopping ambient sound");
        }
    }

    this.unload = function(entityID) { 
        debugPrint("Ambient sound unload");
        if (checkTimer) {
            Script.clearInterval(checkTimer);
        }
        if (soundPlaying && soundPlaying.playing) {
            soundPlaying.stop();
        }
    }; 

})