/
area/
classes/net/sourceforge/pain/logic/
classes/net/sourceforge/pain/logic/event/
classes/net/sourceforge/pain/logic/fn/util/
classes/net/sourceforge/pain/network/console/
classes/net/sourceforge/pain/plugin/
classes/net/sourceforge/pain/plugin/reset/
classes/net/sourceforge/pain/plugin/shutdown/
classes/net/sourceforge/pain/plugin/social/
classest/net/sourceforge/pain/db/data/
doc/
doc/paindb/resources/
src/net/sourceforge/pain/logic/
src/net/sourceforge/pain/logic/event/
src/net/sourceforge/pain/logic/fn/util/
src/net/sourceforge/pain/network/console/
src/net/sourceforge/pain/network/console/telnet/
src/net/sourceforge/pain/plugin/
src/net/sourceforge/pain/plugin/command/
src/net/sourceforge/pain/plugin/reset/
src/net/sourceforge/pain/plugin/shutdown/
src/net/sourceforge/pain/plugin/social/
src/net/sourceforge/pain/util/
tests/
tests/net/sourceforge/pain/db/data/
package net.sourceforge.pain.logic.event.console.command.builder;

import net.sourceforge.pain.*;
import net.sourceforge.pain.data.*;
import net.sourceforge.pain.data.prototype.*;
import net.sourceforge.pain.data.type.*;
import net.sourceforge.pain.db.*;
import net.sourceforge.pain.logic.fn.*;
import net.sourceforge.pain.network.console.*;
import net.sourceforge.pain.util.*;

import java.util.*;

/**
 * PAiN  Date: 05.06.2003  Time: 1:40:02
 */
public final class BC_Set extends BuilderCommand {
	public static final Map funcMap = new HashMap();

	static {
		funcMap.put("race", new RaceSetFunc());
		funcMap.put("dice", new DiceSetFunc());
		funcMap.put("target_list", new TargetListSetFunc());
		funcMap.put("proto", new ProtoSetFunc());
	}

