/
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.event.console.command.builder;

import net.sourceforge.pain.data.*;
import net.sourceforge.pain.data.role.*;
import net.sourceforge.pain.db.*;
import net.sourceforge.pain.tinylib.*;
import net.sourceforge.pain.tinylib.data.*;
import net.sourceforge.pain.tinylib.data.prototype.*;
import net.sourceforge.pain.tinylib.data.type.*;
import net.sourceforge.pain.tinylib.logic.fn.*;
import net.sourceforge.pain.tinylib.util.*;
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);
                            return;
                        }
                        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 = Mudlib.getWorld().getPrototypesRegistry();
        if (prototypesRegistry.isVnumInUse(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 CreaturePrototype) && fid != CreaturePrototype.RACE) {
                throw new SetFuncException("Illegal role or field:" + role.getClass().getName() + " fid:" + fid);
            }
            String lvalue = value.toLowerCase();
            Race r = null;
            for (Iterator it = Mudlib.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);
            }
            CreaturePrototype cp = (CreaturePrototype) role;
            cp.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 CreaturePrototype && (fid == CreaturePrototype.MOVE_POINTS_DICE || fid == CreaturePrototype.HIT_POINTS_DICE))) {
                throw new SetFuncException("Illegal role or field:" + role.getClass().getName() + " fid:" + fid);
            }
            Dice dice = new Dice(value.toLowerCase().trim());
            CreaturePrototype cp = (CreaturePrototype) role.getRole(CreaturePrototype.class);
            if (fid == CreaturePrototype.MOVE_POINTS_DICE) {
                cp.setMovePointsDice(dice);
            } else {
                cp.setHPDice(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 CreaturePrototype)) {
                throw new SetFuncException("Illegal role or field:" + role.getClass().getName() + " fid:" + fid);
            }
            String vnum = value;
            PrototypeInfo p = Mudlib.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);
            }
            CreaturePrototype cr = (CreaturePrototype) role.getRole(CreaturePrototype.class);
            cr.setInventoryPrototype(sp);
            return "[" + vnum + "/" + sp.getSpaceName() + "]";
        }

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

}