ModeleVerreHelper.java

package com.sintia.ffl.admin.optique.catalogue.helpers;

import com.sintia.ffl.admin.optique.catalogue.batch.reporter.Reporter;
import com.sintia.ffl.admin.optique.catalogue.models.EnrichedGlassesCSV;
import com.sintia.ffl.admin.optique.catalogue.models.GlassesCSV;
import com.sintia.ffl.admin.optique.catalogue.utils.GlassesUtil;
import com.sintia.ffl.admin.optique.dal.entities.Classe;
import com.sintia.ffl.admin.optique.dal.entities.TypeMateriau;
import com.sintia.ffl.admin.optique.dal.entities.TypeVerre;
import com.sintia.ffl.admin.optique.dal.entities.catalogue.DistributeurCatalogue;
import com.sintia.ffl.admin.optique.dal.entities.catalogue.FabricantCatalogue;
import com.sintia.ffl.admin.optique.dal.entities.catalogue.ModeleVerreCatalogue;
import com.sintia.ffl.admin.optique.dal.repositories.ClasseRepository;
import com.sintia.ffl.admin.optique.dal.repositories.catalogue.DistributeurCatalogueRepository;
import com.sintia.ffl.admin.optique.dal.repositories.catalogue.FabricantCatalogueRepository;
import com.sintia.ffl.admin.optique.dal.repositories.catalogue.ModeleVerreCatalogueRepository;
import com.sintia.ffl.admin.optique.dal.repositories.TypeMateriauRepository;
import com.sintia.ffl.admin.optique.dal.repositories.TypeVerreRepository;
import com.sintia.ffl.admin.optique.services.services.ModeleVerreService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Optional;

@Service
@Slf4j
public class ModeleVerreHelper {

	@Autowired
	private TypeVerreRepository typeVerreRepository;

	@Autowired
	private TypeMateriauRepository typeMateriauRepository;

	@Autowired
	private ClasseRepository classeRepository;

	@Autowired
	private ModeleVerreCatalogueRepository modeleVerreRepository;
	
	@Autowired
	private DistributeurCatalogueRepository distributeurRepository;
	
	@Autowired
	private FabricantCatalogueRepository fabricantRepository;
	
	@Autowired
	private ModeleVerreService modeleVerreService;

	@Autowired
	private GlassesUtil glassesUtil;

	/**
	 * Retrieve a new {@link ModeleVerreCatalogue} corresponding to the given enrichedGlass,
	 * that then can be insert in the database
	 *
	 * @param enrichedGlass - Correspond to the data read from an enriched catalog
	 *                      file
	 * @param seizable      - indicate if the new {@link ModeleVerreCatalogue} should tag has
	 *                      seizable or not
	 * @param creationDate  - the date used for all the date type fields
	 * @param reporter      - The reporter that will log the error encounter during
	 *                      the {@link ModeleVerreCatalogue} generation
	 * @return A new {@link ModeleVerreCatalogue} corresponding to the given enrichedGlass,
	 *         or null if a functional error occurs (the error will then be logged
	 *         thru the reporter)
	 */
	public ModeleVerreCatalogue getModeleVerreToCreate(EnrichedGlassesCSV enrichedGlass, boolean seizable,
													   LocalDateTime creationDate, Reporter reporter) {
		if (enrichedGlass == null) {
			throw new IllegalArgumentException("Can't generate a new 'ModeleVerre' from a 'null' EnrichedGlassesCSV");
		}

		TypeVerre glassType = typeVerreRepository.findBycTypeVerre(enrichedGlass.getGeometry());
		TypeMateriau material = typeMateriauRepository.findBycTypeMateriau(enrichedGlass.getMaterial());
		if (enrichedGlass.getClassCode() == null) {
			reporter.addError(String.format("La classe du verre %s/%s/%s est absente du fichier.",
					enrichedGlass.getGlassOptoCode(), enrichedGlass.getMaker(), enrichedGlass.getProvider()));
			return null;
		}
		Classe glassClass = classeRepository.findByCode(enrichedGlass.getClassCode());
		if (glassClass == null){
			if (reporter != null) {
				reporter.addError(String.format("Le verre %s/%s/%s est associé à une classe inexistante : '%s'.",
						enrichedGlass.getGlassOptoCode(), enrichedGlass.getMaker(), enrichedGlass.getProvider(),
						enrichedGlass.getClassCode()));
			}
			return null;
		}
		String seizableStr = seizable ? "1" : "0";
		String cModele = glassesUtil.getCModele(enrichedGlass.getGlassOptoCode(), enrichedGlass.getMaker(), enrichedGlass.getProvider());
		
		Optional<DistributeurCatalogue> distributeur = distributeurRepository.findBycOptoCodeDistributeur(enrichedGlass.getProvider());
		Optional<FabricantCatalogue> fabricant = fabricantRepository.findBycodeOptoCodeFabricant(enrichedGlass.getMaker());
		
		ModeleVerreCatalogue modeleVerre = new ModeleVerreCatalogue(
				glassClass.getIdClasse(), distributeur.map(DistributeurCatalogue::getIdDistributeur).orElse(null),
				fabricant.map(FabricantCatalogue::getIdFabricant).orElse(null), material.getIdTypeMateriau(),
				glassType.getIdTypeVerre(), cModele, enrichedGlass.getGlassName(), enrichedGlass.getRefractiveIndex(),
				seizableStr, creationDate, creationDate, enrichedGlass.getGlassOptoCode(), null,
				creationDate, enrichedGlass.getStartDate());

		if (enrichedGlass.isSurfaceType()) {
			modeleVerreService.generateTraitIntegresAsso(modeleVerre, "AS", creationDate);
		}

		if (enrichedGlass.isHardened()) {
			modeleVerreService.generateTraitIntegresAsso(modeleVerre, "DU", creationDate);
		}

		if (enrichedGlass.isAntiReflection()) {
			modeleVerreService.generateTraitIntegresAsso(modeleVerre, "SAR", creationDate);
		}

		if (enrichedGlass.isPhotochromic()) {
			modeleVerreService.generateTraitIntegresAsso(modeleVerre, "PR", creationDate);
		}

		if (enrichedGlass.isTinted()) {
			modeleVerreService.generateTraitIntegresAsso(modeleVerre, "CO", creationDate);
		}

		return modeleVerre;
	}

