/
area/
classes/net/sourceforge/pain/console/
classes/net/sourceforge/pain/logic/
classes/net/sourceforge/pain/logic/event/
classes/net/sourceforge/pain/logic/fn/util/
classes/net/sourceforge/pain/plugin/
classes/net/sourceforge/pain/plugin/reset/
classes/net/sourceforge/pain/plugin/shutdown/
classes/net/sourceforge/pain/plugin/social/
classes/net/sourceforge/pain/util/
classest/net/sourceforge/pain/db/data/
doc/
doc/paindb/resources/
src/net/sourceforge/pain/console/
src/net/sourceforge/pain/console/telnet/
src/net/sourceforge/pain/logic/
src/net/sourceforge/pain/logic/event/
src/net/sourceforge/pain/logic/fn/util/
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/net/sourceforge/pain/db/data/
package net.sourceforge.pain.logic.fn;


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

import java.util.*;


/**
 MessageOutFn template definition:
 $$ - means '$' ascii character, this is not parameter.
 $X - means parameter
 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,T - (text)argiment is a java.lang.String
 d,D - (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)
 e,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();

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

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

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


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

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

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


	public static void outOne(LogicalObject recipient, String template, Object arg1) {
		_outOne(recipient, prepareTemplate(template), arg1, null, Receptive.SEE);
	}

	public static void outOne(LogicalObject recipient, String template, Object arg1, Object arg2) {
		_outOne(recipient, prepareTemplate(template), arg1, arg2, Receptive.SEE);
	}

	private static void _outOne(LogicalObject obj, OutTemplate template, Object arg1, Object arg2, 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;

		console.out(tokens[0]);
		for (int i = 0; i < params.length; i++) {
			final String value;
			switch (params[i]) {
				case 't':
				case 'd':
					value = (String) arg1;
					break;

				case 'T':
				case 'D':
					value = (String) arg2;
					break;

				case 'n':
				case 'p':
					Interactive inter1 = (Interactive) ((LogicalObject) arg1).getRole(Interactive.class);
					if (inter1 == null) {
						throw new RuntimeException("arg1 has not Interactive role!");
					}
					value = inter1.getName();
					break;

				case 'N':
				case 'P':
					Interactive inter2 = (Interactive) ((LogicalObject) arg2).getRole(Interactive.class);
					if (inter2 == null) {
						throw new RuntimeException("arg2 has not Interactive role!");
					}
					value = inter2.getName();
					break;

				case 'e':
					value = LangUtil.he((LogicalObject) arg1);
					break;
				case 'E':
					value = LangUtil.he((LogicalObject) arg2);
					break;

				case 'm':
					value = LangUtil.him((LogicalObject) arg1);
					break;
				case 'M':
					value = LangUtil.him((LogicalObject) arg2);
					break;
				case 's':
					value = LangUtil.his((LogicalObject) arg1);
					break;
				case 'S':
					value = LangUtil.his((LogicalObject) arg2);
					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 arg1, Object arg2, 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, arg1, arg2, 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 {
		public String[] tokens; // simple text between arguments
		public char[] params; // $, parameters

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

			params = new char[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;

			for (int i = 0; i < templateStr.length(); 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());
						params[index] = c;
						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);
		}
	}


}