package com.aionemu.packetsamurai.parser.formattree;
import java.util.Collections;
import java.util.List;
import com.aionemu.packetsamurai.parser.PartType;
import javolution.util.FastTable;
/**
* @author Ulysses R. Ribeiro
*
*/
public class PartContainer extends Part
{
private List<Part> _parts = new FastTable<Part>();
private boolean _lengthComputed;
private boolean _constantLength;
private int _length;
public PartContainer(PartType type, boolean isRoot)
{
super(type, isRoot);
_lengthComputed = false;
_length = 0;
}
public PartContainer(PartType type)
{
this(type, false);
}
public void addPart(Part part)
{
// transmit containing format & container
part.setContainingFormat(this.getContainingFormat());
part.setParentContainer(this);
_parts.add(part);
invalidateLength();
}
public boolean addPartAfter(Part part, Part afterPart)
{
int i = 1;
boolean found = false;
for(Part ipart : _parts)
{
if(afterPart == ipart)
{
found = true;
break;
}
if(ipart instanceof PartContainer && ((PartContainer)ipart).addPartAfter(part, afterPart))
{
return true;
}
if(ipart instanceof ForPart && ((ForPart)ipart).addPartAfter(part, afterPart))
{
return true;
}
else if(ipart instanceof SwitchPart)
{
for(SwitchCaseBlock sCase : ((SwitchPart)ipart).getCases(true))
{
if(sCase.addPartAfter(part, afterPart))
{
return true;
}
}
}
i++;
}
if(found)
{
_parts.add(i, part);
invalidateLength();
}
return found;
}
public boolean removePart(Part part)
{
boolean found = false;
if(_parts.remove(part))
{
found = true;
}
else
{
for(Part p : _parts)
{
if(p instanceof ForPart)
{
found = ((ForPart)p).getModelBlock().removePart(part);
}
else if(p instanceof SwitchPart)
{
for(SwitchCaseBlock scb : ((SwitchPart)p).getCases(true))
{
found = scb.removePart(part);
if(found)
break;
}
}
else if(p instanceof PartContainer)
{
found = ((PartContainer)p).removePart(part);
}
if(found)
break;
}
}
if(found)
invalidateLength();
return found;
}
public Part getPart(int index)
{
return _parts.get(index);
}
public void addParts(List<Part> parts)
{
for (Part part : parts)
{
this.addPart(part);
}
}
/**
* This returns an unmodifiable list of th parts in this container
* @return a List of the parts in this container
*/
public List<Part> getParts()
{
return Collections.unmodifiableList(_parts);
}
public int size()
{
return this.getParts().size();
}
/**
* Searchs in this Part Container for a part with the given id, if not found
* it will search into any Part Containers inside this one and so on, until the lowest level of containers is reached
*
* @param id The Id of the PacketPart to be retrieved
* @return The PacketPart with the given Id if found, null otherwise
*/
public Part getPacketPartById(int id)
{
for(Part part : this.getParts())
{
if(part instanceof PartContainer)
{
Part test = ((PartContainer) part).getPacketPartById(id);
if(test != null)
return test;
}
else if(part instanceof ForPart)
{
Part test = ((ForPart) part).getModelBlock().getPacketPartById(id);
if(test != null)
return test;
}
else if(part instanceof SwitchPart)
{
for(SwitchCaseBlock scb : ((SwitchPart)part).getCases(true))
{
Part test = scb.getPacketPartById(id);
if(test != null)
return test;
}
}
if(id == part.getId())
return part;
}
return null;
}
/**
* Searchs in this Part Container for a part with the given id, before the <code>who</code> part to ensure that the returned part is in the scopte of <code>who</code>, if not found
* it will search up into Part Containers above this one and so on, until the root level of containers is reached
*
* @param id The Id of the PacketPart to be retrieved
* @param who ensures that this part should be able to see the returned part
* @return The PacketPart with the given Id if found, null otherwise
*/
public Part getPacketPartByIdInScope(int id, Part who)
{
for(Part part : this.getParts())
{
if(id == part.getId())
return part;
if(part == who) // dont go after myself
break;
}
if(!this.isRoot())
return this.getParentContainer().getPacketPartByIdInScope(id, who);
return null;
}
/**
* Searchs in this Part Container for a part with the given analyzerName, if not found
* it will search into any Part Containers inside this one and so on, until the lowest level of containers is reached
*
* @param analyzerName the analyzer name to look for
* @return The PacketPart with the given analyzerName or null if not found.
*/
public Part getPartByAnalyzerName(String analyzerName)
{
for(Part part : this.getParts())
{
if(part instanceof PartContainer)
{
Part test = ((PartContainer) part).getPartByAnalyzerName(analyzerName);
if(test != null)
return test;
}
else if(part instanceof ForPart)
{
Part test = ((ForPart) part).getModelBlock().getPartByAnalyzerName(analyzerName);
if(test != null)
return test;
}
else if(part instanceof SwitchPart)
{
for(SwitchCaseBlock scb : ((SwitchPart)part).getCases(true))
{
Part test = scb.getPartByAnalyzerName(analyzerName);
if(test != null)
return test;
}
}
if(analyzerName.equals(part.getName()))
return part;
}
return null;
}
public Part getPartByName(String name)
{
if(name == null)
throw new NullPointerException("Name was null in getPartByName");
for(Part part : this.getParts())
{
if(part instanceof PartContainer)
{
Part test = ((PartContainer) part).getPartByName(name);
if(test != null)
return test;
}
else if(part instanceof ForPart)
{
Part test = ((ForPart) part).getModelBlock().getPartByName(name);
if(test != null)
return test;
}
else if(part instanceof SwitchPart)
{
for(SwitchCaseBlock scb : ((SwitchPart)part).getCases(true))
{
Part test = scb.getPartByName(name);
if(test != null)
return test;
}
}
if(name.equals(part.getName()))
return part;
}
return null;
}
public boolean hasConstantLength()
{
if(!_lengthComputed)
{
computeLength();
}
return _constantLength;
}
public int getLength()
{
if(!_lengthComputed)
{
computeLength();
}
return _length;
}
public void invalidateLength()
{
_lengthComputed = false;
if(!this.isRoot())
getParentContainer().invalidateLength();
if(this.getContainingFormat() != null)
this.getContainingFormat().triggerFormatChanged();
}
private void computeLength()
{
_length = 0;
int typeLength;
for(Part part : _parts)
{
typeLength = part.getType().getTypeByteNumber();
if(typeLength == 0)
{
_length = 0;
_constantLength = false;
break;
}
_length += typeLength;
}
_lengthComputed = true;
}
}