	/**
	 * Retrieve the {@link ModeleVerreCatalogue} corresponding to the given enrichedGlass,
	 * and update only the columns indicated in the columns parameter.<br>
	 * The column "bSaisie" is also updated if the previous value was 0.<br>
	 * The columns "dMaj" and "dMajCatalogue" are always updated with the given date
	 *
	 * @param enrichedGlass - Correspond to the data read from an enriched catalog
	 *                      file and must correspond to an existing glass in the
	 *                      database
	 * @param date          - the date use for the dMaj and dMajCatalogue field, and
	 *                      potentially the dDemandeSupp
	 * @param columns       - A string array where each element is the id of the
	 *                      column to update.
	 * @return A {@link ModeleVerreCatalogue} corresponding to the given enrichedGlass, but
	 *         updated
	 */
	public ModeleVerreCatalogue getModeleVerreToUpdate(EnrichedGlassesCSV enrichedGlass, LocalDateTime date, String[] columns,
													   Reporter reporter)
			throws IllegalArgumentException {
		
		ModeleVerreCatalogue glass = modeleVerreRepository.findByCodeOptoVerreAndCodeOptoDistributeurAndCodeOptoFabricant(enrichedGlass.getGlassOptoCode(),
				enrichedGlass.getProvider(), enrichedGlass.getMaker()).get();

		if ("0".equals(glass.getBSaisie())) {
			glass.setBSaisie("1");
		}
		glass.setDateMaj(date);
		glass.setDateMajCatalogue(date);

		for (String column : columns) {
			switch (column) {
				case "C4":
					if (enrichedGlass.getClassCode() == null) {
						reporter.addError(String.format("La classe du verre %s/%s/%s est absente du fichier.",
								enrichedGlass.getGlassOptoCode(), enrichedGlass.getMaker(), enrichedGlass.getProvider()));
						return null;
					}
					Classe glassClass = classeRepository.findByCode(enrichedGlass.getClassCode());
					if (glassClass == null && reporter != null) {
						reporter.addError(String.format("Le verre %s/%s/%s est associé à une classe inexistante : '%s'.",
								enrichedGlass.getGlassOptoCode(), enrichedGlass.getMaker(), enrichedGlass.getProvider(),
								enrichedGlass.getClassCode()));
						return null;
					}
					glass.setIdClasse(glassClass.getIdClasse());
					break;
				case "C6":
					glass.setLModele(enrichedGlass.getGlassName());
					break;
				case "C8":
					TypeVerre glassType = typeVerreRepository.findBycTypeVerre(enrichedGlass.getGeometry());
					glass.setIdTypeVerre(glassType.getIdTypeVerre());
					break;

				case "C10":
					TypeMateriau material = typeMateriauRepository.findBycTypeMateriau(enrichedGlass.getMaterial());
					glass.setIdTypeMateriau(material.getIdTypeMateriau());
					break;

				case "C12":
					if (enrichedGlass.isSurfaceType()) {
						modeleVerreService.generateTraitIntegresAsso(glass, "AS", date);
					} else {
						modeleVerreService.deleteVerreTraitementIntegresAsso(glass, "AS");
					}
					break;
				case "C14":
					if (enrichedGlass.isHardened()) {
						modeleVerreService.generateTraitIntegresAsso(glass, "DU", date);
					} else {
						modeleVerreService.deleteVerreTraitementIntegresAsso(glass, "DU");
					}
					break;
				case "C16":
					if (enrichedGlass.isAntiReflection()) {
						modeleVerreService.generateTraitIntegresAsso(glass, "SAR", date);
					} else {
						modeleVerreService.deleteVerreTraitementIntegresAsso(glass, "SAR");
					}
					break;
				case "C18":
					if (enrichedGlass.isPhotochromic()) {
						modeleVerreService.generateTraitIntegresAsso(glass, "PR", date);
					} else {
						modeleVerreService.deleteVerreTraitementIntegresAsso(glass, "PR");
					}
					break;
				case "C20":
					glass.setNIndice(enrichedGlass.getRefractiveIndex().shortValue());
					break;
				case "C22":
					if (enrichedGlass.isTinted()) {
						modeleVerreService.generateTraitIntegresAsso(glass, "CO", date);
					} else {
						modeleVerreService.deleteVerreTraitementIntegresAsso(glass, "CO");
					}
					break;
				default:
					reporter.addError(
							String.format("Le verre %s/%s/%s, est flagué avec une colonne incorrecte : '%s'",
									enrichedGlass.getGlassOptoCode(), enrichedGlass.getMaker(),
									enrichedGlass.getProvider(), column));
					return null;
			}
		}
		
		if (enrichedGlass.getStartDate() != null) {
			glass.setDateDebutValidite(enrichedGlass.getStartDate());
		} else {
			glass.setDateDebutValidite(date.toLocalDate());
		}
		
		if (enrichedGlass.getExpiryDate() != null) {
			glass.setDateDemandeSupp(enrichedGlass.getExpiryDate());
		} else {
			glass.setDateDemandeSupp(null);
		}

		return glass;
	}

