/* This file is part of Cyclos (www.cyclos.org). A project of the Social Trade Organisation (www.socialtrade.org). Cyclos 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 2 of the License, or (at your option) any later version. Cyclos 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 Cyclos; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package nl.strohalm.cyclos.controls.reports.simulations; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.List; import javax.servlet.http.HttpServletRequest; import nl.strohalm.cyclos.annotations.Inject; import nl.strohalm.cyclos.controls.ActionContext; import nl.strohalm.cyclos.controls.BaseFormAction; import nl.strohalm.cyclos.controls.reports.statistics.graphs.StatisticalDataProducer; import nl.strohalm.cyclos.entities.accounts.fees.transaction.SimpleTransactionFee; import nl.strohalm.cyclos.entities.accounts.fees.transaction.SimpleTransactionFee.ARateRelation; import nl.strohalm.cyclos.entities.accounts.fees.transaction.TransactionFee; import nl.strohalm.cyclos.entities.accounts.fees.transaction.TransactionFee.ChargeType; import nl.strohalm.cyclos.entities.accounts.transactions.TransferType; import nl.strohalm.cyclos.entities.settings.LocalSettings; import nl.strohalm.cyclos.entities.settings.events.LocalSettingsChangeListener; import nl.strohalm.cyclos.entities.settings.events.LocalSettingsEvent; import nl.strohalm.cyclos.services.accounts.rates.ARatedFeeDTO; import nl.strohalm.cyclos.services.accounts.rates.RateService; import nl.strohalm.cyclos.services.stats.StatisticalResultDTO; import nl.strohalm.cyclos.services.transfertypes.TransactionFeeService; import nl.strohalm.cyclos.services.transfertypes.TransferTypeService; import nl.strohalm.cyclos.utils.RequestHelper; import nl.strohalm.cyclos.utils.binding.BeanBinder; import nl.strohalm.cyclos.utils.binding.DataBinder; import nl.strohalm.cyclos.utils.binding.PropertyBinder; import org.apache.struts.action.ActionForward; /** * Action for the Simulation of the ARate Configuration, showing the ARate curve in a graph. * @author Rinke * */ public class ARateConfigSimulationAction extends BaseFormAction implements LocalSettingsChangeListener { private DataBinder<ARatedFeeDTO> dataBinder; private TransferTypeService transferTypeService; private RateService rateService; private TransactionFeeService transactionFeeService; @Override public void onLocalSettingsUpdate(final LocalSettingsEvent event) { dataBinder = null; } @Inject public void setRateService(final RateService rateService) { this.rateService = rateService; } @Inject public void setTransactionFeeService(final TransactionFeeService transactionFeeService) { this.transactionFeeService = transactionFeeService; } @Inject public void setTransferTypeService(final TransferTypeService transferTypeService) { this.transferTypeService = transferTypeService; } @Override protected ActionForward handleSubmit(final ActionContext context) throws Exception { final HttpServletRequest request = context.getRequest(); final RateConfigSimulationForm form = context.getForm(); if (form.isReloadData()) { return handleDisplay(context); } final ARatedFeeDTO dto = getDataBinder().readFromString(form.getSimulation()); final List<StatisticalDataProducer> dataList = new ArrayList<StatisticalDataProducer>(); final StatisticalResultDTO rawDataObject = rateService.getRateConfigGraph(dto); final StatisticalDataProducer producer = new StatisticalDataProducer(rawDataObject, context); final LocalSettings localSettings = settingsService.getLocalSettings(); producer.setSettings(localSettings); dataList.add(producer); request.setAttribute("dataList", dataList); prepareForm(context); return context.getInputForward(); } @SuppressWarnings("unchecked") @Override protected void prepareForm(final ActionContext context) throws Exception { final RateConfigSimulationForm form = context.getForm(); final HttpServletRequest request = context.getRequest(); final ARatedFeeDTO dto = getDataBinder().readFromString(form.getSimulation()); // store necessary radio button cats final Collection<ChargeType> chargeTypes = EnumSet.of(ChargeType.A_RATE, ChargeType.MIXED_A_D_RATES); request.setAttribute("chargeTypes", chargeTypes); RequestHelper.storeEnum(request, ARateRelation.class, "aRateRelations"); // get the relevant TT's final List<TransferType> aRatedTTs = transferTypeService.listARatedTTs(); TransferType tt = dto.getTransferType(); // if more than 1, just take the first final boolean firstTime = (tt == null); if (tt == null && aRatedTTs.size() > 0) { tt = aRatedTTs.get(0); } // get the fees belonging to the tt if (tt != null) { tt = transferTypeService.load(tt.getId(), TransferType.Relationships.TRANSACTION_FEES); } final Collection<? extends TransactionFee> fees; if (tt == null) { fees = Collections.emptyList(); } else { fees = tt.getARatedFees(); } // set some defaults independent in case of no tt's or fees ARateRelation arateRelation = dto.getfInfinite() == null ? ARateRelation.LINEAR : ARateRelation.ASYMPTOTICAL; if (arateRelation == null) { arateRelation = ARateRelation.LINEAR; } if (dto.getChargeType() == null) { dto.setChargeType(ChargeType.A_RATE); } // if needed fill the fields if (tt != null && (firstTime || form.isReloadData())) { // load fee if already set TransactionFee fee = dto.getTransactionFee(); if (fee != null) { fee = transactionFeeService.load(fee.getId(), TransactionFee.Relationships.ORIGINAL_TRANSFER_TYPE); } // only take first fee if existing fee doesn't belong to this tt if (!(fee != null && fee.getOriginalTransferType().equals(tt))) { fee = ((List<TransactionFee>) fees).get(0); } if (fee != null && (fee instanceof SimpleTransactionFee)) { final SimpleTransactionFee simpleFee = (SimpleTransactionFee) fee; dto.setChargeType(fee.getChargeType()); arateRelation = simpleFee.getfInfinite() == null ? ARateRelation.LINEAR : ARateRelation.ASYMPTOTICAL; dto.setH(simpleFee.getH()); dto.setaFIsZero(simpleFee.getaFIsZero()); dto.setF1(simpleFee.getF1()); dto.setfInfinite(simpleFee.getfInfinite()); dto.setfMinimal(simpleFee.getfMinimal()); dto.setgFIsZero(simpleFee.getgFIsZero()); } } if (firstTime) { dto.setRangeStart(0); dto.setRangeEnd(arateRelation == ARateRelation.ASYMPTOTICAL ? 100 : 30); } dto.setTransferType(tt); form.setSimulation("aRateRelation", arateRelation.name()); getDataBinder().writeAsString(form.getSimulation(), dto); request.setAttribute("tts", aRatedTTs); if (aRatedTTs.size() == 1) { request.setAttribute("singleTT", "true"); } request.setAttribute("fees", fees); if (fees.size() == 1) { request.setAttribute("singleFee", "true"); } request.setAttribute("simulation", "true"); } @Override protected void validateForm(final ActionContext context) { final RateConfigSimulationForm form = context.getForm(); final ARatedFeeDTO dto = getDataBinder().readFromString(form.getSimulation()); final ARateRelation aRateRelation = PropertyBinder.instance(ARateRelation.class, "aRateRelation").readFromString(form.getSimulation()); rateService.validate(dto, aRateRelation); } private DataBinder<ARatedFeeDTO> getDataBinder() { if (dataBinder == null) { final LocalSettings localSettings = settingsService.getLocalSettings(); final BeanBinder<ARatedFeeDTO> binder = BeanBinder.instance(ARatedFeeDTO.class); binder.registerBinder("transferType", PropertyBinder.instance(TransferType.class, "transferType")); binder.registerBinder("transactionFee", PropertyBinder.instance(TransactionFee.class, "transactionFee")); binder.registerBinder("chargeType", PropertyBinder.instance(ChargeType.class, "chargeType")); binder.registerBinder("h", PropertyBinder.instance(BigDecimal.class, "h", localSettings.getHighPrecisionConverter())); binder.registerBinder("aFIsZero", PropertyBinder.instance(BigDecimal.class, "aFIsZero", localSettings.getHighPrecisionConverter())); binder.registerBinder("f1", PropertyBinder.instance(BigDecimal.class, "f1", localSettings.getHighPrecisionConverter())); binder.registerBinder("fInfinite", PropertyBinder.instance(BigDecimal.class, "fInfinite", localSettings.getHighPrecisionConverter())); binder.registerBinder("fMinimal", PropertyBinder.instance(BigDecimal.class, "fMinimal", localSettings.getHighPrecisionConverter())); binder.registerBinder("gFIsZero", PropertyBinder.instance(BigDecimal.class, "gFIsZero", localSettings.getHighPrecisionConverter())); binder.registerBinder("rangeStart", PropertyBinder.instance(Integer.class, "rangeStart")); binder.registerBinder("rangeEnd", PropertyBinder.instance(Integer.class, "rangeEnd")); dataBinder = binder; } return dataBinder; } }