package nl.rutgerkok.blocklocker.impl.protection;

import java.util.Arrays;
import java.util.Collection;

import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Openable;

import nl.rutgerkok.blocklocker.OpenBlockSound;
import nl.rutgerkok.blocklocker.ProtectionSign;
import nl.rutgerkok.blocklocker.impl.blockfinder.BlockFinder;
import nl.rutgerkok.blocklocker.protection.AttachedProtection;
import nl.rutgerkok.blocklocker.protection.Protection;

/**
 * Implementation of {@link AttachedProtection}.
 *
 */
public final class AttachedProtectionImpl extends AbstractProtection implements AttachedProtection {

    /**
     * Gets a door protection from a door, with only a single sign looked up.
     *
     * @param sign
     *            A hint. If it is a main sign, the owner can easily be looked
     *            up, speeding up {@link #getOwner()}.
     * @param blockFinder
     *            The block finder.
     * @param protectionBlock
     *            The door.
     *
     * @return The door protection object.
     */
    public static Protection fromBlockWithSign(ProtectionSign sign, BlockFinder blockFinder, Block protectionBlock) {
        return new AttachedProtectionImpl(sign, blockFinder, protectionBlock);
    }

    /**
     * Creates a new protection for a door, with all signs looked up.
     *
     * @param signs
     *            All signs of the protection. Collection may not be empty.
     * @param blockFinder
     *            The block finder.
     * @param trapDoor
     *            The door that is protected.
     * @return The protection.
     */
    public static Protection fromBlockWithSigns(Collection<ProtectionSign> signs, BlockFinder blockFinder, Block trapDoor) {
        return new AttachedProtectionImpl(signs, blockFinder, trapDoor);
    }

    private final BlockFinder blockFinder;
    private final Block protectionBlock;

    private AttachedProtectionImpl(Collection<ProtectionSign> signs, BlockFinder blockFinder, Block trapDoor) {
        super(signs);
        this.protectionBlock = trapDoor;
        this.blockFinder = blockFinder;
    }

    private AttachedProtectionImpl(ProtectionSign sign, BlockFinder blockFinder, Block trapDoor) {
        super(sign);
        this.protectionBlock = trapDoor;
        this.blockFinder = blockFinder;
    }

    @Override
    public boolean canBeOpened() {
        return protectionBlock.getBlockData() instanceof Openable;
    }

    @Override
    protected Collection<ProtectionSign> fetchSigns() {
        Block supportingBlock = blockFinder.findSupportingBlock(protectionBlock);
        return blockFinder.findAttachedSigns(Arrays.asList(protectionBlock, supportingBlock));
    }

    @Override
    public boolean isOpen() {
        BlockData materialData = protectionBlock.getBlockData();
        if (materialData instanceof Openable) {
            return ((Openable) materialData).isOpen();
        }
        return false;
    }

    @Override
    public void setOpen(boolean open) {
        setOpen(open, SoundCondition.NEVER);
    }

    @Override
    public void setOpen(boolean open, SoundCondition playSound) {
        BlockData materialData = protectionBlock.getBlockData();
        if (!(materialData instanceof Openable)) {
            return;
        }

        Openable openable = (Openable) materialData;

        if (openable.isOpen() == open) {
            return;
        }

        openable.setOpen(open);
        protectionBlock.setBlockData(materialData);

        if (playSound == SoundCondition.ALWAYS) {
            Sound sound = OpenBlockSound.get(materialData.getMaterial(), open);
            protectionBlock.getWorld().playSound(protectionBlock.getLocation(), sound, 1f, 0.7f);
        }
    }

}

@@ -1850,32 +1850,428 @@
 apDoor);%0A    %7D%0A%0A
+    private static void setBlockOpen(Block block, boolean open) %7B%0A        BlockData blockData = block.getBlockData();%0A        if (!(blockData instanceof Openable)) %7B%0A            return;%0A        %7D%0A        Openable openable = (Openable) blockData;%0A%0A        if (openable.isOpen() == open) %7B%0A            return;%0A        %7D%0A%0A        openable.setOpen(open);%0A        block.setBlockData(blockData);%0A    %7D%0A
     private fina
@@ -2293,24 +2293,25 @@
 lockFinder;%0A
+%0A
     private 
@@ -3596,354 +3596,169 @@
     
+set
 Block
-Data materialData = protectionBlock.getBlockData();%0A        if (!(materialData instanceof Openable)) %7B%0A            return;%0A        %7D%0A%0A        Openable openable = (Openable) materialData;%0A%0A        if (openable.isOpen() == open) %7B%0A            return;%0A        %7D%0A%0A        openable.setOpen(open);%0A        protectionBlock.setBlockData(materialData
+Open(protectionBlock, open);%0A        Block supportingBlock = blockFinder.findSupportingBlock(protectionBlock);%0A        setBlockOpen(supportingBlock, open
 );%0A%0A
@@ -3803,16 +3803,36 @@
 n.ALWAYS
+ && isOpen() != open
 ) %7B%0A    
@@ -3876,32 +3876,31 @@
 get(
-materialData.getMaterial
+protectionBlock.getType
 (), 

Fix fence gates placed on top of each other opening in a strange way