/
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.fn;


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

import java.util.*;


/**
 MessageOutFn template definition:
 $$ - means '$' ascii character, this is not parameter.
 $xN - means parameter (N=0-9)
 all paramter look for values in args[] array
 so we haave invariant: args.length = number of parameters

 X:
 lowercase: first param
 UPPERCASE: second param
 t,d - (text)argiment is a java.lang.String (t=t1, T = t2 - compatibility)

 n - interactive name
 p - interactive desc

 This parameters will get clarified in one of the next versions:
 e,E - Result is 'he', 'she', or 'it', depending on the sex/gender of arg (LogicalObject). (default he)
 m,M - Result is 'him', 'her', or 'it', depending on the sex/gender of arg (LogicalObject).(default his)
 s,S - Result is 'his', 'her', or 'its', depending on the sex/gender of arg (LogicalObject).(default his)

 TO_ONE:
 = to messageRecipient only
 TO_SPACE:
 = to every receptive object in this space except messageRecipient

 WARN: single thread model!!!
 */

public final class MessageOutFn {

	private static final Map preparedTemplates = new HashMap();
	private static final Object args[] = new Object[9];


	public static void outSpace(LogicalObject actor, String template, Object arg1) {
		outSpace(actor, template, arg1, null);
	}

	public static void outSpace(LogicalObject actor, String template, Object arg1, Object arg2) {
		outSpace(actor, template, arg1, arg2, Receptive.SEE);
	}

	public static void outSpace(LogicalObject actor, String template, Object arg1, Object arg2, int receptionType) {
		args[0] = arg1;
		args[1] = arg2;
		_outSpace(actor, null, template, args, receptionType);
		args[0] = null;
		args[1] = null;
	}


	public static void outSpaceNoVictim(LogicalObject actor, Interactive victim, String template) {
		outSpaceNoVictim(actor, victim, template, null);
	}

	public static void outSpaceNoVictim(LogicalObject actor, Interactive victim, String template, Object arg1) {
		outSpaceNoVictim(actor, victim, template, arg1, null);
	}

	public static void outSpaceNoVictim(LogicalObject actor, Interactive victim, String template, Object arg1, Object arg2) {
		outSpaceNoVictim(actor, victim, template, arg1, arg2, null, Receptive.SEE);
	}

	public static void outSpaceNoVictim(LogicalObject actor, Interactive victim, String template, Object arg1, Object arg2, Object arg3, int receptionType) {
		args[0] = arg1;
		args[1] = arg2;
		args[2] = arg3;
		_outSpace(actor, victim, template, args, receptionType);
		args[0] = null;
		args[1] = null;
		args[2] = null;
	}


	public static void outOne(LogicalObject recipient, String template, Object arg1) {
		outOne(recipient, template, arg1, null);
	}

	public static void outOne(LogicalObject recipient, String template, Object arg1, Object arg2) {
		args[0] = arg1;
		args[1] = arg2;
		_outOne(recipient, prepareTemplate(template), args, Receptive.SEE);
		args[0] = null;
		args[1] = null;

	}

	private static void _outOne(LogicalObject obj, OutTemplate template, Object[] args, int receptionType) {
		Receptive rObj = (Receptive) obj.getRole(Receptive.class);
		if (rObj == null || !rObj.has(receptionType)) {
			return;
		}
		//today the only reception output is console, in next version reception outputs will be expanded (virtual consoles or something like that)
		Console console = ConsoleFn.getConsole(obj);
		if (console == null) {
			return;
		}

		String[] tokens = template.tokens;
		char[] params = template.params;
		int argN[] = template.argN;

		console.out(tokens[0]);
		for (int i = 0; i < params.length; i++) {
			final String value;
			Object arg = args[argN[i]];
			switch (params[i]) {
				case 'T':
				case 'D':
					value = (String) arg;
					break;
				case 'N':
					Interactive inter1 = (Interactive) ((LogicalObject) arg).getRole(Interactive.class);
					if (inter1 == null) {
						throw new RuntimeException("arg" + argN[i] + " is not Interactive!");
					}
					value = inter1.getName();
					break;
				case 'P':
					Interactive inter2 = (Interactive) ((LogicalObject) arg).getRole(Interactive.class);
					if (inter2 == null) {
						throw new RuntimeException("arg" + argN[i] + " is not Interactive!");
					}
					value = inter2.getDesc();
					break;
				case 'E':
					value = LangUtil.he((LogicalObject) arg);
					break;
				case 'M':
					value = LangUtil.him((LogicalObject) arg);
					break;
				case 'S':
					value = LangUtil.his((LogicalObject) arg);
					break;
				default:
					throw new RuntimeException("Not supported type:" + params[i]);
			}
			//			Log.debug("OUT:value'"+value+"'");
			console.out(value);
			//			Log.debug("OUT:token'"+template.tokens[i + 1]+"'");
			console.out(template.tokens[i + 1]);
		}
		console.out("\n");
	}

