package org.nexml.model.impl;
import java.util.HashMap;
import java.util.Map;
import org.nexml.model.Character;
import org.nexml.model.CharacterStateSet;
import org.nexml.model.ContinuousMatrix;
import org.nexml.model.OTU;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
class ContinuousMatrixImpl extends MatrixImpl<Double> implements ContinuousMatrix {
/**
* Protected constructors are intended for recursive parsing, i.e.
* starting from the root element (which maps onto DocumentImpl) we
* traverse the element tree such that for every child element that maps
* onto an Impl class the containing class calls that child's protected
* constructor, passes in the element of the child. From there the
* child takes over, populates itself and calls the protected
* constructors of its children. These should probably be protected
* because there is all sorts of opportunity for outsiders to call
* these in the wrong context, passing in the wrong elements etc.
* @param document the containing DOM document object. Every Impl
* class needs a reference to this so that it can create DOM element
* objects
* @param element the equivalent NeXML element (e.g. for OTUsImpl, it's
* the <otus/> element)
* @author rvosa
*/
protected ContinuousMatrixImpl(Document document, Element item, OTUsImpl otus) {
super(document,item);
NodeList children = item.getChildNodes();
Map<String,Character> charactersById = null;
for ( int i = 0; i < children.getLength(); i++ ) {
String localName = children.item(i).getNodeName();
if ( null != localName && localName.equals("format") ) {
charactersById = processCharacters((Element)children.item(i));
}
if ( null != localName && localName.equals("matrix") ) {
processMatrix((Element)children.item(i),otus, charactersById);
}
}
setOTUs(otus);
}
private Map<String,Character> processCharacters(Element format) {
setFormatElement(format);
Map<String,Character> result = new HashMap<String,Character>();
for ( Element charElement : getChildrenByTagName(format, "char") ) {
String charId = charElement.getAttribute("id");
Character character = new CharacterImpl(getDocument(),charElement);
result.put(charId, character);
addThing(character);
}
return result;
}
private void processMatrix(Element matrix,OTUsImpl otus,Map<String,Character> charactersById) {
setMatrixElement(matrix);
for ( Element rowElement : getChildrenByTagName(matrix, "row") ) {
OTU otu = otus.getThingById(rowElement.getAttribute("otu"));
rowElement.setAttribute("otu", otu.getId());
for ( Element cellElement : getChildrenByTagName(rowElement, "cell") ) {
MatrixCellImpl<Double> matrixCell = new MatrixCellImpl<Double>(getDocument(),cellElement);
setCell(otu, charactersById.get(cellElement.getAttribute("char")), matrixCell);
cellElement.setAttribute("char", charactersById.get(cellElement.getAttribute("char")).getId());
matrixCell.setValue(Double.parseDouble(cellElement.getAttribute("state")));
}
for ( Element seq : getChildrenByTagName(rowElement, "seq")) {
String sequence = seq.getTextContent();
String[] states = sequence.split("\\s+");
int k = 0;
STATE: for ( int j = 0; j < states.length; j++ ) {
if ( states[j].length() == 0 ) {
continue STATE;
}
Character character = null;
character = getCharacterByIndex(k);
getCell(otu, character).setValue(Double.parseDouble(states[j]));
k++;
}
rowElement.removeChild(seq);
}
}
}
/**
* Protected constructors that take a DOM document object but not
* an element object are used for generating new element nodes in
* a NeXML document. On calling such constructors, a new element
* is created, which can be retrieved using getElement(). After this
* step, the Impl class that called this constructor would still
* need to attach the element in the proper location (typically
* as a child element of the class that called the constructor).
* @param document a DOM document object
* @author rvosa
*/
protected ContinuousMatrixImpl(Document document) {
super(document,"Continuous");
}
/**
* This method creates a char element, i.e. a column definition.
* @author rvosa
*/
public Character createCharacter() {
CharacterImpl character = new CharacterImpl(getDocument());
addThing(character);
getFormatElement().appendChild(character.getElement());
return character;
}
public Character createCharacter(CharacterStateSet stateSet) {
return createCharacter();
}
public Double parseSymbol(String symbol) {
return Double.parseDouble(symbol);
}
}