/*
Copyright (C) 2005 David Green <green@couchpotato.net>

This file is part of I3J.

I3J is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

I3J is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with I3J; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package com.aelfengard.i3.packet;

import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.aelfengard.i3.LPCUtils;
import com.aelfengard.i3.LPCMixed;

public abstract class I3Packet {

    private static final Map<String,Type> typeMap = new HashMap<String,Type>();
    
    public static enum Type {

        STARTUP_REQ(StartupReq3Packet.class),
        STARTUP_REPLY(StartupReplyPacket.class),
        MUD_LIST(MudListPacket.class),
        CHANLIST_REPLY(ChanListReplyPacket.class),
        CHANNEL_LISTEN(ChannelListenPacket.class),
        CHANNEL_M(ChannelMPacket.class),
        CHANNEL_E(ChannelEPacket.class),
        CHANNEL_T(ChannelTPacket.class),
        ERROR(ErrorPacket.class),
        WHO_REQ(WhoReqPacket.class),
        WHO_REPLY(WhoReplyPacket.class),
        TELL(TellPacket.class),
        EMOTE_TO(EmoteToPacket.class);
        
        private final Class clazz;
        
        private Type(Class clazz) {
            try {
                this.clazz = clazz;
                String token = (String) clazz.getField("TOKEN").get(null);
                typeMap.put(token, this);
            }
            catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
        
        public Class getPacketClass() {
            return clazz;
        }
        
    }

    private final Type type;
    
    public I3Packet(Type type) {
        if (getClass() != type.getPacketClass()) {
            throw new IllegalArgumentException(type + ", " + getClass());
        }
        this.type = type;
    }
    
    public static I3Packet forString(String s) {
        List<LPCMixed> list = LPCUtils.lpcToJava(s).asList();
        return forList(list);
    }
    
    public static I3Packet forList(List<LPCMixed> list) {
        String typeString = list.get(0).asString();
        Type type = typeMap.get(typeString);
        if (type == null) {
            return null; // unrecognized packet
        }
        try {
            Class clazz = type.getPacketClass();
            Constructor c = clazz.getConstructor(List.class);
            return (I3Packet) c.newInstance(list);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
    
    public Type getType() {
        return type;
    }
    
    public final String toString() {
        return LPCUtils.javaToLPC(toList());
    }
    
    public abstract List<LPCMixed> toList();

}