/*
* Copyright (C) 2014 GG-Net GmbH - Oliver Günther
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.ggnet.dwoss.redtape.entity.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.lang3.time.DateUtils;
import eu.ggnet.dwoss.redtape.entity.Document;
import eu.ggnet.dwoss.redtape.entity.Position;
import eu.ggnet.dwoss.rules.PositionType;
import static eu.ggnet.dwoss.redtape.entity.util.DocumentEquals.Property.*;
/**
* A Helper class to build different forms of Equalities.
*
* @author oliver.guenther
*/
public class DocumentEquals {
public static enum Property {
ID,TYPE,ACTIVE,ACTUAL,IDENTIFIER,HISTORY,PREDECESSOR,SETTLEMENTS ,DOSSIER,SHIPPING_ADDRESS,INVOICE_ADDRESS,DIRECTIVE,FLAGS,CLOSED,CONDITIONS
}
private Set<Property> properties = EnumSet.allOf(Property.class);
private Set<PositionType> positionTypes = EnumSet.allOf(PositionType.class);
private boolean positionOrder = true;
public DocumentEquals ignore(Property ... properties) {
this.properties.removeAll(Arrays.asList(properties));
return this;
}
public DocumentEquals ignoreAddresses() {
properties.remove(INVOICE_ADDRESS);
properties.remove(SHIPPING_ADDRESS);
return this;
}
/**
* Enables to ignore some Positions of a type, implies to ignore the order of the positions also.
*
* @param types the types to ignore.
* @return this
*/
public DocumentEquals ignorePositions(PositionType... types) {
positionOrder = false;
positionTypes.removeAll(Arrays.asList(types));
return this;
}
public DocumentEquals igonrePositionOrder() {
positionOrder = false;
return this;
}
/**
* Checks if two documents are equal with the given relaxations.
*
* @param d1 Document one
* @param d2 Document two
* @return true if both are equal
*/
public boolean equals(Document d1, Document d2) {
return equalsMessage(d1, d2) == null;
}
/**
* Checks if two documents are not equal returning a string containing the message what is not equal or null.
*
* @param d1 Document one
* @param d2 Document two
* @return null if equal or a string describing the difference.
*/
public String equalsMessage(Document d1, Document d2) {
if ( d1 == null ) return "d1 is null";
if ( d2 == null ) return "d2 is null";
if ( properties.contains(SETTLEMENTS) ) if ( !Objects.equals(d1.getSettlements(), d2.getSettlements()) ) return "Settlements are not equal, d1=" + d1.getSettlements() + ", d2=" + d2.getSettlements();
if ( properties.contains(ACTUAL) ) {
if (d1.getActual() == null && d2.getActual() != null) return "Actual is not equal, d1=" + d1.getActual() + ", d2=" + d2.getActual();
if (d1.getActual() != null && d2.getActual() == null) return "Actual is not equal, d1=" + d1.getActual() + ", d2=" + d2.getActual();
if ( !DateUtils.isSameDay(d1.getActual(), d2.getActual()) ) return "Actual is not equal, d1=" + d1.getActual() + ", d2=" + d2.getActual();
}
if ( properties.contains(IDENTIFIER) ) if ( !Objects.equals(d1.getIdentifier(), d2.getIdentifier()) ) return "Identifier is not equal, d1=" + d1.getIdentifier() + ", d2=" + d2.getIdentifier();
if ( properties.contains(CONDITIONS) ) if ( !Objects.equals(d1.getConditions(), d2.getConditions()) ) return "Conditions are not equal, d1=" + d1.getConditions() + ", d2=" + d2.getConditions();
if ( properties.contains(TYPE) ) if ( d1.getType() != d2.getType() ) return "Type is not equal, d1=" + d1.getType() + ", d2=" + d2.getType();
if ( properties.contains(DOSSIER) ) if ( !d1.getDossier().equals(d2.getDossier()) ) return "Dossier is not equal, d1=" + d1.getDossier() + ", d2=" + d2.getDossier();
if ( properties.contains(ID) ) if ( d1.getId() != d2.getId() ) return "Id is not equal, d1=" + d1.getId() + ", d2=" + d2.getId();
if ( properties.contains(ACTIVE) ) if ( d1.isActive() != d2.isActive() ) return "Active is not equal, d1=" + d1.isActive() + ", d2=" + d2.isActive();
if ( properties.contains(HISTORY) ) if ( !Objects.equals(d1.getHistory(), d2.getHistory()) ) return "History is not equal, d1=" + d1.getHistory() + ", d2=" + d2.getHistory();
if ( properties.contains(PREDECESSOR) ) if ( !Objects.equals(d1.getPredecessor(), d2.getPredecessor()) ) return "Predecessor is not equal, d1=" + d1.getPredecessor() + ", d2=" + d2.getPredecessor();
if ( properties.contains(FLAGS) ) if ( !Objects.equals(d1.getFlags(), d2.getFlags()) ) return "Flags is not equal, d1=" + d1.getFlags() + ", d2=" + d2.getFlags();
if ( properties.contains(DIRECTIVE)) if ( d1.getDirective() != d2.getDirective() ) return "Directive is not equal, d1=" + d1.getDirective() + ", d2=" + d2.getDirective();
if ( properties.contains(INVOICE_ADDRESS)) if ( !Objects.equals(d1.getInvoiceAddress(), d2.getInvoiceAddress()) ) return "Invoiceaddress is not equal, d1=" + d1.getInvoiceAddress() + ", d2=" + d2.getInvoiceAddress();
if ( properties.contains(SHIPPING_ADDRESS)) if ( !Objects.equals(d1.getShippingAddress(), d2.getShippingAddress()) ) return "Shippingaddress is not equal, d1=" + d1.getShippingAddress() + ", d2=" + d2.getShippingAddress();
if ( properties.contains(CLOSED) ) if ( d1.isClosed() != d2.isClosed() ) return "Closed is not equal, d1=" + d1.isClosed() + ", d2=" + d2.isClosed();
if ( positionTypes.size() == PositionType.values().length ) if ( d1.getPositions().size() != d2.getPositions().size() ) return "Positions.size is not equal, d1=" + d1.getPositions().size() + ", d2=" + d2.getPositions().size();
if ( positionTypes.size() == PositionType.values().length && positionOrder ) {
Iterator<Position> p1 = new TreeSet<>(d1.getPositions().values()).iterator();
Iterator<Position> p2 = new TreeSet<>(d2.getPositions().values()).iterator();
while (p1.hasNext()) {
Position p1p = p1.next();
Position p2p = p2.next();
if ( !p1p.equalsContent(p2p) ) return "Positions are not equal d1=" + p1p + ", d2=" + p2p;
}
} else {
List<Position> d1Poss = new ArrayList<>();
List<Position> d2Poss = new ArrayList<>();
for (Position pos : d1.getPositions().values()) {
if ( positionTypes.contains(pos.getType()) ) d1Poss.add(pos);
}
for (Position pos : d2.getPositions().values()) {
if ( positionTypes.contains(pos.getType()) ) d2Poss.add(pos);
}
if ( d1Poss.size() != d2Poss.size() ) return "Posistions subSiz is not equal d1=" + d1Poss.size() + ", d2=" + d2Poss.size()
+ ", evaluating only types " + positionTypes;
for (Position pos1 : d1Poss) {
boolean existAndIsEqual = false;
for (Position pos2 : d2Poss) {
if ( pos1.equalsContentWithoutId(pos2) ) existAndIsEqual = true;
}
if ( !existAndIsEqual ) return "Subpositions are not equal d1=" + d1Poss + ", d2=" + d2Poss;
}
}
return null;
}
}