/
codebase/src/net/sourceforge/pain/admin/console/command/
codebase/src/net/sourceforge/pain/data/role/
codebase/src/net/sourceforge/pain/network/console/telnet/
codebase/src/net/sourceforge/pain/network/guitool/
codebase/src/net/sourceforge/pain/plugin/
codebase/src/net/sourceforge/pain/util/
db/src/net/sourceforge/pain/util/
gui/
gui/lib/
gui/src/net/sourceforge/pain/tools/guitool/dbbrowse/
gui/src/net/sourceforge/pain/tools/guitool/dialog/
gui/src/net/sourceforge/pain/tools/guitool/menu/
gui/src/net/sourceforge/pain/tools/guitool/resources/
gui/src/net/sourceforge/pain/tools/guitool/resources/images/
gui/src/net/sourceforge/pain/tools/guitool/resources/images/explorer/
mudlibs/tinylib/
mudlibs/tinylib/area/
mudlibs/tinylib/etc/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/data/affect/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/data/prototype/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/data/trigger/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/affect/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/event/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/event/deploy/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/event/guitool/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/event/guitool/event/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/fn/util/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/trigger/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/trigger/impl/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/plugin/command/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/plugin/reset/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/plugin/shutdown/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/plugin/social/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/util/
tests/
tests/src/
tests/src/net/sourceforge/pain/db/data/
package net.sourceforge.pain.tinylib.logic.fn;


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

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
 * <p/>
 * X:
 * lowercase: first param
 * UPPERCASE: second param
 * t,d - (text)argiment is a java.lang.String (t=t1, T = t2 - compatibility)
 * <p/>
 * n - interactive name
 * p - interactive desc
 * <p/>
 * 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)
 * <p/>
 * TO_ONE:
 * = to messageRecipient only
 * TO_SPACE:
 * = to every receptive object in this space except messageRecipient
 * <p/>
 * 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(Role actor, String template, Object arg1) {
        outSpace(actor, template, arg1, null);
    }

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

    public static void outSpace(Role 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(Role actor, Interactive victim, String template) {
        outSpaceNoVictim(actor, victim, template, null);
    }

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

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

    public static void outSpaceNoVictim(Role 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(Role recipient, String template, Object arg1) {
        outOne(recipient, template, arg1, null);
    }

    public static void outOne(Role 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(Role 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 passes to telnet consoles, 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) ((Role) 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) ((Role) 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((Role) arg);
                    break;
                case 'M':
                    value = LangUtil.him((Role) arg);
                    break;
                case 'S':
                    value = LangUtil.his((Role) 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(Role actor, Role 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(Role obj, String message) {
        Console c = ConsoleFn.getConsole(obj);
        if (c == null) {
            return;
        }
        outln(c, message);
    }

    public static void outln(Role 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);
        }
    }
}