	public void processBuilderCommand(BuilderShell p, String args) throws Exception {
		Prototype role = p.builder.getEditedRole();
		if (args == null || args.trim().length() == 0) {
			showHelp(p.console);
			return;
		}
		if (role == null) {
			MessageOutFn.outln(p.console, "No active role found!");
		} else {
			int space = args.indexOf(' ');
			if (space < 1) {
				showHelp(p.console);
				return;
			}
			final String fieldName = args.substring(0, space).trim();
			String fieldValue = args.substring(space + 1, args.length());
			if (role.getClass() == PrototypeInfo.class && fieldName.equals("vnum")) {
				processSetVnum(p.console, (PrototypeInfo) role, fieldValue);
				return;
			}
			DbClass clazz = role.getDbClass();
			int fid = -1;
			for (int i = 2; i < clazz.getNumberOfFields(); i++) {
				String name = clazz.getFieldName(i);
				if (fieldName.equalsIgnoreCase(name)) {
					fid = i;
					break;
				}
			}
			if (fid == -1) {
				MessageOutFn.outln(p.console, "Field not found:" + fieldName);
				return;
			}
			final String setTo;
			switch (clazz.getFieldType(fid)) {
				case DbType.BOOLEAN:
					boolean bool = "true".equalsIgnoreCase(fieldValue.trim());
					role.setBoolean(fid, bool);
					setTo = "" + bool;
					break;
				case DbType.BYTE:
					byte bt = Byte.parseByte(fieldValue.trim());
					role.setByte(fid, bt);
					setTo = "" + bt;
					break;
				case DbType.CHAR:
					char ch = fieldValue.charAt(0);
					role.setChar(fid, ch);
					setTo = "" + ch;
					break;
				case DbType.DOUBLE:
					double d = Double.parseDouble(fieldValue.trim());
					role.setDouble(fid, d);
					setTo = "" + d;
					break;
				case DbType.FLOAT:
					float ft = Float.parseFloat(fieldValue.trim());
					role.setFloat(fid, ft);
					setTo = "" + ft;
					break;
				case DbType.INT:
					int i = Integer.parseInt(fieldValue.trim());
					role.setInt(fid, i);
					setTo = "" + i;
					break;
				case DbType.LONG:
					long l = Long.parseLong(fieldValue.trim());
					role.setLong(fid, l);
					setTo = "" + l;
					break;
				case DbType.SHORT:
					short sh = Short.parseShort(fieldValue.trim());
					role.setShort(fid, sh);
					setTo = "" + sh;
					break;
				case DbType.STRING:
					role.setString(fid, fieldValue);
					setTo = fieldValue;
					break;
				default:
					if (fieldValue.startsWith("@")) {
						space = fieldValue.indexOf(' ');
						if (space == -1 || space > fieldValue.length() - 2) {
							MessageOutFn.outln(p.console, "invalid func :" + fieldValue);
							return;
						}
						final String funcName = fieldValue.substring(1, space).trim();
						fieldValue = fieldValue.substring(space + 1);
						SetFunc setFunc = (SetFunc) funcMap.get(funcName);
						if (setFunc == null) {
							MessageOutFn.outln(p.console, "Function not found:" + funcName);
							showSpecialFunctionsNames(p.console);
						}
						try {
							setTo = setFunc.apply(role, fid, fieldValue);
						} catch (SetFuncException e) {
							MessageOutFn.outln(p.console, "{RError:{x" + e.getMessage());
							return;
						}
					} else {
						MessageOutFn.outln(p.console, "Can't set value for this type(use special functions):" + DbType.name(fid));
						showSpecialFunctionsNames(p.console);
						return;
					}
			}
			MessageOutFn.outln(p.console, "Value of the field '" + fieldName + "' has been set to '{w" + setTo + "{x'");
		}
	}

	private void showSpecialFunctionsNames(Console console) {
		for (Iterator it = funcMap.keySet().iterator(); it.hasNext();) {
			String funcName = (String) it.next();
			SetFunc setFunc = (SetFunc) funcMap.get(funcName);
			MessageOutFn.outln(console, funcName + " : " + setFunc.getFuncDesc());
		}
	}


	private void processSetVnum(Console console, PrototypeInfo info, String vnum) {
		if (info.getVnum().equals(vnum)) {
			MessageOutFn.outln(console, "Vnum stays the same:" + vnum);
			return;
		}
		PrototypesRegistry prototypesRegistry = Core.getWorld().getPrototypesRegistry();
		if (prototypesRegistry.isUsedVnum(vnum)) {
			MessageOutFn.outln(console, "Vnum is already in use:" + vnum);
		} else {
			prototypesRegistry.unregisterPrototype(info);
			info.setVnum(vnum);
			prototypesRegistry.registerPrototype(info);
			MessageOutFn.outln(console, "Vnum changed to {w" + vnum + "{x");
		}
	}

	public void showHelp(Console console) {
		MessageOutFn.outln(console, "Builder command SET inits fields values for the currently edited prototype");
		MessageOutFn.outln(console, "Only primitives and strings could be setted directly");
		MessageOutFn.outln(console, "Available functions for other types: ");
		showSpecialFunctionsNames(console);
		MessageOutFn.outln(console, "Usage: set <field_name> [@func_name] <value>");

	}


	/**
	 * TODO: change interface name and make it global
	 * all SetFunc code is very raw in this version and will be clarified and enchanced in next release
	 * but it works:)
	 */
	private static interface SetFunc {
		/**
		 * Sets the specified value to the field of the role.
		 * Parse this values, checks it validity.
		 * @param role
		 * @param fid
		 * @param value
		 * @return String represensation of setted value
		 */
		public String apply(Role role, int fid, String value) throws SetFuncException;

		public String getFuncDesc();

	}


