/* This file is part of MusicalRegions for Bukkit, licensed under the MIT License (MIT).
 *
 * Copyright (c) JCThePants (www.jcwhatever.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */


package com.jcwhatever.musical.regions;

import com.jcwhatever.musical.Msg;
import com.jcwhatever.musical.MusicalRegions;
import com.jcwhatever.nucleus.regions.Region;
import com.jcwhatever.nucleus.sounds.PlayList;
import com.jcwhatever.nucleus.sounds.PlayList.PlayerSoundQueue;
import com.jcwhatever.nucleus.sounds.ResourceSound;
import com.jcwhatever.nucleus.sounds.SoundManager;
import com.jcwhatever.nucleus.storage.IDataNode;
import com.jcwhatever.nucleus.utils.CollectionUtils;

import org.bukkit.entity.Player;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * A region that plays sounds to players that enter.
 */
public class MusicRegion extends Region {

    private PlayList _playList;

    /**
     * Constructor.
     *
     * @param name      The name of the region.
     * @param dataNode  The regions data node.
     */
    public MusicRegion(String name, IDataNode dataNode) {
        super(MusicalRegions.getPlugin(), name, dataNode);

        setEventListener(true);

        load();
    }

    /**
     * Get the regions playlist.
     */
    public PlayList getPlayList() {
        return _playList;
    }

    /**
     * Erase the regions playlist and replace with a single resource sound.
     *
     * @param sound  The resource sound.
     */
    public void setSound(ResourceSound sound) {
        _playList.clearSounds();
        _playList.addSound(sound);

        IDataNode dataNode = getDataNode();
        assert dataNode != null;

        dataNode.set("sounds", _playList.getSounds());
        dataNode.save();
    }

    /**
     * Erase the regions playlist and replace with the specified
     * resource sounds.
     *
     * @param sounds  The resource sounds.
     */
    public void setSound(Collection<ResourceSound> sounds) {

        _playList.clearSounds();
        _playList.addSounds(sounds);

        IDataNode dataNode = getDataNode();
        assert dataNode != null;

        dataNode.set("sounds", _playList.getSounds());
        dataNode.save();
    }

    /**
     * Determine if the regions playlist plays in a loop.
     */
    public boolean isLoop() {
        return _playList.isLoop();
    }

    /**
     * Enable or disable playlist looping for the region.
     *
     * @param isLoop  True to enable, false to disable.
     */
    public void setLoop(boolean isLoop) {
        _playList.setLoop(isLoop);
    }

    @Override
    protected void onPlayerEnter(Player p, EnterRegionReason reason) {
        _playList.addPlayer(p);
    }

    @Override
    protected boolean canDoPlayerEnter(Player p, EnterRegionReason reason) {

        PlayerSoundQueue queue = _playList.getSoundQueue(p);
        return queue == null && super.canDoPlayerEnter(p, reason);
    }

    @Override
    protected void onPlayerLeave(Player p, LeaveRegionReason reason) {
        if (!p.getWorld().equals(this.getWorld()))
            _playList.removePlayer(p);
    }

    private void load() {

        IDataNode dataNode = getDataNode();

        assert dataNode != null;

        boolean isLoop = dataNode.getBoolean("loop");

        //noinspection unchecked
        List<String> soundNames = dataNode.getStringList("sounds", CollectionUtils.UNMODIFIABLE_EMPTY_LIST);
        assert soundNames != null;

        List<ResourceSound> sounds = new ArrayList<>(soundNames.size());

        for (String soundName : soundNames) {

            ResourceSound sound = SoundManager.getSound(soundName.trim());
            if (sound == null)
                Msg.debug("Failed to find resource sound '{0}' for musical region '{1}'", soundName, getName());

            sounds.add(sound);
        }

        _playList = new PlayList(MusicalRegions.getPlugin(), sounds);
        _playList.setLoop(isLoop);
        _playList.setLocation(getCenter());
        _playList.setVolume(Math.max(1, (Math.max(getXBlockWidth(), getZBlockWidth())) / 16));
    }
}
@@ -1686,25 +1686,145 @@
 ils.
-CollectionUtils;%0A
+ArrayUtils;%0Aimport com.jcwhatever.nucleus.utils.CollectionUtils;%0Aimport com.jcwhatever.nucleus.utils.PreCon;%0A%0Aimport org.bukkit.Location;
 %0Aimp
@@ -1933,16 +1933,50 @@
 il.List;
+%0Aimport javax.annotation.Nullable;
 %0A%0A/**%0A *
@@ -2736,224 +2736,73 @@
     
-_playList.clearSounds();%0A        _playList.addSound(sound);%0A%0A        IDataNode dataNode = getDataNode();%0A        assert dataNode != null;%0A%0A        dataNode.set(%22sounds%22, _playList.getSounds());%0A        dataNode.save(
+PreCon.notNull(sound);%0A%0A        setSound(ArrayUtils.asList(sound)
 );%0A 
@@ -3018,24 +3018,56 @@
 d%3E sounds) %7B
+%0A        PreCon.notNull(sounds);
 %0A%0A        _p
@@ -3197,32 +3197,200 @@
 aNode != null;%0A%0A
+        List%3CString%3E soundNames = new ArrayList%3C%3E(sounds.size());%0A%0A        for (ResourceSound sound : sounds) %7B%0A            soundNames.add(sound.getName());%0A        %7D%0A%0A
         dataNode
@@ -3408,29 +3408,18 @@
 s%22, 
-_playList.getSounds()
+soundNames
 );%0A 
@@ -4345,24 +4345,327 @@
 (p);%0A    %7D%0A%0A
+    @Override%0A    protected void onCoordsChanged(@Nullable Location p1, @Nullable Location p2) %7B%0A%0A        if (p1 == null %7C%7C p2 == null)%0A            return;%0A%0A        _playList.setLocation(getCenter());%0A        _playList.setVolume(Math.max(1, (Math.max(getXBlockWidth(), getZBlockWidth())) / 16));%0A    %7D%0A%0A
     private 

fix incorrectly saving resource sound instance instead of name