/**
 * Copyright © CENRA (2016)
 *
 * remi.clement@espaces-naturels.fr
 *
 * This software is a multi-platform and portable application based on
 * the scientifical toolbox to monitor wetlands. With this toolbox it’s
 * possible to calculate indicators «RhoMéO» to monitor quality,
 * fonctionalities and urban and agricultural pressures of wetlands.
 * Indicators are calculated using naturalist data entered and/or imported,
 * and geographic data downloaded from a geographic server.
 *
 * This software is governed by the CeCILL license under French law and
 * abiding by the rules of distribution of free software.  You can  use,
 * modify and/ or redistribute the software under the terms of the CeCILL
 * license as circulated by CEA, CNRS and INRIA at the following URL
 * "http://www.cecill.info".
 *
 * As a counterpart to the access to the source code and  rights to copy,
 * modify and redistribute granted by the license, users are provided only
 * with a limited warranty  and the software's author,  the holder of the
 * economic rights,  and the successive licensors  have only  limited
 * liability.
 *
 * In this respect, the user's attention is drawn to the risks associated
 * with loading,  using,  modifying and/or developing or reproducing the
 * software by the user in light of its specific status of free software,
 * that may mean  that it is complicated to manipulate,  and  that  also
 * therefore means  that it is reserved for developers  and  experienced
 * professionals having in-depth computer knowledge. Users are therefore
 * encouraged to load and test the software's suitability as regards their
 * requirements in conditions enabling the security of their systems and/or
 * data to be ensured and,  more generally, to use and operate it in the
 * same conditions as regards security.
 *
 * The fact that you are presently reading this means that you have had
 * knowledge of the CeCILL license and that you accept its terms.
*/
package fr.cenra.rhomeo.protocol.p01;

import fr.cenra.rhomeo.api.annotations.RefersTo;
import fr.cenra.rhomeo.api.data.Statement;
import fr.cenra.rhomeo.api.data.Warning;
import fr.cenra.rhomeo.core.list.VonPost;
import fr.cenra.rhomeo.protocol.p01.list.Abundance;
import fr.cenra.rhomeo.protocol.p01.list.Adhesiveness;
import fr.cenra.rhomeo.protocol.p01.list.AlterationMO;
import fr.cenra.rhomeo.protocol.p01.list.Chroma;
import fr.cenra.rhomeo.protocol.p01.list.Clarity;
import fr.cenra.rhomeo.protocol.p01.list.Color;
import fr.cenra.rhomeo.protocol.p01.list.Compacity;
import fr.cenra.rhomeo.protocol.p01.list.Friability;
import fr.cenra.rhomeo.protocol.p01.list.Humidity;
import fr.cenra.rhomeo.protocol.p01.list.Limits;
import fr.cenra.rhomeo.protocol.p01.list.Plasticity;
import fr.cenra.rhomeo.protocol.p01.list.RawElements;
import fr.cenra.rhomeo.protocol.p01.list.Roots;
import fr.cenra.rhomeo.protocol.p01.list.Shape;
import fr.cenra.rhomeo.protocol.p01.list.Size;
import fr.cenra.rhomeo.protocol.p01.list.Stains;
import fr.cenra.rhomeo.protocol.p01.list.Structure;
import fr.cenra.rhomeo.protocol.p01.list.Texture;
import java.time.LocalDate;
import java.util.Objects;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotBlank;

/**
 *
 * @author Samuel Andrés (Geomatys)
 */
public class PedologyStatement extends Statement {

    private final IntegerProperty numberHProperty = new SimpleIntegerProperty();

    private final SimpleObjectProperty<Integer> depthProperty = new SimpleObjectProperty();

    private final IntegerProperty limitsProperty = new SimpleIntegerProperty();

    private final StringProperty colorProperty = new SimpleStringProperty();

    private final StringProperty valueProperty = new SimpleStringProperty();

    private final StringProperty chromaProperty = new SimpleStringProperty();

    private final IntegerProperty textureProperty = new SimpleIntegerProperty();

    private final IntegerProperty structureProperty = new SimpleIntegerProperty();

    private final IntegerProperty rawElementsProperty = new SimpleIntegerProperty();

    private final IntegerProperty rootsProperty = new SimpleIntegerProperty();

    private final IntegerProperty stainsProperty = new SimpleIntegerProperty();

    private final IntegerProperty abundanceProperty = new SimpleIntegerProperty();

    private final IntegerProperty sizeProperty = new SimpleIntegerProperty();

    private final IntegerProperty shapeProperty = new SimpleIntegerProperty();

