package de.minestar.therock.data;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;

public class BlockVector implements Comparable<BlockVector> {
    private final int x, y, z;
    private String worldName;
    private int hashCode = Integer.MIN_VALUE;
    private Location location = null;
    private int TypeID;
    private Material Type;
    private byte subData;
    private String extraData = null;

    /**
     * Constructor
     * 
     * @param the
     *            x
     * @param the
     *            y
     * @param the
     *            z
     */
    public BlockVector(String worldName, int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
        this.worldName = worldName;
    }

    public void setExtraData(String extraData) {
        this.extraData = extraData;
    }

    public String getExtraData() {
        return this.extraData;
    }

    /**
     * Constructor
     * 
     * @param the
     *            location
     */
    public BlockVector(Location location) {
        this(location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ());
        this.location = location;
    }
    /**
     * @return the location
     */
    public Location getLocation() {
        if (this.location == null) {
            World world = Bukkit.getWorld(this.worldName);
            if (world != null) {
                this.location = new Location(world, this.x, this.y, this.z);
            }
        }
        return this.location;
    }

    /**
     * @return the x
     */
    public int getX() {
        return x;
    }

    /**
     * @return the y
     */
    public int getY() {
        return y;
    }

    /**
     * @return the z
     */
    public int getZ() {
        return z;
    }

    /**
     * @return the worldName
     */
    public String getWorldName() {
        return worldName;
    }

    public int getTypeID() {
        return TypeID;
    }

    public Material getType() {
        return Type;
    }
    
    public void setType(Material type) {
        Type = type;
    }
    
    public void setTypeID(int typeID) {
        TypeID = typeID;
    }

    public byte getSubData() {
        return subData;
    }

    public void setSubData(byte subData) {
        this.subData = subData;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this)
            return true;

        if (obj instanceof BlockVector) {
            return this.equals((BlockVector) obj);
        }

        return false;
    }

    /**
     * Create a BlockVector from a given string. The string must have the same syntax as <code>@toString()</code>
     * 
     * @param string
     * @return the BlockVector for this string, or null if it fails
     */
    public static BlockVector fromString(String string) {
        BlockVector vector = null;
        try {
            string = string.replace(" ", "").replace("BlockVector={", "").replace("}", "");
            String[] split = string.split(";");
            vector = new BlockVector(split[0], Integer.valueOf(split[1]), Integer.valueOf(split[2]), Integer.valueOf(split[3]));
        } catch (Exception e) {
            vector = null;
        }
        return vector;
    }

    /**
     * Returns a new BlockVector that is relative to this BlockVector with the given positions
     * 
     * @param x
     * @param y
     * @param z
     * @return the relative BlockVector
     */
    public BlockVector getRelative(int x, int y, int z) {
        return new BlockVector(this.worldName, this.x + x, this.y + y, this.z + z);
    }

    /**
     * Check if another BlockVector equals this BlockVector
     * 
     * @param other
     * @return <b>true</b> if the vectors are equal, otherwise <b>false</b>
     */
    public boolean equals(BlockVector other) {
        return (this.x == other.x && this.y == other.y && this.z == other.z && this.worldName.equalsIgnoreCase(other.worldName));
    }

    @Override
    public int hashCode() {
        if (hashCode == Integer.MIN_VALUE) {
            this.hashCode = this.toString().hashCode();
        }
        return this.hashCode;
    }

    @Override
    public String toString() {
        return "BlockVector={ " + this.worldName + " ; " + this.x + " ; " + this.y + " ; " + this.z + " }";
    }

    @Override
    public int compareTo(BlockVector other) {
        return this.hashCode() - other.hashCode();
    }
}
