/*
* 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.receipt.unit;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.util.*;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import eu.ggnet.dwoss.mandator.MandatorSupporter;
import eu.ggnet.dwoss.receipt.UnitSupporter;
import eu.ggnet.dwoss.receipt.UiProductSupport;
import eu.ggnet.dwoss.receipt.unit.UnitModel.MetaValue;
import eu.ggnet.dwoss.receipt.unit.chain.ChainLink;
import eu.ggnet.dwoss.receipt.unit.chain.ChainLink.Result;
import eu.ggnet.dwoss.receipt.unit.chain.Chains;
import eu.ggnet.dwoss.rules.ReceiptOperation;
import eu.ggnet.dwoss.spec.SpecAgent;
import eu.ggnet.dwoss.spec.format.SpecFormater;
import eu.ggnet.dwoss.uniqueunit.UniqueUnitAgent;
import eu.ggnet.dwoss.uniqueunit.entity.UniqueUnit;
import eu.ggnet.dwoss.util.UserInfoException;
import eu.ggnet.dwoss.common.DwOssCore;
import eu.ggnet.dwoss.util.validation.ValidationUtil;
import lombok.Getter;
import lombok.Setter;
import static eu.ggnet.saft.core.Client.lookup;
import static eu.ggnet.dwoss.rules.ReceiptOperation.*;
import static javax.swing.JOptionPane.*;
public class UnitController {
private class OperationAction extends AbstractAction {
private final ReceiptOperation operation;
public OperationAction(ReceiptOperation operation) {
super(operation.getNote());
this.operation = operation;
setEnabled(false);
}
@Override
public void actionPerformed(ActionEvent e) {
String comment = showInputDialog(view, "Unit in den Process " + operation + " übergeben ?", "Frage", OK_CANCEL_OPTION);
if ( comment == null ) return;
model.setOperation(operation);
model.setOperationComment(comment);
view.setCancel(false);
view.setVisible(false);
}
}
private class SaleableAction extends AbstractAction {
public SaleableAction() {
super("In den Verkauf");
setEnabled(false);
}
@Override
public void actionPerformed(ActionEvent e) {
if ( showConfirmDialog(view, "Unit zum Verkauf freigeben ?", "Frage", YES_NO_OPTION) != YES_OPTION ) return;
model.setOperation(ReceiptOperation.SALEABLE);
view.setCancel(false);
view.setVisible(false);
}
}
private class InSaleAction extends AbstractAction {
public InSaleAction() {
super("Änderungen übernehmen");
setEnabled(false);
}
@Override
public void actionPerformed(ActionEvent e) {
model.setOperation(ReceiptOperation.IN_SALE);
view.setCancel(false);
view.setVisible(false);
}
}
private static final Logger L = LoggerFactory.getLogger(UnitController.class);
@Getter
@Setter
private UnitView view;
// TODO: Add in the usage actions. for now its ok.
@Getter
@Setter
private UnitModel model;
private final UiProductSupport uiProductSupport = new UiProductSupport();
/**
* Init the controller, call after setting view an model.
*/
public void init() {
Objects.requireNonNull(model, "Model is null");
Objects.requireNonNull(view, "View is null");
Objects.requireNonNull(view.getController(), "View has no controller");
Objects.requireNonNull(view.getModel(), "View has no model");
ValidationUtil.validate(model);
UniqueUnit uu = view.getUnit();
if ( uu.getId() > 0 ) model.setEditMode(true);
if ( uu.getProduct() != null ) model.setMode(uu.getProduct().getTradeName().getManufacturer());
view.updateMode();
updateChains();
validateAll();
if ( model.getOperation() == IN_SALE ) {
// This Unit is not available so only simple changes are allowed and no RedTape Modifikation.
addClosingAction(new InSaleAction());
return;
}
addClosingAction(new SaleableAction());
lookup(MandatorSupporter.class).loadReceiptCustomers().enabledOperations(model.getContractor())
.stream().forEach(r -> addClosingAction(new OperationAction(r)));
}
public void createOrEditPart(String partNo) throws UserInfoException {
if ( uiProductSupport != null ) uiProductSupport.createOrEditPart(model.getMode(), partNo, view);
validatePartNoAndLoadDetails();
}
public void validateRefurbishedId() {
final MetaValue<String> value = model.getMetaUnit().getRefurbishId();
new SwingWorker<String, Object>() {
@Override
protected String doInBackground() throws Exception {
L.debug("Validating refurbishId : {}", value.getValue());
return validateValue(value.getValue(), value.getChain(), value.getSurvey());
}
@Override
protected void done() {
try {
model.getMetaUnit().getRefurbishId().setValue(get());
} catch (InterruptedException | ExecutionException ex) {
DwOssCore.show(view, ex);
} finally {
view.updateMetaUnit();
}
}
}.execute();
}
public void validatePartNoAndLoadDetails() {
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
MetaValue<String> value = model.getMetaUnit().getPartNo();
L.debug("Validating partNo : {}", value.getValue());
value.setValue(validateValue(value.getValue(), value.getChain(), value.getSurvey()));
if ( value.getSurvey().isOkOrWarn() ) {
L.debug("Loading Details for PartNo: {}", value.getValue());
// Load details for update.
model.setProduct(lookup(UniqueUnitAgent.class).findProductByPartNo(value.getValue()));
model.setProductSpecDescription(SpecFormater.toHtml(lookup(SpecAgent.class).findProductSpecByPartNoEager(value.getValue())));
} else {
L.debug("Removeing PartNo Details.");
model.setProduct(null);
model.setProductSpecDescription("");
}
return null;
}
@Override
protected void done() {
try {
get();
} catch (InterruptedException | ExecutionException ex) {
DwOssCore.show(view, ex);
} finally {
view.updateMetaUnit();
view.updateProduct();
}
}
}.execute();
}
public void validateSerial() {
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
MetaValue<String> value = model.getMetaUnit().getSerial();
L.debug("Validating serial : {}", value.getValue());
value.setValue(validateValue(value.getValue(), value.getChain(), value.getSurvey()));
return null;
}
@Override
protected void done() {
try {
get();
} catch (InterruptedException | ExecutionException ex) {
DwOssCore.show(view, ex);
} finally {
view.updateMetaUnit();
}
}
}.execute();
}
public void validateMfgDate() {
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
MetaValue<Date> value = model.getMetaUnit().getMfgDate();
L.debug("Validating mfgDate : {}", value.getValue());
value.setValue(validateValue(value.getValue(), value.getChain(), value.getSurvey()));
return null;
}
@Override
protected void done() {
try {
get();
} catch (InterruptedException | ExecutionException ex) {
DwOssCore.show(view, ex);
} finally {
view.updateMetaUnit();
}
}
}.execute();
}
public void editRefurbishedId(String refurbishId) {
String newRefurbishId = JOptionPane.showInputDialog(view, "SopoNr:", refurbishId);
if ( newRefurbishId == null ) return;
// TODO: Push this through the Validation Chain.
newRefurbishId = newRefurbishId.trim();
if ( newRefurbishId.equals("") ) return;
if ( newRefurbishId.equals(refurbishId) ) return;
if ( lookup(UnitSupporter.class).isRefurbishIdAvailable(refurbishId) ) {
model.getMetaUnit().getRefurbishId().setValue(refurbishId);
view.updateMetaUnit();
} else {
JOptionPane.showMessageDialog(view, "SopoNr nicht verfügbar", "Fehler", JOptionPane.ERROR_MESSAGE);
}
}
void validateAll() {
validateRefurbishedId();
validateSerial();
validatePartNoAndLoadDetails();
validateMfgDate();
}
private <T> T validateValue(T value, List<ChainLink<T>> chain, UnitModel.Survey validationStatus) {
validationStatus.validating("Wert wird geprüft");
view.updateValidationStatus();
Result<T> result = Chains.execute(chain, value);
L.debug("After Chain (optionals={}, metaunit.partno.isSet={}, metaunit.mfgDate.isSet={}) : {}",
result.hasOptionals(), model.getMetaUnit().getPartNo().isSet(), model.getMetaUnit().getMfgDate().isSet(), result);
if ( result.hasOptionals() && result.getOptional().getPartNo() != null && !model.getMetaUnit().getPartNo().isSet() ) {
model.getMetaUnit().getPartNo().setValue(result.getOptional().getPartNo());
validatePartNoAndLoadDetails();
}
if ( result.hasOptionals() && result.getOptional().getMfgDate() != null && !model.getMetaUnit().getMfgDate().isSet() ) {
model.getMetaUnit().getMfgDate().setValue(result.getOptional().getMfgDate());
validateMfgDate();
}
validationStatus.setStatus(result.getValid(), result.getMessage());
view.updateValidationStatus();
updateActions();
return result.getValue();
}
void updateChains() {
L.debug("updateChains called with {}", model.getMode());
UnitModel.MetaUnit metaUnit = model.getMetaUnit();
Chains chains = Chains.getInstance(model.getMode());
metaUnit.getRefurbishId().setChain(chains.newRefubishIdChain(model.getContractor(), lookup(UnitSupporter.class), model.isEditMode()));
metaUnit.getSerial().setChain(chains.newSerialChain(lookup(UnitSupporter.class), (model.isEditMode() ? metaUnit.getRefurbishId().getValue() : null)));
metaUnit.getPartNo().setChain(chains.newPartNoChain(lookup(SpecAgent.class), lookup(MandatorSupporter.class).loadContractors().allowedBrands()));
metaUnit.getMfgDate().setChain(chains.newMfgDateChain());
}
void updateActions() {
final boolean enabled = model.getMetaUnit().isOkOrWarn();
final List<Action> updateActions = changedActions(enabled);
if ( updateActions == null ) return;
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
for (Action action : updateActions) {
action.setEnabled(enabled);
}
}
});
}
private List<Action> changedActions(boolean enabled) {
List<Action> updateActions = null;
for (Action action : model.getActions()) {
if ( enabled != action.isEnabled() ) {
if ( updateActions == null ) updateActions = new ArrayList<>();
updateActions.add(action);
}
}
return updateActions;
}
private void addClosingAction(Action action) {
model.addAction(action);
view.addOperationAction(action);
}
}