    private final IntegerProperty humidityProperty = new SimpleIntegerProperty();

    private final IntegerProperty compactnessProperty = new SimpleIntegerProperty();

    private final IntegerProperty plasticityProperty = new SimpleIntegerProperty();

    private final IntegerProperty adhesivenessProperty = new SimpleIntegerProperty();

    private final IntegerProperty friabilityProperty = new SimpleIntegerProperty();

    private final IntegerProperty alterationMoProperty = new SimpleIntegerProperty();

    private final StringProperty vonPostProperty = new SimpleStringProperty();

    public PedologyStatement() {

    }

    /**
     *
     * @param trackingPoint
     * @param date
     * @param remarks
     * @param numberH
     * @param depth
     * @param limits
     * @param color
     * @param value
     * @param chroma
     * @param texture
     * @param structure
     * @param rawElements
     * @param roots
     * @param stains
     * @param abundance Not null. Set to 0 for no abundance value.
     * @param size
     * @param shape
     * @param humidity
     * @param compactness
     * @param plasticity
     * @param adhesiveness
     * @param friability
     * @param alterationMo
     * @param vonPost
     */
    public PedologyStatement(final String trackingPoint, final LocalDate date,
            final String remarks, final int numberH, final int depth,
            final int limits, final String color, final String value,
            final String chroma, final int texture, final int structure,
            final int rawElements, final int roots, final int stains,
            final int abundance, final int size, final int shape,
            final int humidity, final int compactness, final int plasticity,
            final int adhesiveness, final int friability,
            final int alterationMo, final String vonPost) {
        super(trackingPoint, date);

        this.remarksProperty.set(remarks);
        this.numberHProperty.set(numberH);
        this.depthProperty.set(depth);
        this.limitsProperty.set(limits);
        this.colorProperty.set(color);
        this.valueProperty.set(value);
        this.chromaProperty.set(chroma);
        this.textureProperty.set(texture);
        this.structureProperty.set(structure);
        this.rawElementsProperty.set(rawElements);
        this.rootsProperty.set(roots);
        this.stainsProperty.set(stains);
        this.abundanceProperty.set(abundance);
        this.sizeProperty.set(size);
        this.shapeProperty.set(shape);
        this.humidityProperty.set(humidity);
        this.compactnessProperty.set(compactness);
        this.plasticityProperty.set(plasticity);
        this.adhesivenessProperty.set(adhesiveness);
        this.friabilityProperty.set(friability);
        this.alterationMoProperty.set(alterationMo);
        this.vonPostProperty.set(vonPost);
    }

    public IntegerProperty numberHProperty(){return numberHProperty;}

    public SimpleObjectProperty<Integer> depthProperty(){return depthProperty;}

    public IntegerProperty limitsProperty(){return limitsProperty;}

    public StringProperty colorProperty(){return colorProperty;}

    public StringProperty valueProperty(){return valueProperty;}

    public StringProperty chromaProperty(){return chromaProperty;}

    public IntegerProperty textureProperty(){return textureProperty;}

    public IntegerProperty structureProperty(){return structureProperty;}

    public IntegerProperty rawElementsProperty(){return rawElementsProperty;}

    public IntegerProperty rootsProperty(){return rootsProperty;}

    public IntegerProperty stainsProperty(){return stainsProperty;}

    public IntegerProperty abundanceProperty(){return abundanceProperty;}

    public IntegerProperty sizeProperty(){return sizeProperty;}

    public IntegerProperty shapeProperty(){return shapeProperty;}

    public IntegerProperty humidityProperty(){return humidityProperty;}

    public IntegerProperty compactnessProperty(){return compactnessProperty;}

    public IntegerProperty plasticityProperty(){return plasticityProperty;}

    public IntegerProperty adhesivenessProperty(){return adhesivenessProperty;}

    public IntegerProperty friabilityProperty(){return friabilityProperty;}

    public IntegerProperty alterationMoProperty(){return alterationMoProperty;}

    public StringProperty vonPostProperty(){return vonPostProperty;}

    public void setNumberH(final int numberH){numberHProperty.set(numberH);}

    public void setDepth(final int depth){depthProperty.set(depth);}

    public void setDepth(final Integer depth){depthProperty.set(depth);}

    public void setLimits(final int limits){limitsProperty.set(limits);}

    public void setColor(final String color){colorProperty.set(color);}

    public void setValue(final String value){valueProperty.set(value);}

    public void setChroma(final String chroma){chromaProperty.set(chroma);}

    public void setTexture(final int texture){textureProperty.set(texture);}

