/
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.guitool.event;

import net.sourceforge.pain.*;
import net.sourceforge.pain.db.*;
import net.sourceforge.pain.tinylib.logic.event.guitool.*;
import net.sourceforge.pain.util.*;

import java.util.*;

public class DbBrowseEvent extends GuiEventHandler {

    public void processEvent() {
        String[] data = (String[]) packet.data;
        String action = data[0];
        if (action.equals("retrieve")) {
            retrieve(data);
        } else {
            send(new String[]{"Unknown action: '" + action + "'"});
        }

    }

    private void retrieve(String[] data) {
        if (data.length != 2) {
            send(new String[]{"Illegal number of action params: " + data.length});
            return;
        }
        String query = data[1];
        String errMessage = null;
        try {
            if (query.equalsIgnoreCase("root")) {
                DbObject obj = Codebase.getDB().getRoot();
                if (obj == null) {
                    send(new String[]{"Database has no ROOT object"});
                    return;
                }
                Object oid = obj.getOid();
                sendObject(oid);
            } else if (query.trim().matches("^\\[[\\d]+\\/[\\d]+\\]$")) {
                Object oid = new DbOid(query);
                sendObject(oid);
            } else { //field query
                int eqIndex = query.indexOf("=");
                if (eqIndex >= 3 && eqIndex < query.length() - 1) {
                    int fieldSep = query.indexOf(".");
                    if (fieldSep > 1 && fieldSep < eqIndex - 1) {
                        String className = query.substring(0, fieldSep);
                        String fieldName = query.substring(fieldSep + 1, eqIndex);
                        String value = query.substring(eqIndex + 1);
                        DbClass dbClass = null;
                        for (Iterator it = Codebase.getDB().getDbClassesIterator(); it.hasNext();) {
                            DbClass clz = (DbClass) it.next();
                            final String clzName = clz.getClassName();
                            if (clzName.endsWith(className)) {
                                dbClass = clz;
                                break;
                            }
                        }
                        if (dbClass != null) {
                            int num = -1;
                            for (int i = 0; i < dbClass.getNumberOfFields(); i++) {
                                String fName = dbClass.getFieldName(i);
                                if (fName.equals(fieldName)) {
                                    num = i;
                                    break;
                                }
                            }
                            if (num >= 0) {
                                sendQueryResults(dbClass, num, value);
                                return;
                            } else {
                                errMessage = "field not found:" + fieldName;
                            }
                        } else {
                            errMessage = "dbclass not found:" + className;
                        }
                    }
                }
                if (errMessage == null) {
                    errMessage = "Illegal query:" + query;
                }
            }
        } catch (Exception e) {
            errMessage = "Exception:" + e.getMessage();
        }
        if (errMessage != null) {
            send(new String[]{"Error: '" + errMessage + "'"});
            return;
        }

    }

    private void sendObject(Object o) {
        DbOid oid;
        DbObject obj;
        if (o instanceof DbOid) {
            oid = (DbOid) o;
            obj = Codebase.getDB().getObject(oid);
            if (obj == null) {
                send(new String[]{"Object not found! OID: '" + oid + "'"});
                return;
            }
        } else {
            obj = (DbObject) o;
            oid = (DbOid) obj.getOid();
        }
        try {
            DbClass dbclass = obj.getDbClass();
            int fieldCount = dbclass.getNumberOfFields();
            Object[] result = new Object[2 + 3 * fieldCount];
            result[0] = oid.toString();
            result[1] = dbclass.getClassName();
            for (int i = 0, j = 2; i < fieldCount; i++, j += 3) {
                result[j] = dbclass.getFieldName(i);
                byte fieldType = dbclass.getFieldType(i);
                result[j + 1] = new Integer(fieldType);
                result[j + 2] = getFieldValue(obj, fieldType, i);
                Log.debug("field:" + dbclass.getFieldName(i));
            }
            send(result);
        } catch (Exception e) {
            Log.error(e.getMessage(), e);
            send(new String[]{"Unexpected Error!: '" + e.getMessage() + "'"});
        }
    }

    private Object getFieldValue(DbObject obj, int type, int i) {
        switch (type) {
            case DbType.BOOLEAN:
                return "" + obj.getBoolean(i);
            case DbType.BYTE:
                return "" + obj.getByte(i);
            case DbType.CHAR:
                return "" + obj.getChar(i);
            case DbType.DOUBLE:
                return "" + obj.getDouble(i);
            case DbType.FLOAT:
                return "" + obj.getFloat(i);
            case DbType.INT:
                return "" + obj.getInt(i);
            case DbType.LONG:
                return "" + obj.getLong(i);
            case DbType.SHORT:
                return "" + obj.getShort(i);
            case DbType.STRING:
                return obj.getString(i);
            case DbType.REFERENCE:
                DbObject ref = obj.getReference(i);
                return ref == null ? null : ref.getOid().toString();
            case DbType.ARRAY_OF_BYTE:
                return obj.getByteArray(i);
            case DbType.ARRAY_OF_CHAR:
                return obj.getCharArray(i);
            case DbType.ARRAY_OF_INT:
                return obj.getIntArray(i);
            case DbType.ARRAY_OF_STRING:
                return obj.getStringArray(i);
            case DbType.LINKED_LIST:
                return refsToIds(obj.getList(i).toArray());
            case DbType.ARRAY_LIST:
                return refsToIds(obj.getList(i).toArray());
            case DbType.INT_KEY_MAP:
                return new Object[]{obj.getIntKeyMap(i).keySet().toArray(), refsToIds(obj.getIntKeyMap(i).values().toArray())};
            case DbType.STRING_KEY_MAP:
                return new Object[]{obj.getStringKeyMap(i).keySet().toArray(), refsToIds(obj.getStringKeyMap(i).values().toArray())};
            case DbType.REFERENCE_SET:
                return refsToIds(obj.getRefSet(i).toArray());
            case DbType.STRING_SET:
                return obj.getStringSet(i).toArray();
            case DbType.STRING_MAP:
                return new Object[]{obj.getStringMap(i).keySet().toArray(), obj.getStringMap(i).entrySet().toArray()};
            default:
                return "Unknown field type!:" + type;
        }

    }