	private static void _outSpace(LogicalObject actor, LogicalObject victim, String template, Object[] args, int receptionType) {
		final Located actorL = (Located) actor.getRole(Located.class);
		final Located victimL = victim == null ? null : (Located) victim.getRole(Located.class);
		final OutTemplate t = prepareTemplate(template);
		Space space = actorL.getLocation();
		for (Located obj = space.getFirstInSpace(); obj != null; obj = obj.getNextInSpace()) {
			if (obj != actorL && obj != victimL) {
				_outOne(obj, t, args, receptionType);
			}
		}
	}

	private static OutTemplate prepareTemplate(String templateStr) {
		OutTemplate template = (OutTemplate) preparedTemplates.get(templateStr);
		if (template == null) {
			template = new OutTemplate(templateStr);
			preparedTemplates.put(templateStr, template);
		}
		return template;
	}

	protected static final class OutTemplate {

		private static final char[] upper = new char[127];

		static {
			upper['T'] = upper['t'] = 'T';
			upper['D'] = upper['d'] = 'D';
			upper['N'] = upper['n'] = 'N';
			upper['P'] = upper['p'] = 'P';
			upper['E'] = upper['e'] = 'E';
			upper['M'] = upper['m'] = 'M';
			upper['S'] = upper['s'] = 'S';
		}

		public String[] tokens; // simple text between arguments
		public char[] params; // $, parameters
		public int[] argN; // argNum

		public OutTemplate(String templateStr) {
			int nParams = countParams(templateStr);

			params = new char[nParams];
			argN = new int[nParams];
			tokens = new String[nParams + 1];
			// we always have N parameters and N+1 tokens
			// example: templateStr = '$n tells $T'  ->""+n+" tells "+T+""
			StringBuffer buff = new StringBuffer();
			int index = 0;

			final int tLen = templateStr.length();
			for (int i = 0; i < tLen; i++) {
				char c = templateStr.charAt(i);
				if (c == '$') {
					i++;
					c = templateStr.charAt(i);
					if (c == '$') {
						buff.append(c);
					} else {
						tokens[index] = (buff.length() == 0 ? "" : buff.toString());
						buff.delete(0, buff.length());
						char uc = c < 127 ? upper[c] : 0;
						if (uc == 0) {
							throw new RuntimeException("Illegal param value:" + c);
						}
						params[index] = uc;
						i++;
						int arg = 0;
						if (i < tLen) {
							arg = templateStr.charAt(i) - '0';
							if (arg < 1 || arg > 9) {
								arg = 0;
								i--;
							}
						}
						if (arg == 0) {
							arg = c == uc ? 2 : 1;
						}
						argN[index] = arg - 1; // argN is started from 0
						index++;
					}
				} else {
					buff.append(c);
				}
			}
			tokens[tokens.length - 1] = (buff.length() == 0 ? "" : buff.toString());
		}

		private int countParams(String str) {
			int result = 0;
			for (int i = 0; i < str.length(); i++) {
				char c = str.charAt(i);
				if (c == '$') {
					i++;
					c = str.charAt(i);
					if (c != '$') {
						result++;
					}
				}
			}
			return result;
		}
	}


	public static final void out(Console outConsole, String text) {
		if (outConsole != null) {
			outConsole.out(text);
		}
	}

	public static final void outln(Console outConsole, String text) {
		if (outConsole != null) {
			outConsole.out(text);
			outConsole.out("\n");
		}
	}

	/**
	 * any reception type!
	 * @param obj
	 * @param message
	 */
	public static void outln(LogicalObject obj, String message) {
		Console c = ConsoleFn.getConsole(obj);
		if (c == null) {
			return;
		}
		outln(c, message);
	}

	public static void outln(LogicalObject obj, String message, int receptionType) {
		Receptive r = (Receptive) obj.getRole(Receptive.class);
		if (r == null || !r.has(receptionType)) {
			return;
		}
		Console c = ConsoleFn.getConsole(obj);
		if (c == null) {
			return;
		}
		outln(c, message);
	}


	public static void outSpace(Space space, String message) {
		for (Located obj = space.getFirstInSpace(); obj != null; obj = obj.getNextInSpace()) {
			outln(obj, message, Receptive.FEEL);
		}
	}
}