/**
* ***************************************************************************
* Copyright (c) 2010 Qcadoo Limited
* Project: Qcadoo MES
* Version: 1.4
* <p>
* This file is part of Qcadoo.
* <p>
* Qcadoo is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation; either version 3 of the License,
* or (at your option) any later version.
* <p>
* 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 Affero General Public License for more details.
* <p>
* You should have received a copy of the GNU Affero General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* ***************************************************************************
*/
package com.qcadoo.mes.basic;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.StrSubstitutor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.qcadoo.mes.basic.constants.AddressFields;
import com.qcadoo.mes.basic.constants.BasicConstants;
import com.qcadoo.mes.basic.constants.CompanyFields;
import com.qcadoo.model.api.DataDefinition;
import com.qcadoo.model.api.DataDefinitionService;
import com.qcadoo.model.api.Entity;
import com.qcadoo.model.api.search.SearchRestrictions;
import com.qcadoo.model.constants.DictionaryFields;
import com.qcadoo.model.constants.DictionaryItemFields;
import com.qcadoo.model.constants.QcadooModelConstants;
@Service
public class BasicService {
private static final String L_MAIN = "01main";
private static final String L_SHIPPING = "02shipping";
private static final String L_ADDRESS_TYPE = "addressType";
private static final String L_GET_NUMBERS_QUERY_TEMPLATE = "SELECT "
+ "SUBSTRING(${NUMBER_FIELD}, '${PREFIX}([0-9]+)') AS ${NUM_PROJECTION_ALIAS}, '' AS nullResultFix "
+ "FROM #basic_address " + "WHERE ${COMPANY_FIELD}.id = ${COMPANY_VALUE} " + "ORDER BY numProjection DESC";
private static final String L_NUM_PROJECTION_ALIAS = "numProjection";
private static final String L_DASH = "-";
@Autowired
private DataDefinitionService dataDefinitionService;
public String getMainAddressType() {
String addressType = null;
Optional<Entity> mayBeMainAddressType = getAddressTypeDictionaryItem(L_MAIN);
if (mayBeMainAddressType.isPresent()) {
Entity mainAddressType = mayBeMainAddressType.get();
addressType = mainAddressType.getStringField(DictionaryItemFields.NAME);
}
return addressType;
}
public String getShippingAddressType() {
String addressType = null;
Optional<Entity> mayBeShippingAddressType = getAddressTypeDictionaryItem(L_SHIPPING);
if (mayBeShippingAddressType.isPresent()) {
Entity shippingAddressType = mayBeShippingAddressType.get();
addressType = shippingAddressType.getStringField(DictionaryItemFields.NAME);
}
return addressType;
}
private Optional<Entity> getAddressTypeDictionaryItem(final String technicalCode) {
Optional<Entity> mayBeAddressType = getAddressTypeDictionary();
if (mayBeAddressType.isPresent()) {
Entity addressType = mayBeAddressType.get();
return Optional.ofNullable(findAddressTypeDictionaryItem(addressType, technicalCode));
}
return Optional.empty();
}
private Entity findAddressTypeDictionaryItem(final Entity addressType, final String technicalCode) {
return getDictionaryItemDD().find().add(SearchRestrictions.belongsTo(DictionaryItemFields.DICTIONARY, addressType))
.add(SearchRestrictions.eq(DictionaryItemFields.TECHNICAL_CODE, technicalCode)).setMaxResults(1).uniqueResult();
}
private Optional<Entity> getAddressTypeDictionary() {
return Optional.ofNullable(findAddressTypeDictionary());
}
private Entity findAddressTypeDictionary() {
return getDictionaryDD().find().add(SearchRestrictions.eq(DictionaryFields.NAME, L_ADDRESS_TYPE)).setMaxResults(1)
.uniqueResult();
}
public Optional<Entity> getMainAddress(final Entity company) {
if (company.getId() != null) {
String addressType = getMainAddressType();
if (StringUtils.isNotEmpty(addressType)) {
return Optional.ofNullable(findMainAddress(company, addressType));
}
}
return Optional.empty();
}
private Entity findMainAddress(final Entity company, final String addressType) {
return getAddressDD().find().add(SearchRestrictions.belongsTo(AddressFields.COMPANY, company))
.add(SearchRestrictions.eq(AddressFields.ADDRESS_TYPE, addressType)).setMaxResults(1).uniqueResult();
}
public String generateAddressNumber(final Entity company) {
String addressNumber = "";
Long greatestNumber = 0L;
if (company.getId() != null) {
Collection<Entity> numberProjections = getNumbersProjection(company);
Collection<Long> numericValues = extractNumericValues(numberProjections);
if (!numericValues.isEmpty()) {
greatestNumber = Ordering.natural().max(numericValues);
}
}
addressNumber = generateNumber(company, greatestNumber + 1);
return addressNumber;
}
private Collection<Entity> getNumbersProjection(final Entity company) {
List<Entity> numbersProjection = Lists.newArrayList();
if (company != null) {
String hqlQuery = buildQuery(company);
numbersProjection = getAddressDD().find(hqlQuery).list().getEntities();
}
return numbersProjection;
}
private String buildQuery(final Entity company) {
String query = "";
if (company != null) {
Map<String, String> placeholderValues = Maps.newHashMap();
placeholderValues.put("NUMBER_FIELD", AddressFields.NUMBER);
placeholderValues.put("PREFIX", createPrefix(company));
placeholderValues.put("NUM_PROJECTION_ALIAS", L_NUM_PROJECTION_ALIAS);
placeholderValues.put("COMPANY_FIELD", AddressFields.COMPANY);
placeholderValues.put("COMPANY_VALUE", company.getId().toString());
StrSubstitutor substitutor = new StrSubstitutor(placeholderValues, "${", "}");
query = substitutor.replace(L_GET_NUMBERS_QUERY_TEMPLATE).toString();
}
return query;
}
private String createPrefix(final Entity company) {
String number = company.getStringField(CompanyFields.NUMBER);
return escapeSql(number) + L_DASH;
}
private String escapeSql(final String number) {
return number.replace("'", "''").replace("(", "\\(").replace(")", "\\)");
}
private Collection<Long> extractNumericValues(final Iterable<Entity> numberProjections) {
List<Long> numericValues = Lists.newArrayList();
for (Entity projection : numberProjections) {
String numberFieldValue = projection.getStringField(L_NUM_PROJECTION_ALIAS);
if (StringUtils.isNumeric(numberFieldValue)) {
numericValues.add(Long.valueOf(numberFieldValue));
}
}
return numericValues;
}
private String generateNumber(final Entity company, final Long number) {
StringBuilder numberBuilder = new StringBuilder();
numberBuilder.append(company.getStringField(CompanyFields.NUMBER));
numberBuilder.append(L_DASH);
numberBuilder.append(String.format("%02d", number));
return numberBuilder.toString();
}
public boolean checkIfIsMainAddressType(final String addressType) {
if (StringUtils.isNotEmpty(addressType)) {
String mainAddressType = getMainAddressType();
if (StringUtils.isNotEmpty(mainAddressType)) {
if (mainAddressType.equals(addressType)) {
return true;
}
}
}
return false;
}
public DataDefinition getDictionaryDD() {
return dataDefinitionService.get(QcadooModelConstants.PLUGIN_IDENTIFIER, QcadooModelConstants.MODEL_DICTIONARY);
}
public DataDefinition getDictionaryItemDD() {
return dataDefinitionService.get(QcadooModelConstants.PLUGIN_IDENTIFIER, QcadooModelConstants.MODEL_DICTIONARY_ITEM);
}
public DataDefinition getAddressDD() {
return dataDefinitionService.get(BasicConstants.PLUGIN_IDENTIFIER, BasicConstants.MODEL_ADDRESS);
}
}