    public void setStructure(final int structure){structureProperty.set(structure);}

    public void setRawElements(final int rawElements){rawElementsProperty.set(rawElements);}

    public void setRoots(final int roots){rootsProperty.set(roots);}

    public void setStains(final int stains){stainsProperty.set(stains);}

    public void setAbundance(final int abundance){abundanceProperty.set(abundance);}

    public void setSize(final int size){sizeProperty.set(size);}

    public void setShape(final int shape){shapeProperty.set(shape);}

    public void setHumidity(final int humidity){humidityProperty.set(humidity);}

    public void setCompactness(final int compactness){compactnessProperty.set(compactness);}

    public void setPlasticity(final int plasticity){plasticityProperty.set(plasticity);}

    public void setAdhesiveness(final int adhesiveness){adhesivenessProperty.set(adhesiveness);}

    public void setFriability(final int friability){friabilityProperty.set(friability);}

    public void setAlterationMo(final int alterationMo){alterationMoProperty.set(alterationMo);}

    public void setVonPost(final String vonPost){vonPostProperty.set(vonPost);}

    /**
     * NUMERO_H.
     *
     * (Source : CCTP)
     *
     * "Numéro du prélèvement de sol [(horizon)]."
     *
     * (Source : rhomeo_base_install.sql)
     *
     * @return
     */
    @Min(1)
    @NotNull
    public int getNumberH() {
        return numberHProperty.get();
    }

