/* UtilLib - Copyright (c) -2005-2019 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package net.mapeadores.util.text;

import java.io.Serializable;


/**
 * SubstringPosition est utilisée pour conserver les informations d'une
 * sous-chaîne à l'intérieure d'une chaîne. SubstringPosition ne se préoccupe
 * pas des chaînes et sous-chaînes en question, cette classe se contente de
 * manipuler l'index de départ de la sous-chaîne dans la châine et la longueur
 * de la sous-chaîne.
 *
 * @author Vincent Calame
 */
public final class SubstringPosition implements Serializable, Comparable {

    private final int beginIndex;
    private final int length;

    /**
     * Crèe une instance de SubstringPosition avec beginIndex comme index de
     * départ de la sous-chaîne et length comme longueur de la sous-chaîne.
     */
    public SubstringPosition(int beginIndex, int length) {
        this.beginIndex = beginIndex;
        this.length = length;
    }

    /**
     * Retourne l'index de départ de la sous-chaîne dans la châine.
     */
    public int getBeginIndex() {
        return beginIndex;
    }

    /**
     * Retourne la longueur de la sous-chaîne.
     */
    public int getLength() {
        return length;
    }

    /**
     * Retourne l'index dans la chaîne du dernier caractère de la sous-chaîne.
     * Méthode raccourci équivalente à getBeginIndex() + getLength() - 1
     */
    public int getEndIndex() {
        return beginIndex + length - 1;
    }

    /**
     * Une instance de SubstringPosition est égale à une autre si
     * getBeginIndex() et getLength() ont des valeurs égales.
     */
    @Override
    public boolean equals(Object other) {
        if (other == null) {
            return false;
        }
        if (other == this) {
            return true;
        }
        if (!(other instanceof SubstringPosition)) {
            return false;
        }
        SubstringPosition sp = (SubstringPosition) other;
        return (sp.beginIndex == this.beginIndex) && (sp.length == this.length);
    }

    /**
     * Réécriture de la méthode hashCode pour la rendre cohérente avec la
     * méthode equals(). Retourne getBeginIndex() * 1000 + length;
     */
    public int hashCode() {
        return beginIndex * 1000 + length;
    }

    /**
     * Implémentation de l'interface Comparable. Une instance de
     * SubstringPosition est « inférieure « à une autre si elle est plus proche
     * de l'origine de la chaîne. Retourne -1 si getBeginIndex() < ((SubstringPosition) obj).getBeginIndex()
     * Retourne 1 si getBeginIndex() > ((SubstringPosition) obj).getBeginIndex()
     * Si getBeginIndex() = ((SubstringPosition) obj).getBeginIndex(), retourne
     * -1 si getLength() < (SubstringPosition) obj).getLength()
     * et retourne 1 si getLength() > (SubstringPosition) obj).getLength()
     *
     */
    @Override
    public int compareTo(Object obj) {
        if (obj == this) {
            return 0;
        }
        SubstringPosition sp = (SubstringPosition) obj;
        if (this.beginIndex == sp.beginIndex) {
            if (this.length == sp.length) {
                return 0;
            } else {
                return (this.length < sp.length) ? -1 : 1;
            }
        }
        return (this.beginIndex < sp.beginIndex) ? -1 : 1;
    }

    /**
     * Vérifie si l'instance de SubstringPosition contient une autre instance de
     * SubstringPosition. Une instance de SubstringPosition en contient une
     * autre si <em>(substringPosition.beginIndex >= this.beginIndex) &&
     * (substringPosition.length <= this.length)</em>
     */
    public boolean contains(SubstringPosition substringPosition) {
        return (substringPosition.beginIndex >= this.beginIndex) && (substringPosition.length <= this.length);
    }

    public static SubstringPosition merge(SubstringPosition sp1, SubstringPosition sp2) {
        int comp = sp1.compareTo(sp2);
        if (comp == 0) {
            return sp1;
        }
        if (comp < 0) {
            return mergeInOrder(sp1, sp2);
        } else {
            return mergeInOrder(sp2, sp1);
        }
    }

    private static SubstringPosition mergeInOrder(SubstringPosition sp1, SubstringPosition sp2) {
        int start = sp1.beginIndex;
        int length = sp2.beginIndex - sp1.beginIndex + sp2.length;
        return new SubstringPosition(start, length);
    }

}
