package com.aionemu.packetsamurai.parser.valuereader;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javolution.util.FastMap;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.aionemu.packetsamurai.PacketSamurai;
import com.aionemu.packetsamurai.parser.datatree.IntValuePart;
import com.aionemu.packetsamurai.parser.datatree.ValuePart;
/**
*
* @author Gilles Duboscq
*
*/
public class MultiValueReader implements Reader
{
private Map<Integer, Case> _cases = new FastMap<Integer, Case>();
private Case _default;
private Class<?> _enum;
private String _enumName;
public boolean loadReaderFromXML(Node n)
{
NamedNodeMap attrs = n.getAttributes();
Node atr = attrs.getNamedItem("enum");
if(atr != null)
{
_enumName = atr.getNodeValue();
// get enum class
}
for(Node subNode = n.getFirstChild(); subNode != null; subNode = subNode.getNextSibling())
{
if("case".equals(subNode.getNodeName()))
{
attrs = subNode.getAttributes();
atr = attrs.getNamedItem("val");
if(atr == null)
{
PacketSamurai.getUserInterface().log("Error while reading MultiValue reader : no val atribute");
return false;
}
if("default".equals(atr.getNodeValue()))
{
atr = attrs.getNamedItem("display");
String disp = atr.getNodeValue();
String enumValue = null;
if(_enum != null)
{
atr = attrs.getNamedItem("enumval");
if(atr == null)
{
PacketSamurai.getUserInterface().log("Warning: reading MultiValue reader : no enumval attribute while reader has an enum : disabling enum for this reader");
_enum = null;
}
else
{
enumValue = atr.getNodeValue();
}
}
_default = new Case(disp, enumValue);
continue;
}
int caseId = 0;
try
{
caseId = Integer.decode(atr.getNodeValue());
}
catch (NumberFormatException e)
{
PacketSamurai.getUserInterface().log("Error while reading MultiValue reader : val should be a number");
return false;
}
atr = attrs.getNamedItem("display");
String disp = atr.getNodeValue();
String enumValue = null;
if(_enum != null)
{
atr = attrs.getNamedItem("enumval");
if(atr == null)
{
PacketSamurai.getUserInterface().log("Warning: reading MultiValue reader : no enumval attribute while reader has an enum : disabling enum for this reader");
_enum = null;
}
else
{
enumValue = atr.getNodeValue();
}
}
_cases.put(caseId, new Case(caseId, disp, enumValue));
}
else
{
//wtf!
}
}
return true;
}
public String read(ValuePart part)
{
if(!(part instanceof IntValuePart))
throw new IllegalStateException("A MultiValueReader must be providen an IntValuePart");
Case c = _cases.get(((IntValuePart)part).getIntValue());
if(c == null)
c = _default;
if(c == null)
return "Unknown case";
if(c.display != null)
return c.display;
return "";
}
public JComponent readToComponent(ValuePart part)
{
return new JLabel(this.read(part));
}
// XXX this is dirty, we should see if we can do something without having dirty unchecked type casting
@SuppressWarnings("unchecked")
public <T extends Enum<T>> T getEnum(ValuePart part)
{
if(_enum == null)
throw new IllegalStateException("getEnum can not be called on a MultiValueReader that doesnt supports enums");
if(!(part instanceof IntValuePart))
throw new IllegalStateException("A MultiValueReader must be providen an IntValuePart");
Case c = _cases.get(((IntValuePart)part).getIntValue());
return Enum.valueOf((Class<T>)_enum, c.enumValue);
}
public boolean saveReaderToXML(Element element, Document doc)
{
if(this.supportsEnum())
element.setAttribute("enum", _enumName);
for(Case c : _cases.values())
{
Element caseElement = doc.createElement("case");
caseElement.setAttribute("val", Integer.toString(c.id));
caseElement.setAttribute("display", c.display);
if(this.supportsEnum())
caseElement.setAttribute("enumval", c.enumValue);
element.appendChild(caseElement);
}
return true;
}
public boolean supportsEnum()
{
return (_enum != null);
}
private class Case
{
public int id;
public boolean defaultCase;
public String display;
public String enumValue;
public Case(int i, String dis, String enname)
{
id = i;
display = dis;
enumValue = enname;
defaultCase = false;
}
public Case(String dis, String enname)
{
id = 0;
display = dis;
enumValue = enname;
defaultCase = true;
}
}
}