    /**
     * PROFONDEUR.
     *
     * (Source : CCTP)
     *
     * "Profondeur maximale [d'un] horizon."
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @Min(value = 1, payload = Warning.class)
    public int getDepth() {
        // If depth is null, we consider we're on a bottom one, where user might not know max depth.
        return depthProperty.get() == null? Integer.MAX_VALUE : depthProperty.get();
    }

    /**
     * LIMITES.
     *
     * (Source : CCTP)
     *
     * Bloc A.
     *
     * Codes :
     * 1 => régulière
     * 2 => ondulée
     * 3 => irrégulière
     * 4 => interrompue
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Limits.class, property="code", payload = Warning.class)
    @NotNull(payload=Warning.class)
    public int getLimits() {
        return limitsProperty.get();
    }

    /**
     * COLOR.
     *
     * (Source : CCTP)
     *
     * "teinte 'hue'."
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Color.class, property="code", payload = Warning.class)
    @NotBlank(payload=Warning.class)
    public String getColor() {
        return colorProperty.get();
    }

    /**
     * VALUE.
     *
     * (Source : CCTP)
     *
     * "clarté 'value' […] de la charte Munsell."
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Clarity.class, property="code", payload = Warning.class)
    @NotBlank(payload=Warning.class)
    public String getValue() {
        return valueProperty.get();
    }

    /**
     * CHROMA.
     *
     * (Source : CCTP)
     *
     * "pureté 'chroma' […] de la charte Munsell."
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Chroma.class, property="code", payload = Warning.class)
    @NotBlank(payload=Warning.class)
    public String getChroma() {
        return chromaProperty.get();
    }

    /**
     * TEXTURE.
     *
     * (Source : CCTP)
     *
     * Bloc C.
     *
     * Codes :
     * 1 => organique
     * 2 => sableuse
     * 3 => limoneuse
     * 4 => argileuse
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Texture.class, property="code", payload = Warning.class)
    @NotNull(payload=Warning.class)
    public int getTexture() {
        return textureProperty.get();
    }

    /**
     * STRUCTURE.
     *
     * (Source : CCTP)
     *
     * Bloc D.
     *
     * Codes :
     * 1 => particulaire
     * 2 => grumeleuse
     * 3 => grenue
     * 4 => massive
     * 5 => lammellaire
     * 6 => prismatique
     * 7 => en colonnes
     * 8 => polyédrique
     * 9 => blocs cubique
     * 10 => en fuseaux
     * 11 => fibreuse
     * 12 => feuillettée
     * 13 => lithologique
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Structure.class, property="code", payload = Warning.class)
    @NotNull(payload=Warning.class)
    public int getStructure() {
        return structureProperty.get();
    }

    /**
     * ELEMENTS_GROSSIERS.
     *
     * (Source : CCTP)
     *
     * Bloc E.
     *
     * Codes :
     * 1 => sans
     * 2 => Graviers < 2cm
     * 3 => Cailloux 2 à 6cm
     * 4 => Pierres et blocs > 6cm
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = RawElements.class, property="code", payload = Warning.class)
    @NotNull(payload=Warning.class)
    public int getRawElements() {
        return rawElementsProperty.get();
    }

    /**
     * RACINES.
     *
     * (Source : CCTP)
     *
     * Bloc F.
     *
     * Codes :
     * 1 => sans
     * 2 => < 8/dm²
     * 3 => 8 à 32 / dm²
     * 4 => > 32 /dm²
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Roots.class, property="code", payload = Warning.class)
    @NotNull(payload=Warning.class)
    public int getRoots() {
        return rootsProperty.get();
    }

    /**
     * TACHES.
     *
     * (Source : CCTP)
     *
     * Bloc G.
     *
     * Codes :
     * 1 => sans
     * 2 => oxydation
     * 3 => réduction
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Stains.class, property="code", payload = Warning.class)
    @NotNull(payload=Warning.class)
    public int getStains() {
        return stainsProperty.get();
    }

    /**
     * ABONDANCE.
     *
     * (Source : CCTP)
     *
     * "…descripteur noté [uniquement] en présence de taches d'oxydation ([G]=2)."
     *
     * Bloc H.
     *
     * Codes :
     * 1 => < 5%
     * 2 => 5 à 15 %
     * 3 => 15 à 40 %
     * 4 => > 40 %
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Abundance.class, property="code", payload = Warning.class)
    @NotNull(payload=Warning.class)
    public int getAbundance() {
        return abundanceProperty.get();
    }

    /**
     * TAILLE.
     *
     * (Source : CCTP)
     *
     * "…descripteur noté [uniquement] en présence de taches d'oxydation ([G]=2)."
     *
     * Bloc I.
     *
     * Codes :
     * 1 => < 2 mm
     * 2 => 2 à 6 mm
     * 3 => 6 à 20 mm
     * 4 => > 20 mm
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Size.class, property="code", payload = Warning.class)
    @NotNull(payload=Warning.class)
    public int getSize() {
        return sizeProperty.get();
    }

    /**
     * FORME.
     *
     * (Source : CCTP)
     *
     * "…descripteur noté [uniquement] en présence de taches d'oxydation ([G]=2)."
     *
     * Bloc J.
     *
     * Codes :
     * 1 => irrégulières
     * 2 => arrondis
     * 3 => trainées horizontales
     * 4 => trainées verticales
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Shape.class, property="code", payload = Warning.class)
    @NotNull(payload=Warning.class)
    public int getShape() {
        return shapeProperty.get();
    }

    /**
     * HUMIDITE.
     *
     * (Source : CCTP)
     *
     * Bloc K.
     *
     * Codes :
     * 1 => sec
     * 2 => frais
     * 3 => humide
     * 4 => saturé
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Humidity.class, property="code", payload = Warning.class)
    @NotNull(payload=Warning.class)
    public int getHumidity() {
        return humidityProperty.get();
    }

    /**
     * COMPACITE.
     *
     * (Source : CCTP)
     *
     * Bloc L.
     *
     * Codes (couteau) :
     * 1 => pénétré sans effort
     * 2 => avec effort
     * 3 => incomplètement
     * 4 => pas ou de quelques mm
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Compacity.class, property="code", payload = Warning.class)
    @NotNull(payload=Warning.class)
    public int getCompactness() {
        return compactnessProperty.get();
    }

    /**
     * PLASTICITE.
     *
     * (Source : CCTP)
     *
     * Bloc M.
     *
     * Codes (boudin) :
     * 1 => impossible de le former
     * 2 => se brise sous son poids
     * 3 => sous faible déformation
     * 4 => ne rompt pas
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Plasticity.class, property="code", payload = Warning.class)
    @NotNull(payload=Warning.class)
    public int getPlasticity() {
        return plasticityProperty.get();
    }

    /**
     * ADHESIVITE.
     *
     * (Source : CCTP)
     *
     * Bloc N.
     *
     * Codes (pouce/index) :
     * 1 => non collant
     * 2 => colle sans adhérer
     * 3 => adhère aux doigts
     * 4 => s'étire nettement
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Adhesiveness.class, property="code", payload = Warning.class)
    @NotNull(payload=Warning.class)
    public int getAdhesiveness() {
        return adhesivenessProperty.get();
    }

    /**
     * FRIABILITE.
     *
     * (Source : CCTP)
     *
     * Bloc O.
     *
     * Codes (pouce/index) :
     * 1 => ne s'effrite pas
     * 2 => sous forte pression
     * 3 => s'effrite facilement
     * 4 => très légère pression
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = Friability.class, property="code", payload = Warning.class)
    @NotNull(payload=Warning.class)
    public int getFriability() {
        return friabilityProperty.get();
    }

    /**
     * ALTERATION_MO.
     *
     * (Source : CCTP)
     *
     * "…altération de la [matière organique]."
     *
     * Bloc P.
     *
     * Codes :
     * 1 => végétaux identifiables
     * 2 => identifiables avec traces de décomposition
     * 3 => peu d'organes végétaux identifiables
     * 4 => non identifiable
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = AlterationMO.class, property="code", payload = Warning.class)
    @NotNull(payload=Warning.class)
    public int getAlterationMo() {
        return alterationMoProperty.get();
    }

    /**
     * VON_POST.
     *
     * (Source : CCTP)
     *
     * "Indice de Von-Post."
     *
     * Bloc Q.
     *
     * Codes :
     * H1 => eau limpide
     * H2 => eau peu colorée
     * H3 => eau trouble pâle
     * H4 => eau trouble foncée
     * H5 => eau trouble et particules
     * H6 => 1/3 du matériel passe entre les doigts
     * H7 => 1/2du matériel passe entre les doigts
     * H8 => 2/3 du matériel passe entre les doigts
     * H9 => Presque tout le matériel
     * H10 => Tout le matériel
     *
     * (Source : Boîte à outils complète)
     *
     * @return
     */
    @RefersTo(type = VonPost.class, property = "code", payload = Warning.class)
    @NotBlank(payload=Warning.class)
    public String getVonPost(){
        return vonPostProperty.get();
    }