    private static Object[] refsToIds(Object[] objects) {
        if (objects == null) {
            return null;
        }
        Object[] result = new Object[objects.length];
        for (int i = 0; i < objects.length; i++) {
            DbObject obj = (DbObject) objects[i];
            result[i] = obj == null ? null : obj.getOid();
        }
        return result;
    }


    private void sendQueryResults(DbClass dbClass, int num, String value) {
        int type = dbClass.getFieldType(num);
        if (type > 9) {
            send(new String[]{"Query not supported on type: '" + DbType.name(type) + "'"});
            return;
        }
        FieldComparator fc = null;
        switch (type) {
            case DbType.BOOLEAN:
                fc = new BooleanFieldComparator(num, Boolean.getBoolean(value));
                break;
            case DbType.BYTE:
                fc = new ByteFieldComparator(num, Byte.parseByte(value));
                break;
            case DbType.CHAR:
                fc = new CharFieldComparator(num, value.charAt(0));
                break;
            case DbType.DOUBLE:
                fc = new DoubleFieldComparator(num, Double.parseDouble(value));
                break;
            case DbType.FLOAT:
                fc = new FloatFieldComparator(num, Float.parseFloat(value));
                break;
            case DbType.INT:
                fc = new IntFieldComparator(num, Integer.parseInt(value));
                break;
            case DbType.LONG:
                fc = new LongFieldComparator(num, Long.parseLong(value));
                break;
            case DbType.SHORT:
                fc = new ShortFieldComparator(num, Short.parseShort(value));
                break;
            case DbType.STRING:
                fc = new StringFieldComparator(num, value);
                break;
        }
        for (Iterator it = dbClass.extentIterator(); it.hasNext();) {
            DbObject o = (DbObject) it.next();
            if (fc.matches(o)) {
                sendObject(o);
                return;
            }
        }
        send(new String[]{"No results found"});
    }


    interface FieldComparator {
        boolean matches(DbObject obj);
    }

    final class BooleanFieldComparator implements FieldComparator {
        private int num;
        private boolean sample;

        public BooleanFieldComparator(int num, boolean sample) {
            this.num = num;
            this.sample = sample;
        }

        public boolean matches(DbObject obj) {
            return obj.getBoolean(num) == sample;
        }
    }


    final class ByteFieldComparator implements FieldComparator {
        private int num;
        private byte sample;

        public ByteFieldComparator(int num, byte sample) {
            this.num = num;
            this.sample = sample;
        }

        public boolean matches(DbObject obj) {
            return obj.getByte(num) == sample;
        }
    }

    final class CharFieldComparator implements FieldComparator {
        private int num;
        private char sample;

        public CharFieldComparator(int num, char sample) {
            this.num = num;
            this.sample = sample;
        }

        public boolean matches(DbObject obj) {
            return obj.getChar(num) == sample;
        }
    }

    final class DoubleFieldComparator implements FieldComparator {
        private int num;
        private double sample;

        public DoubleFieldComparator(int num, double sample) {
            this.num = num;
            this.sample = sample;
        }

        public boolean matches(DbObject obj) {
            return obj.getDouble(num) == sample;
        }
    }

    final class FloatFieldComparator implements FieldComparator {
        private int num;
        private float sample;

        public FloatFieldComparator(int num, float sample) {
            this.num = num;
            this.sample = sample;
        }

        public boolean matches(DbObject obj) {
            return obj.getFloat(num) == sample;
        }
    }

    final class IntFieldComparator implements FieldComparator {
        private int num;
        private int sample;

        public IntFieldComparator(int num, int sample) {
            this.num = num;
            this.sample = sample;
        }

        public boolean matches(DbObject obj) {
            return obj.getInt(num) == sample;
        }
    }

    final class LongFieldComparator implements FieldComparator {
        private int num;
        private long sample;

        public LongFieldComparator(int num, long sample) {
            this.num = num;
            this.sample = sample;
        }

        public boolean matches(DbObject obj) {
            return obj.getLong(num) == sample;
        }
    }

    final class ShortFieldComparator implements FieldComparator {
        private int num;
        private short sample;

        public ShortFieldComparator(int num, short sample) {
            this.num = num;
            this.sample = sample;
        }

        public boolean matches(DbObject obj) {
            return obj.getShort(num) == sample;
        }
    }

    final class StringFieldComparator implements FieldComparator {
        private int num;
        private String sample;

        public StringFieldComparator(int num, String sample) {
            this.num = num;
            this.sample = sample.toLowerCase();
        }

        public boolean matches(DbObject obj) {
            final String val = obj.getString(num);
            return val!= null && val.toLowerCase().indexOf(sample) >= 0;
        }
    }

}