/FileExtraction/Java_unseen/Wind-Development_WindSpigot/WindSpigot-API/src/main/java/org/bukkit/material/Door.java
package org.bukkit.material;

import org.bukkit.Material;
import org.bukkit.TreeSpecies;
import org.bukkit.block.BlockFace;

/**
 * Represents a door.
 *
 * This class was previously deprecated, but has been retrofitted to work with
 * modern doors. Some methods are undefined dependant on
 * <code>isTopHalf()</code> due to Minecraft's internal representation of doors.
 *
 * @see Material.WOODEN_DOOR
 * @see Material.IRON_DOOR_BLOCK
 * @see Material.SPRUCE_DOOR
 * @see Material.BIRCH_DOOR
 * @see Material.JUNGLE_DOOR
 * @see Material.ACACIA_DOOR
 * @see Material.DARK_OAK_DOOR
 */
public class Door extends MaterialData implements Directional, Openable {

	// This class breaks API contracts on Directional and Openable because
	// of the way doors are currently implemented. Beware!

	/**
	 * @deprecated Artifact of old API, equivalent to new
	 *             <code>Door(Material.WOODEN_DOOR);</code>
	 */
	@Deprecated
	public Door() {
		super(Material.WOODEN_DOOR);
	}

	/**
	 * @param type the raw type id
	 * @deprecated Magic value
	 */
	@Deprecated
	public Door(final int type) {
		super(type);
	}

	public Door(final Material type) {
		super(type);
	}

	/**
	 * Constructs the bottom half of a door of the given material type, facing the
	 * specified direction and set to closed
	 *
	 * @param type The type of material this door is made of. This must match the
	 *             type of the block above.
	 * @param face The direction the door is facing.
	 *
	 * @see Material.WOODEN_DOOR
	 * @see Material.IRON_DOOR_BLOCK
	 * @see Material.SPRUCE_DOOR
	 * @see Material.BIRCH_DOOR
	 * @see Material.JUNGLE_DOOR
	 * @see Material.ACACIA_DOOR
	 * @see Material.DARK_OAK_DOOR
	 *
	 * @see BlockFace.WEST
	 * @see BlockFace.NORTH
	 * @see BlockFace.EAST
	 * @see BlockFace.SOUTH
	 */
	public Door(final Material type, BlockFace face) {
		this(type, face, false);
	}

	/**
	 * Constructs the bottom half of a door of the given material type, facing the
	 * specified direction and set to open or closed
	 *
	 * @param type   The type of material this door is made of. This must match the
	 *               type of the block above.
	 * @param face   The direction the door is facing.
	 * @param isOpen Whether the door is currently opened.
	 *
	 * @see Material.WOODEN_DOOR
	 * @see Material.IRON_DOOR_BLOCK
	 * @see Material.SPRUCE_DOOR
	 * @see Material.BIRCH_DOOR
	 * @see Material.JUNGLE_DOOR
	 * @see Material.ACACIA_DOOR
	 * @see Material.DARK_OAK_DOOR
	 *
	 * @see BlockFace.WEST
	 * @see BlockFace.NORTH
	 * @see BlockFace.EAST
	 * @see BlockFace.SOUTH
	 */
	public Door(final Material type, BlockFace face, boolean isOpen) {
		super(type);
		setTopHalf(false);
		setFacingDirection(face);
		setOpen(isOpen);
	}

	/**
	 * Constructs the top half of door of the given material type and with the hinge
	 * on the left or right
	 *
	 * @param type         The type of material this door is made of. This must
	 *                     match the type of the block below.
	 * @param isHingeRight True if the hinge is on the right hand side, false if the
	 *                     hinge is on the left hand side.
	 *
	 * @see Material.WOODEN_DOOR
	 * @see Material.IRON_DOOR_BLOCK
	 * @see Material.SPRUCE_DOOR
	 * @see Material.BIRCH_DOOR
	 * @see Material.JUNGLE_DOOR
	 * @see Material.ACACIA_DOOR
	 * @see Material.DARK_OAK_DOOR
	 */
	public Door(final Material type, boolean isHingeRight) {
		super(type);
		setTopHalf(true);
		setHinge(isHingeRight);
	}

	/**
	 * Constructs the bottom half of a wooden door of the given species, facing the
	 * specified direction and set to closed
	 *
	 * @param species The species this wooden door is made of. This must match the
	 *                species of the block above.
	 * @param face    The direction the door is facing.
	 *
	 * @see TreeSpecies
	 *
	 * @see BlockFace.WEST
	 * @see BlockFace.NORTH
	 * @see BlockFace.EAST
	 * @see BlockFace.SOUTH
	 */
	public Door(final TreeSpecies species, BlockFace face) {
		this(getWoodDoorOfSpecies(species), face, false);
	}

	/**
	 * Constructs the bottom half of a wooden door of the given species, facing the
	 * specified direction and set to open or closed
	 *
	 * @param species The species this wooden door is made of. This must match the
	 *                species of the block above.
	 * @param face    The direction the door is facing.
	 * @param isOpen  Whether the door is currently opened.
	 *
	 * @see TreeSpecies
	 *
	 * @see BlockFace.WEST
	 * @see BlockFace.NORTH
	 * @see BlockFace.EAST
	 * @see BlockFace.SOUTH
	 */
	public Door(final TreeSpecies species, BlockFace face, boolean isOpen) {
		this(getWoodDoorOfSpecies(species), face, isOpen);
	}