    /**
     *
     * @return
     *
     * @see PedologyStatement#equals(java.lang.Object)
     */
    @Override
    public int hashCode() {
        Integer hash = 7;
        hash = 37 * hash + Objects.hashCode(this.getDate());
        hash = 37 * hash + Objects.hashCode(this.getTrackingPoint());
        hash = 37 * hash + getNumberH();
        hash = 37 * hash + getDepth();
        return hash;
    }

    /**
     * {@link PedologyStatement} equality is determined by the horizon number at
     * a given date and at a given tracking point.
     *
     * @param obj
     * @return
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final PedologyStatement other = (PedologyStatement) obj;

        return
                // Compare first elements which are most likely to differ.
                getDepth() == other.getDepth() &&
                getNumberH() == other.getNumberH() &&
                Objects.equals(getTrackingPoint(), other.getTrackingPoint()) &&
                Objects.equals(getDate(), other.getDate()) &&
                // Other, alphabetically
                getAbundance() == other.getAbundance() &&
                getAdhesiveness() == other.getAdhesiveness() &&
                getAlterationMo() == other.getAlterationMo() &&
                Objects.equals(getChroma(), other.getChroma()) &&
                Objects.equals(getColor(), other.getColor()) &&
                getCompactness() == other.getCompactness() &&
                getFriability() == other.getFriability() &&
                getHumidity() == other.getHumidity() &&
                getLimits() == other.getLimits() &&
                getPlasticity() == other.getPlasticity() &&
                getRawElements() == other.getRawElements() &&
                Objects.equals(getRemarks(), other.getRemarks()) &&
                getRoots() == other.getRoots() &&
                getShape() == other.getShape() &&
                getSize() == other.getSize() &&
                getStains() == other.getStains() &&
                getStructure() == other.getStructure() &&
                getTexture() == other.getTexture() &&
                Objects.equals(getValue(), other.getValue()) &&
                Objects.equals(getVonPost(), other.getVonPost());
    }

    @Override
    public String toString() {
        return new StringBuilder("PedologyStatement{")
                .append("remarks=").append(getRemarks())
                .append(", numberH=").append(getNumberH())
                .append(", depth=").append(getDepth())
                .append(", limits=").append(getLimits())
                .append(", color=").append(getColor())
                .append(", value=").append(getValue())
                .append(", chroma=").append(getChroma())
                .append(", texture=").append(getTexture())
                .append(", structure=").append(getStructure())
                .append(", rawElements=").append(getRawElements())
                .append(", roots=").append(getRoots())
                .append(", stains=").append(getStains())
                .append(", abundance=").append(getAbundance())
                .append(", size=").append(getSize())
                .append(", shape=").append(getShape())
                .append(", humidity=").append(getHumidity())
                .append(", compactness=").append(getCompactness())
                .append(", plasticity=").append(getPlasticity())
                .append(", adhesiveness=").append(getAdhesiveness())
                .append(", friability=").append(getFriability())
                .append(", alterationMo=").append(getAlterationMo())
                .append(", vonPost=").append(getVonPost())
                .append('}').toString();
    }
}