	/**
	 * Retrieve the {@link ModeleVerreCatalogue} corresponding to the given enrichedGlass,
	 * and tag it as '(re)activate' by :
	 * <ul>
	 * <li>Setting the bSaisie to 1 if it previously was 0</li>
	 * <li>Updating both the dMaj and dMajCatalogue with the given date</li>
	 * <li>Removing the dDemandeSupp if none in input, or updating the value with
	 * the new one</li>
	 * </ul>
	 *
	 * @param enrichedGlass - Correspond to the data read from an enriched catalog
	 *                      file and must correspond to an existing glass in the
	 *                      database
	 * @param date          - the date use for the dMaj and dMajCatalogue field
	 * @return A {@link ModeleVerreCatalogue} corresponding to the given enrichedGlass, but
	 *         tag as '(re)activate'
	 */
	public ModeleVerreCatalogue getModeleVerreToReactivate(EnrichedGlassesCSV enrichedGlass, LocalDateTime date) {
		ModeleVerreCatalogue glass = modeleVerreRepository.findByCodeOptoVerreAndCodeOptoDistributeurAndCodeOptoFabricant(enrichedGlass.getGlassOptoCode(),
				enrichedGlass.getProvider(), enrichedGlass.getMaker()).get();
		if ("0".equals(glass.getBSaisie())) {
			glass.setBSaisie("1");
		}
		glass.setDateMaj(date);
		glass.setDateMajCatalogue(date);
		if (enrichedGlass.getExpiryDate() != null) {
			glass.setDateDemandeSupp(enrichedGlass.getExpiryDate());
		} else {
			glass.setDateDemandeSupp(null);
		}

		return glass;
	}

