Coverage Summary for Class: LogicalStructMapType (org.kitodo.dataeditor.entities)
Class |
Method, %
|
Line, %
|
LogicalStructMapType |
100%
(16/16)
|
98,6%
(71/72)
|
LogicalStructMapType$1 |
100%
(1/1)
|
100%
(1/1)
|
Total |
100%
(17/17)
|
98,6%
(72/73)
|
/*
* (c) Kitodo. Key to digital objects e. V. <contact@kitodo.org>
*
* This file is part of the Kitodo project.
*
* It is licensed under GNU General Public License version 3 or later.
*
* For the full copyright and license information, please read the
* GPL3-License.txt file that was distributed with this source code.
*/
package org.kitodo.dataeditor.entities;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.kitodo.dataeditor.MetsKitodoObjectFactory;
import org.kitodo.dataeditor.enums.PositionOfNewDiv;
import org.kitodo.dataformat.metskitodo.DivType;
import org.kitodo.dataformat.metskitodo.StructMapType;
public class LogicalStructMapType extends StructMapType {
private static final Logger logger = LogManager.getLogger(LogicalStructMapType.class);
/**
* Constructor to copy the data from parent class.
*
* @param structMapType
* The structMapType object.
*/
public LogicalStructMapType(StructMapType structMapType) {
super.div = structMapType.getDiv();
super.id = structMapType.getID();
super.label = structMapType.getLABEL();
super.type = structMapType.getTYPE();
}
/**
* Moves a given DivType object by removing it from logical structMap and
* inserting it as a child of a new parent div.
*
* @param movedDiv
* The DivType object which has to be moved.
* @param parentDiv
* The DivType object which is the new parent div.
* @param index
* The index position where the moved div needs to be inserted.
*/
public void moveDivToDivAtIndex(DivType movedDiv, DivType parentDiv, int index) {
removeDiv(movedDiv);
parentDiv.getDiv().add(index, movedDiv);
generateIdsForDivs();
}
/**
* Removed the given DivType object from current logical structMap.
*
* @param divToRemove
* The DivType object which should be removed.
*/
public void removeDiv(DivType divToRemove) {
removeDivFromStructMap(divToRemove);
generateIdsForDivs();
}
/**
* Adds a new DivType object which specified type and position to the given
* DivType object.
*
* @param presentDiv
* The DivType object to which the new DivType should be added to.
* @param type
* The type of the DivType object.
* @param position
* The position in relation to the given DivType object.
*/
public void addNewDiv(DivType presentDiv, String type, PositionOfNewDiv position) {
addNewLogicalDivToExistingDiv(presentDiv, type, position);
generateIdsForDivs();
}
/**
* Adds a new logical div to an existing div of a structMap.
*
* @param existingDiv
* The existing div.
* @param type
* The type of the new div.
* @param position
* The position of the new added div.
*/
private void addNewLogicalDivToExistingDiv(DivType existingDiv, String type,
PositionOfNewDiv position) {
MetsKitodoObjectFactory objectFactory = new MetsKitodoObjectFactory();
DivType newDiv = objectFactory.createDivType();
newDiv.setTYPE(type);
switch (position) {
case LAST_CHILD_OF_ELEMENT:
addDivToDivAsLastChild(existingDiv, newDiv);
break;
case FIRST_CHILD_OF_ELEMENT:
addDivToDivAsFirstChild(existingDiv, newDiv);
break;
case BEFORE_ELEMENT:
addDivBeforeExistingDiv(existingDiv, newDiv);
break;
case AFTER_ELEMENT:
addDivAfterExistingDiv(existingDiv, newDiv);
break;
default:
throw new IllegalArgumentException("Position of new div element is not supported");
}
}
private void addDivToDivAsLastChild(DivType existingDiv, DivType newDiv) {
existingDiv.getDiv().add(newDiv);
}
private void addDivToDivAsFirstChild(DivType existingDiv, DivType newDiv) {
existingDiv.getDiv().add(0, newDiv);
}
private void addDivBeforeExistingDiv(DivType existingDiv, DivType newDiv) {
DivType parentDiv = getParentDivOfDiv(existingDiv);
int count = parentDiv.getDiv().size();
for (int i = 0; i < count; i++) {
if (Objects.equals(parentDiv.getDiv().get(i).getID(), existingDiv.getID())) {
parentDiv.getDiv().add(i, newDiv);
return;
}
}
}
private void addDivAfterExistingDiv(DivType existingDiv, DivType newDiv) {
DivType parentDiv = getParentDivOfDiv(existingDiv);
int count = parentDiv.getDiv().size();
for (int i = 0; i < count; i++) {
if (Objects.equals(parentDiv.getDiv().get(i).getID(), existingDiv.getID())) {
parentDiv.getDiv().add(i + 1, newDiv);
return;
}
}
}
private DivType getParentDivOfDiv(DivType div) {
DivType currentParentDiv = this.getDiv();
if (currentParentDiv.getDiv().contains(div)) {
return currentParentDiv;
}
return getParentDivOfChildDivFromDivList(div, currentParentDiv.getDiv());
}
private DivType getParentDivOfChildDivFromDivList(DivType childDiv, List<DivType> divTypeList) {
if (childDiv.getID().contains("ROOT")) {
throw new UnsupportedOperationException("Root element cannot have a parent!");
}
for (DivType div : divTypeList) {
if (div.getDiv().contains(childDiv)) {
return div;
}
if (!div.getDiv().isEmpty()) {
try {
return getParentDivOfChildDivFromDivList(childDiv, div.getDiv());
} catch (NoSuchElementException e) {
// this method is calling recursive its self for handling a complex structure of nested divs
// we need to catch the below exception internally that the for loop can run farther
logger.debug("Div element with Id {} does not contain div element with Id: {}", div.getID(),
childDiv.getID());
}
}
}
throw new NoSuchElementException("Child div element not found");
}
/**
* Generating and setting of ids of all div elements in given StructMapType
* object.
*/
private void generateIdsForDivs() {
if (Objects.nonNull(super.getDiv())) {
List<DivType> divTypes = super.getDiv().getDiv();
if (!divTypes.isEmpty()) {
int index = 1;
setIdsOfDivTypes(divTypes, "LOG_", index);
}
}
}
private int setIdsOfDivTypes(List<DivType> divTypes, String prefix, int startingIndex) {
for (DivType div : divTypes) {
div.setID(prefix + String.format("%04d", startingIndex));
startingIndex++;
if (!div.getDiv().isEmpty()) {
startingIndex = setIdsOfDivTypes(div.getDiv(), prefix, startingIndex);
}
}
return startingIndex;
}
/**
* Removed a div element from a structMap. Does nothing if the given div does
* not exist at structMap.
*
* @param divToRemove
* The divType object to remove.
*/
public void removeDivFromStructMap(DivType divToRemove) {
removeDivFromDivList(divToRemove, this.getDiv().getDiv());
}
private void removeDivFromDivList(DivType divToRemove, List<DivType> divList) {
if (!divList.remove(divToRemove)) {
for (DivType div : divList) {
if (!div.getDiv().isEmpty()) {
removeDivFromDivList(divToRemove, div.getDiv());
}
}
}
}
}