package org.ultramine.mods.hawkeye;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;

import org.ultramine.mods.hawkeye.util.HawkPermission;
import org.ultramine.mods.hawkeye.util.HawkUtil;
import org.ultramine.mods.hawkeye.util.HawkVector;

//import com.sk89q.worldedit.bukkit.selections.Selection;

/**
 * Class for parsing HawkEye arguments ready to be used by an instance of
 * {@SearchQuery}
 * 
 * @author oliverw92
 */
public class SearchParser
{
	public ICommandSender player = null;
	public List<String> players = new ArrayList<String>();
	public HawkVector loc = null;
	public HawkVector minLoc = null;
	public HawkVector maxLoc = null;
	public Integer radius = null;
	public List<DataType> actions = new ArrayList<DataType>();
	public String[] worlds = null;
	public long dateFrom = 0;
	public long dateTo = 0;
	public String[] filters = null;

	public SearchParser()
	{
	}

	public SearchParser(ICommandSender player)
	{
		this.player = player;
	}

	public SearchParser(ICommandSender player, int radius)
	{
		this.player = player;
		this.radius = radius;
		parseLocations();
	}

	public SearchParser(ICommandSender player, List<String> args) throws IllegalArgumentException
	{
		this.player = player;

		String lastParam = "";
		boolean paramSet = false;
		boolean worldedit = false;

		for(int i = 0; i < args.size(); i++)
		{
			String arg = args.get(i);
			if(arg.isEmpty())
				continue;

			if(!paramSet)
			{
				if(arg.length() < 2)
					throw new IllegalArgumentException("Invalid argument format: &7" + arg);
				if(!arg.substring(1, 2).equals(":"))
				{
					if(arg.contains(":"))
						throw new IllegalArgumentException("Invalid argument format: &7" + arg);

					// No arg specified, treat as player
					players.add(arg);
					continue;
				}

				lastParam = arg.substring(0, 1).toLowerCase();
				paramSet = true;

				if(arg.length() == 2)
				{
					if(i == (args.size() - 1)) // No values specified
						throw new IllegalArgumentException("Invalid argument format: &7" + arg);
					else
						// User put a space between the colon and value
						continue;
				}

				// Get values out of argument
				arg = arg.substring(2);
			}

			if(paramSet)
			{
				if(arg.isEmpty())
				{
					throw new IllegalArgumentException("Invalid argument format: &7" + lastParam + ":");
				}

				String[] values = arg.split(",");

				// Players
				if(lastParam.equals("p"))
					for(String p : values)
						players.add(p);
				// Worlds
				else if(lastParam.equals("w"))
					worlds = values;
				// Filters
				else if(lastParam.equals("f"))
				{
					if(filters != null)
						filters = HawkUtil.concat(filters, values);
					else
						filters = values;
				}
				// Blocks
				else if(lastParam.equals("b"))
				{
					//for (int j = 0; j < values.length; j++) {
					//	if (Material.getMaterial(values[j]) != null)
					//		values[j] = Integer.toString(Material.getMaterial(values[j]).getId());
					//}
				}
				// Actions
				else if(lastParam.equals("a"))
				{
					for(String value : values)
					{
						DataType type = DataType.fromName(value);
						if(type == null)
							throw new IllegalArgumentException("Invalid action supplied: &7" + value);
						if(!HawkPermission.searchType(player, type.getConfigName()))
							throw new IllegalArgumentException("You do not have permission to search for: &7" + type.getConfigName());
						actions.add(type);
					}
				}
				// Location
				else if(lastParam.equals("l") && player instanceof EntityPlayerMP)
				{
					if(values[0].equalsIgnoreCase("here"))
						loc = new HawkVector((EntityPlayerMP)player);
					else
					{
						loc = new HawkVector();
						loc.setX(Integer.parseInt(values[0]));
						loc.setY(Integer.parseInt(values[1]));
						loc.setZ(Integer.parseInt(values[2]));
					}
				}
				// Radius
				else if(lastParam.equals("r") && player instanceof EntityPlayerMP)
				{
					if(!HawkUtil.isInteger(values[0]))
					{
						/*
						if ((values[0].equalsIgnoreCase("we") || values[0].equalsIgnoreCase("worldedit")) && HawkEye.worldEdit != null) {
							Selection sel = HawkEye.worldEdit.getSelection((Player) player);
							double lRadius = Math.ceil(sel.getLength() / 2);
							double wRadius = Math.ceil(sel.getWidth() / 2);
							double hRadius = Math.ceil(sel.getHeight() / 2);

							if (Config.MaxRadius != 0 && (lRadius > Config.MaxRadius || wRadius > Config.MaxRadius || hRadius > Config.MaxRadius))
								throw new IllegalArgumentException("Selection too large, max radius: &7" + Config.MaxRadius);

							worldedit = true;
							minLoc = new Vector(sel.getMinimumPoint().getX(), sel.getMinimumPoint().getY(), sel.getMinimumPoint().getZ());
							maxLoc = new Vector(sel.getMaximumPoint().getX(), sel.getMaximumPoint().getY(), sel.getMaximumPoint().getZ());
						} else {
							throw new IllegalArgumentException("Invalid radius supplied: &7" + values[0]);
						}
						*/
					}
					else
					{
						radius = Integer.parseInt(values[0]);
						int maxRadius = HawkEye.instance.config.general.maxRadius;
						if(maxRadius != 0 && radius > maxRadius)
							throw new IllegalArgumentException("Radius too large, max allowed: &7" + maxRadius);
					}
				}
				//Time
				else if(lastParam.equals("t"))
				{

					int type = 2;
					for(int j = 0; j < arg.length(); j++)
					{
						String c = arg.substring(j, j + 1);
						if(!HawkUtil.isInteger(c))
						{
							if(c.equals("m") || c.equals("s") || c.equals("h") || c.equals("d") || c.equals("w"))
								type = 0;
							if(c.equals("-") || c.equals(":"))
								type = 1;
						}
					}

					//If the time is in the format '0w0d0h0m0s'
					if(type == 0)
					{

						int weeks = 0;
						int days = 0;
						int hours = 0;
						int mins = 0;
						int secs = 0;

						String nums = "";
						for(int j = 0; j < values[0].length(); j++)
						{
							String c = values[0].substring(j, j + 1);
							if(HawkUtil.isInteger(c))
							{
								nums += c;
								continue;
							}
							int num = Integer.parseInt(nums);
							if(c.equals("w"))
								weeks = num;
							else if(c.equals("d"))
								days = num;
							else if(c.equals("h"))
								hours = num;
							else if(c.equals("m"))
								mins = num;
							else if(c.equals("s"))
								secs = num;
							else
								throw new IllegalArgumentException("Invalid time measurement: &7" + c);
							nums = "";
						}

						Calendar cal = Calendar.getInstance();
						cal.add(Calendar.WEEK_OF_YEAR, -1 * weeks);
						cal.add(Calendar.DAY_OF_MONTH, -1 * days);
						cal.add(Calendar.HOUR, -1 * hours);
						cal.add(Calendar.MINUTE, -1 * mins);
						cal.add(Calendar.SECOND, -1 * secs);
						dateFrom = cal.getTimeInMillis();

					}
					//If the time is in the format 'yyyy-MM-dd HH:mm:ss'
					else if(type == 1)
					{
						try
						{
							SimpleDateFormat parse = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
							if(values.length == 1)
							{
								SimpleDateFormat form = new SimpleDateFormat("yyyy-MM-dd");
								dateFrom = parse.parse(form.format(Calendar.getInstance().getTime()) + " " + values[0]).getTime();
							}
							if(values.length >= 2)
								dateFrom = parse.parse(values[0] + " " + values[1]).getTime();
							if(values.length == 4)
								dateTo = parse.parse(values[2] + " " + values[3]).getTime();
						}
						catch(ParseException e)
						{
							throw new IllegalArgumentException("Invalid time format!", e);
						}
					}
					//Invalid time format
					else if(type == 2)
						throw new IllegalArgumentException("Invalid time format!");

				}
				else
					throw new IllegalArgumentException("Invalid parameter supplied: &7" + lastParam);

				paramSet = false;
			}
		}

		//Sort out locations
		if(!worldedit)
			parseLocations();
	}

	/**
	 * Formats min and max locations if the radius is set
	 */
	public void parseLocations()
	{
		if(!(player instanceof EntityPlayerMP))
			return;

		// Check if there is a max radius
		int maxRadius = HawkEye.instance.config.general.maxRadius;
		if(radius == null && maxRadius != 0)
			radius = maxRadius;

		//If the radius is set we need to format the min and max locations
		if(radius != null)
		{

			//Check if location and world are supplied
			if(loc == null)
				loc = new HawkVector((EntityPlayerMP)player);
			if(worlds == null)
				worlds = new String[] {Integer.toString(((EntityPlayerMP)player).dimension)};

			//Format min and max
			minLoc = new HawkVector(loc.getX() - radius, loc.getY() - radius, loc.getZ() - radius);
			maxLoc = new HawkVector(loc.getX() + radius, loc.getY() + radius, loc.getZ() + radius);

		}

	}

}