	/**
	 * Retrieve the {@link ModeleVerreCatalogue} corresponding to the given enrichedGlass,
	 * and tag it as 'to expire' by updating its dDemandeSupp.<br>
	 * The expiryDate is set to the one define in the enrichedGlass, unless it isn't
	 * defined, then use the given date
	 *
	 * @param enrichedGlass - Correspond to the data read from an enriched catalog
	 *                      file and must correspond to an existing glass in the
	 *                      database
	 * @param date          - the date use for the dMaj and dMajCatalogue field, and
	 *                      potentially the dDemandeSupp
	 * @return A {@link ModeleVerreCatalogue} corresponding to the given enrichedGlass, but
	 *         tag as 'to expire'
	 */
	public ModeleVerreCatalogue getModeleVerreToExpire(EnrichedGlassesCSV enrichedGlass, LocalDateTime date) {
		ModeleVerreCatalogue glass = modeleVerreRepository.findByCodeOptoVerreAndCodeOptoDistributeurAndCodeOptoFabricant(enrichedGlass.getGlassOptoCode(),
				enrichedGlass.getProvider(), enrichedGlass.getMaker()).get();
		glass.setDateMaj(date);
		glass.setDateMajCatalogue(date);
		if (enrichedGlass.getExpiryDate() != null) {
			glass.setDateDemandeSupp(enrichedGlass.getExpiryDate());
		} else {
			glass.setDateDemandeSupp(date.toLocalDate());
		}
		return glass;
	}
	/**
	 * Calculate the action code delta for the given enrichedGlasses<br>
	 * The returned value can be :
	 * <ul>
	 * <li>SA : nothing to do</li>
	 * <li>C : the glasses must be created</li>
	 * <li>MAJDDP : the glasses expiry date must be updated</li>
	 * <li>some column numbers, separated by ',' : the corresponding column in the
	 * enriched catalog must be updated</li>
	 * </ul>
	 *
	 * @param enrichedGlasses
	 * @return
	 */
	public String calculateActionCodeDelta(EnrichedGlassesCSV enrichedGlasses) {
		String result;
		if (!modeleVerreService.exist(enrichedGlasses.getMaker(), enrichedGlasses.getProvider(), enrichedGlasses.getGlassOptoCode())) {
			if ("S".equals(enrichedGlasses.getAction())) {
				result = "SA";
			} else {
				result = "C";
			}
		} else {
			if ("S".equals(enrichedGlasses.getAction())) {
				result = "MAJDDP";
			} else {
				result = "SA";
				String column = "";
				if (!enrichedGlasses.getClassCode()
						.equals(enrichedGlasses.getClassCodeRepo())) {
					column += "C4,";
				}
				if (!enrichedGlasses.getGlassName()
						.equals(enrichedGlasses.getGlassNameRepo())) {
					column += "C6,";
				}
				if (!enrichedGlasses.getGeometry()
						.equals(enrichedGlasses.getGeometryRepo())) {
					column += "C8,";
				}
				if (!enrichedGlasses.getMaterial()
						.equals(enrichedGlasses.getMaterialRepo())) {
					column += "C10,";
				}
				if (enrichedGlasses.isSurfaceType() != enrichedGlasses.isSurfaceTypeRepo()) {
					column += "C12,";
				}
				if (enrichedGlasses.isHardened() != enrichedGlasses.isHardenedRepo()) {
					column += "C14,";
				}
				if (enrichedGlasses.isAntiReflection() != enrichedGlasses.isAntiReflectionRepo()) {
					column += "C16,";
				}
				if (enrichedGlasses.isPhotochromic() != enrichedGlasses.isPhotochromicRepo()) {
					column += "C18,";
				}
				if (!enrichedGlasses.getRefractiveIndex()
						.equals(enrichedGlasses.getRefractiveIndexRepo())) {
					column += "C20,";
				}
				if (enrichedGlasses.isTinted() != enrichedGlasses.isTintedRepo()) {
					column += "C22,";
				}
				if (!"".equals(column)) {
					result = column.substring(0, column.length() - 1);
				}
			}
		}
		return result;
	}

	/**
	 * Expire in the database the glass corresponding to the given glassCSV, by
	 * setting the current date in its dDemandeSupp field
	 *
	 * @param glassCSV contains the id for the glass to expire
	 */
	public void expireGlass(GlassesCSV glassCSV, LocalDateTime expireDate) {
		if (glassCSV != null) {
			ModeleVerreCatalogue mdlVerre = modeleVerreRepository.findByCodeOptoVerreAndCodeOptoDistributeurAndCodeOptoFabricant(glassCSV.getGlassOptoCode(),
					glassCSV.getProvider(), glassCSV.getMaker()).get();
			mdlVerre.setDateMaj(expireDate);
			mdlVerre.setDateDemandeSupp(expireDate.toLocalDate());
			modeleVerreRepository.save(mdlVerre);
		} else {
			log.warn("The given glass is null, can't expire it.");
		}
	}


}