/*
* 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.state;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import eu.ggnet.dwoss.redtape.entity.Document;
import eu.ggnet.dwoss.redtape.entity.Document.Condition;
import eu.ggnet.dwoss.redtape.entity.Document.Directive;
import eu.ggnet.dwoss.rules.DocumentType;
import eu.ggnet.dwoss.rules.PaymentMethod;
import eu.ggnet.dwoss.rules.CustomerFlag;
import eu.ggnet.statemachine.State;
import eu.ggnet.statemachine.StateCharacteristic;
/**
* The Characteristic of a Document.
*
* @author oliver.guenther
*/
public class RedTapeStateCharacteristic implements StateCharacteristic<CustomerDocument> {
/**
* Helper class for creating multiple States.
* Is considered to be used like:
* <pre>
* new Permutation() {{
* init = new RedTapeStateCharacteristic(Type.ORDER, PaymentMethod.ADVANCE_PAYMENT, of(Condition.CREATED), null, null, false);
* flagss = asList(noneOf(Flag.class), of(Flag.CONFIRMED_CASH_ON_DELIVERY), of(Flag.CONFIRMS_DOSSIER), of(Flag.CONFIRMED_CASH_ON_DELIVERY, Flag.CONFIRMS_DOSSIER));
* directives = asList(Directive.SEND_ORDER_DOCUMENT, Directive.WAIT_3_DAYS_FOR_MONEY, Directive.WAIT_10_DAYS_FOR_MONEY);
* }}.build());
* </pre>
*/
public static class Permutation {
protected RedTapeStateCharacteristic init;
protected Set<PaymentMethod> paymentMethods;
protected Set<Set<CustomerFlag>> flagss;
protected Set<Directive> directives;
protected Set<Set<Condition>> conditionss;
protected boolean permuteDispatch = false;
public Collection<RedTapeStateCharacteristic> build() {
Set<RedTapeStateCharacteristic> result = new HashSet<>();
if ( paymentMethods == null ) {
paymentMethods = new HashSet<>();
paymentMethods.add(init.getPaymentMethod());
}
if ( flagss == null ) {
flagss = new HashSet<>();
flagss.add(init.getCustomerFlags());
}
if ( directives == null ) {
directives = new HashSet<>();
directives.add(init.getDirective());
}
if ( conditionss == null ) {
conditionss = new HashSet<>();
conditionss.add(init.getConditions());
}
for (PaymentMethod paymentMethod : paymentMethods) {
for (Set<CustomerFlag> flags : flagss) {
for (Directive directive : directives) {
for (Set<Condition> conditions : conditionss) {
if ( !permuteDispatch ) {
result.add(new RedTapeStateCharacteristic(init.getType(), paymentMethod, conditions, directive, flags, init.isDispatch()));
} else {
result.add(new RedTapeStateCharacteristic(init.getType(), paymentMethod, conditions, directive, flags, false));
result.add(new RedTapeStateCharacteristic(init.getType(), paymentMethod, conditions, directive, flags, true));
}
}
}
}
}
return result;
}
}
public static class Change {
private State<CustomerDocument> init;
private DocumentType type;
private PaymentMethod paymentMethod;
private Set<Document.Condition> conditions;
private Document.Directive directive;
private CustomerFlag customerFlag;
private Boolean dispatch;
public Change(State<CustomerDocument> state, Directive directive) {
this(state, null, null, null, directive, null, null);
}
public Change(State<CustomerDocument> state, CustomerFlag flag, Directive directive) {
this(state, null, null, null, directive, null, null);
}
public Change(State<CustomerDocument> state, DocumentType type, Directive directive) {
this(state, type, null, null, directive, null, null);
}
public Change(State<CustomerDocument> state, DocumentType type, Set<Condition> conditions, Directive directive) {
this(state, type, null, conditions, directive, null, null);
}
public Change(State<CustomerDocument> state, Set<Condition> conditions, Directive directive) {
this(state, null, null, conditions, directive, null, null);
}
public Change(State<CustomerDocument> state, PaymentMethod paymentMethod, boolean dispatch) {
this(state, null, paymentMethod, null, null, null, dispatch);
}
public Change(State<CustomerDocument> state, boolean dispatch) {
this(state, null, null, null, null, null, dispatch);
}
public Change(State<CustomerDocument> init,
DocumentType type,
PaymentMethod paymentMethod,
Set<Document.Condition> conditions,
Directive directive,
CustomerFlag customerFlag,
Boolean dispatch) {
this.init = init;
this.type = type;
this.paymentMethod = paymentMethod;
this.conditions = conditions;
this.directive = directive;
this.customerFlag = customerFlag;
this.dispatch = dispatch;
}
public Boolean getDispatch() {
return dispatch;
}
public Collection<RedTapeStateCharacteristic> build() {
Set<RedTapeStateCharacteristic> result = new HashSet<>();
for (StateCharacteristic<CustomerDocument> o : init.getCharacteristics()) {
RedTapeStateCharacteristic rsc = (RedTapeStateCharacteristic)o; // Not nice, but ok.
Set<Condition> newConditions = EnumSet.noneOf(Condition.class);
newConditions.addAll(rsc.getConditions());
if ( conditions != null ) newConditions.addAll(conditions);
Set<CustomerFlag> newFlags = EnumSet.noneOf(CustomerFlag.class);
newFlags.addAll(rsc.getCustomerFlags());
if ( customerFlag != null ) newFlags.add(customerFlag);
result.add(new RedTapeStateCharacteristic(
(type == null ? rsc.getType() : type),
(paymentMethod == null ? rsc.getPaymentMethod() : paymentMethod),
newConditions,
(directive == null ? rsc.getDirective() : directive),
newFlags,
(dispatch == null ? rsc.isDispatch() : dispatch)));
}
return result;
}
}
public RedTapeStateCharacteristic(DocumentType type, PaymentMethod paymentMethod, Set<Document.Condition> conditions, Directive directive,
Set<CustomerFlag> customerFlags, boolean dispatch) {
this.dispatch = dispatch;
this.type = type;
this.paymentMethod = paymentMethod;
this.directive = directive;
if ( conditions != null ) this.conditions.addAll(conditions);
if ( customerFlags != null ) this.customerFlags.addAll(customerFlags);
}
private boolean dispatch;
private DocumentType type;
private PaymentMethod paymentMethod;
private Set<Document.Condition> conditions = EnumSet.noneOf(Document.Condition.class);
private Document.Directive directive;
private Set<CustomerFlag> customerFlags = EnumSet.noneOf(CustomerFlag.class);
public boolean isDispatch() {
return dispatch;
}
public DocumentType getType() {
return type;
}
public PaymentMethod getPaymentMethod() {
return paymentMethod;
}
public Set<Condition> getConditions() {
return EnumSet.copyOf(conditions);
}
public Set<CustomerFlag> getCustomerFlags() {
return EnumSet.copyOf(customerFlags);
}
public Directive getDirective() {
return directive;
}
@Override
public int hashCode() {
int hash = 7;
hash = 13 * hash + (this.dispatch ? 1 : 0);
hash = 13 * hash + (this.type != null ? this.type.hashCode() : 0);
hash = 13 * hash + (this.paymentMethod != null ? this.paymentMethod.hashCode() : 0);
hash = 13 * hash + Objects.hashCode(this.conditions);
hash = 13 * hash + (this.directive != null ? this.directive.hashCode() : 0);
hash = 13 * hash + Objects.hashCode(this.customerFlags);
return hash;
}
@Override
public boolean equals(Object obj) {
if ( obj == null ) return false;
if ( getClass() != obj.getClass() ) return false;
final RedTapeStateCharacteristic other = (RedTapeStateCharacteristic)obj;
if ( this.dispatch != other.dispatch ) return false;
if ( this.type != other.type ) return false;
if ( this.paymentMethod != other.paymentMethod ) return false;
if ( !Objects.equals(this.conditions, other.conditions) ) return false;
if ( this.directive != other.directive ) return false;
if ( !Objects.equals(this.customerFlags, other.customerFlags) ) return false;
return true;
}
@Override
public String toString() {
return "RedTapeStateCharacteristic{" + "dispatch=" + dispatch + ", type=" + type + ", paymentMethod=" + paymentMethod + ", conditions=" + conditions + ", directive=" + directive + ", customerFlags=" + customerFlags + '}';
}
}