package org.ultramine.mods.hawkeye.entry;

import org.ultramine.mods.hawkeye.DataType;
import org.ultramine.mods.hawkeye.util.HawkBlockUtil;

import cpw.mods.fml.common.eventhandler.Event;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.IChatComponent;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.BlockSnapshot;

/**
 * Represents a HawkEye database entry This class can be extended and overriden
 * by sub-entry classes to allow customisation of rollbacks etc
 * 
 * @author oliverw92
 */
public class DataEntry extends Event
{
	private long dataId;
	private long date;
	private String player = null;
	private int world;
	private double x;
	private double y;
	private double z;
	protected DataType type = null;
	protected String data = null;
	protected byte[] subdata;
	
	private BlockSnapshot undoState;

	public DataEntry()
	{
	}

	public DataEntry(EntityPlayer player, DataType type, World world, double x, double y, double z, String data)
	{
		setInfo(player, type, world, x, y, z);
		setData(data);
	}

	public DataEntry(String player, DataType type, World world, double x, double y, double z, String data)
	{
		setInfo(player, type, world, x, y, z);
		setData(data);
	}

	public void setDataId(long dataId)
	{
		this.dataId = dataId;
	}

	public long getDataId()
	{
		return dataId;
	}

	public void setDate(long date)
	{
		this.date = date;
	}

	public long getDate()
	{
		return date;
	}

	public void setPlayer(String player)
	{
		this.player = player;
	}

	public String getPlayer()
	{
		return player;
	}

	public void setType(DataType type)
	{
		this.type = type;
	}

	public DataType getType()
	{
		return type;
	}

	public void setWorld(int world)
	{
		this.world = world;
	}

	public int getWorld()
	{
		return world;
	}

	public void setX(double x)
	{
		this.x = x;
	}

	public double getX()
	{
		return x;
	}

	public void setY(double y)
	{
		this.y = y;
	}

	public double getY()
	{
		return y;
	}

	public void setZ(double z)
	{
		this.z = z;
	}

	public double getZ()
	{
		return z;
	}

	public void setData(String data)
	{
		this.data = data;
	}

	public BlockSnapshot getUndoState()
	{
		return undoState;
	}

	public void setUndoState(BlockSnapshot undoState)
	{
		this.undoState = undoState;
	}

	/**
	 * Returns the entry data in a visually attractive and readable way for an
	 * in-game user to read Extending classes can add colours, customise layout
	 * etc.
	 * 
	 * @return
	 */
	public IChatComponent getStringData()
	{
		if(type == DataType.BLOCK_INTERACT)
			return HawkBlockUtil.getBlockComponent(data);
		return new ChatComponentText(data);
	}

	/**
	 * Converts the raw data from the database into the actual data required by
	 * the entry Extending classes can override this to support custom storage
	 * methods (e.g. sign data etc)
	 * 
	 * @param data
	 *            string to be interpreted
	 */
	public void interpretSqlData(String data)
	{
		this.data = data;
	}

	/**
	 * Returns the entry data ready for storage in the database Extending
	 * classes can override this method and format the data as they wish
	 * 
	 * @return string containing data to be stored
	 */
	public String getSqlData()
	{
		return data;
	}

	/**
	 * Rolls back the data entry on the specified block Default is to return
	 * false, however extending classes can override this and do their own thing
	 * 
	 * @param block
	 * @return true if rollback is performed, false if it isn't
	 */
	public boolean rollback(World world)
	{
		return false;
	}

	/**
	 * Performs a local rollback for the specified player only Default is to
	 * return false, and most extending classes will not override this If
	 * overriding, the method should use Player.sendBlockChange() for sending
	 * fake changes
	 * 
	 * @param block
	 * @param player
	 * @return true if rollback is performed, false if it isn't
	 */
	public boolean rollbackPlayer(World world, EntityPlayerMP player)
	{
		return false;
	}

	/**
	 * Rebuilds the entry (reapplies it) Extending classes can implement this
	 * method to do custom things
	 * 
	 * @param block
	 * @return true if rebuild is performed, false it if isn't
	 */
	public boolean rebuild(World world)
	{
		return false;
	}

	/**
	 * Parses the inputted action into the DataEntry instance
	 * 
	 * @param player
	 * @param instance
	 * @param type
	 * @param loc
	 * @param action
	 */
	public void setInfo(EntityPlayer player, DataType type, World world, double x, double y, double z)
	{
		setInfo(player.getGameProfile().getName().toLowerCase(), type, world, x, y, z);
	}

	public void setInfo(String player, DataType type, World world, double x, double y, double z)
	{
		setInfo(player, "HawkEye", type, world, x, y, z);
	}

	public void setInfo(String player, String instance, DataType type, World world, double x, double y, double z)
	{
		setDate(System.currentTimeMillis());
		setPlayer(player);
		setType(type);
		setWorld(world.provider.dimensionId);
		setX(Math.round(x * 10) / 10d);
		setY(Math.round(y * 10) / 10d);
		setZ(Math.round(z * 10) / 10d);
	}

	public byte[] getSubData()
	{
		return subdata;
	}

	public void setSubData(byte[] subdata)
	{
		this.subdata = subdata;
	}
	
	public void post()
	{
		MinecraftForge.EVENT_BUS.post(this);
	}
}