	public static final class SetFuncException extends IllegalArgumentException {
		public SetFuncException(String message) {
			super(message);
		}
	}

	private static final class RaceSetFunc implements SetFunc {
		public String apply(Role role, int fid, String value) throws SetFuncException {
			if (!(role instanceof LifeFormPrototype) && fid != LifeFormPrototype.RACE) {
				throw new SetFuncException("Illegal role or field:" + role.getClass().getName() + " fid:" + fid);
			}
			String lvalue = value.toLowerCase();
			Race r = null;
			for (Iterator it = Core.getWorld().getRaces().iterator(); it.hasNext();) {
				r = (Race) it.next();
				if (r.getName().toLowerCase().equals(lvalue)) {
					break;
				}
				r = null;
			}
			if (r == null) {
				throw new SetFuncException("Race not found!:" + value);
			}
			LifeFormPrototype lfp = (LifeFormPrototype) role;
			lfp.setRace(r);
			return r.getName();
		}

		public String getFuncDesc() {
			return "sets race type field";
		}
	}

	private static final class TargetListSetFunc implements SetFunc {
		public String apply(Role role, int fid, String value) throws SetFuncException {
			if (!(role instanceof InteractivePrototype) && fid != InteractivePrototype.TARGET_LIST) {
				throw new SetFuncException("Illegal role or field:" + role.getClass().getName() + " fid:" + fid);
			}

			String lvalue = value.toLowerCase();
			String[] list = new String[0];
			for (StringTokenizer st = new StringTokenizer(lvalue, " \t"); st.hasMoreTokens();) {
				list = TargetList.addNameToList(list, list.length, st.nextToken());
			}
			if (list.length == 0) {
				throw new SetFuncException("illegal target list value:" + lvalue);
			}
			Log.debug("target list:" + value);
			InteractivePrototype ip = (InteractivePrototype) role;
			ip.setTargetList(list);
			return TargetList.string(list);
		}

		public String getFuncDesc() {
			return "sets targetList type field for Interactive roles";
		}
	}

	private static final class DiceSetFunc implements SetFunc {
		public String apply(Role role, int fid, String value) throws SetFuncException {
			if ((!(role instanceof MobilePrototype) && fid != MobilePrototype.MOVE_POINTS_DICE)
			        || !(role instanceof LifeFormPrototype) && fid != LifeFormPrototype.LIFE_POINTS_DICE) {
				throw new SetFuncException("Illegal role or field:" + role.getClass().getName() + " fid:" + fid);
			}
			Dice dice = new Dice(value.toLowerCase().trim());
			if (role instanceof MobilePrototype) {
				((MobilePrototype) role).setMovePointsDice(dice);
			} else {
				((LifeFormPrototype) role).setLifePointsDice(dice);
			}
			return dice.toString();
		}

		public String getFuncDesc() {
			return "sets Dice type field";
		}
	}


	private static final class ProtoSetFunc implements SetFunc {
		public String apply(Role role, int fid, String value) throws SetFuncException {
			if (!(role instanceof EquippedPrototype)) {
				throw new SetFuncException("Illegal role or field:" + role.getClass().getName() + " fid:" + fid);
			}
			String vnum = value;
			PrototypeInfo p = Core.getWorld().getPrototypesRegistry().getPrototypeByVnum(vnum);
			if (p == null) {
				throw new SetFuncException("Prototype not found:" + value);
			}
			SpacePrototype sp = (SpacePrototype) p.getRole(SpacePrototype.class);
			if (sp == null) {
				throw new SetFuncException("Not a space prototype:" + value);
			}
			EquippedPrototype eq = (EquippedPrototype) role.getRole(EquippedPrototype.class);
			eq.setInventoryPrototype(sp);
			return "[" + vnum + "/" + sp.getSpaceName() + "]";
		}

		public String getFuncDesc() {
			return "sets fields with type of references to prototypes";
		}
	}

}