	/**
	 * Constructs the top half of a wooden door of the given species and with the
	 * hinge on the left or right
	 *
	 * @param species      The species this wooden door is made of. This must match
	 *                     the species of the block below.
	 * @param isHingeRight True if the hinge is on the right hand side, false if the
	 *                     hinge is on the left hand side.
	 *
	 * @see TreeSpecies
	 */
	public Door(final TreeSpecies species, boolean isHingeRight) {
		this(getWoodDoorOfSpecies(species), isHingeRight);
	}

	/**
	 * @param type the raw type id
	 * @param data the raw data value
	 * @deprecated Magic value
	 */
	@Deprecated
	public Door(final int type, final byte data) {
		super(type, data);
	}

	/**
	 * @param type the type
	 * @param data the raw data value
	 * @deprecated Magic value
	 */
	@Deprecated
	public Door(final Material type, final byte data) {
		super(type, data);
	}

	/**
	 * Returns the item type of a wooden door for the given tree species.
	 *
	 * @param species The species of wood door required.
	 * @return The item type for the given species.
	 *
	 * @see Material.WOODEN_DOOR
	 * @see Material.SPRUCE_DOOR
	 * @see Material.BIRCH_DOOR
	 * @see Material.JUNGLE_DOOR
	 * @see Material.ACACIA_DOOR
	 * @see Material.DARK_OAK_DOOR
	 */
	public static Material getWoodDoorOfSpecies(TreeSpecies species) {
		switch (species) {
		default:
		case GENERIC:
			return Material.WOODEN_DOOR;
		case BIRCH:
			return Material.BIRCH_DOOR;
		case REDWOOD:
			return Material.SPRUCE_DOOR;
		case JUNGLE:
			return Material.JUNGLE_DOOR;
		case ACACIA:
			return Material.ACACIA_DOOR;
		case DARK_OAK:
			return Material.DARK_OAK_DOOR;
		}
	}

	/**
	 * Result is undefined if <code>isTopHalf()</code> is true.
	 */
	public boolean isOpen() {
		return ((getData() & 0x4) == 0x4);
	}

	/**
	 * Set whether the door is open. Undefined if <code>isTopHalf()</code> is true.
	 */
	public void setOpen(boolean isOpen) {
		setData((byte) (isOpen ? (getData() | 0x4) : (getData() & ~0x4)));
	}

	/**
	 * @return whether this is the top half of the door
	 */
	public boolean isTopHalf() {
		return ((getData() & 0x8) == 0x8);
	}

	/**
	 * Configure this part of the door to be either the top or the bottom half
	 *
	 * @param isTopHalf True to make it the top half.
	 */
	public void setTopHalf(boolean isTopHalf) {
		setData((byte) (isTopHalf ? (getData() | 0x8) : (getData() & ~0x8)));
	}

	/**
	 * @return BlockFace.SELF
	 * @deprecated This method should not be used; use hinge and facing accessors
	 *             instead.
	 */
	@Deprecated
	public BlockFace getHingeCorner() {
		return BlockFace.SELF;
	}

	@Override
	public String toString() {
		return (isTopHalf() ? "TOP" : "BOTTOM") + " half of " + super.toString();
	}

	/**
	 * Set the direction that this door should is facing.
	 *
	 * Undefined if <code>isTopHalf()</code> is true.
	 *
	 * @param face the direction
	 */
	public void setFacingDirection(BlockFace face) {
		byte data = (byte) (getData() & 0xC);
		switch (face) {
		case WEST:
			data |= 0x0;
			break;
		case NORTH:
			data |= 0x1;
			break;
		case EAST:
			data |= 0x2;
			break;
		case SOUTH:
			data |= 0x3;
			break;
		}
		setData(data);
	}

	/**
	 * Get the direction that this door is facing.
	 *
	 * Undefined if <code>isTopHalf()</code> is true.
	 *
	 * @return the direction
	 */
	public BlockFace getFacing() {
		byte data = (byte) (getData() & 0x3);
		switch (data) {
		case 0:
			return BlockFace.WEST;
		case 1:
			return BlockFace.NORTH;
		case 2:
			return BlockFace.EAST;
		case 3:
			return BlockFace.SOUTH;
		default:
			throw new IllegalStateException("Unknown door facing (data: " + data + ")");
		}
	}

	/**
	 * Returns the side of the door the hinge is on.
	 *
	 * Undefined if <code>isTopHalf()</code> is false.
	 *
	 * @return false for left hinge, true for right hinge
	 */
	public boolean getHinge() {
		return (getData() & 0x1) == 1;
	}

	/**
	 * Set whether the hinge is on the left or right side. Left is false, right is
	 * true.
	 *
	 * Undefined if <code>isTopHalf()</code> is false.
	 *
	 * @param isHingeRight True if the hinge is on the right hand side, false if the
	 *                     hinge is on the left hand side.
	 */
	public void setHinge(boolean isHingeRight) {
		setData((byte) (isHingeRight ? (getData() | 0x1) : (getData() & ~0x1)));
	}

	@Override
	public Door clone() {
		return (Door) super.clone();
	}
}
