package de.duehl.basics.text;

/*
 * Copyright 2016 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

/**
 * Diese Klasse stellt eine Position eines in einem Text gefundenen Strings dar.
 *
 * @version 1.01     2015-11-27
 * @author Christian Dühl
 */

public class TextPosition implements Comparable<TextPosition> {

    /** Die Position des ersten Zeichens des gefundenen Teilstrings. */
    private final int begin;

    /** Die Position hinter dem letzten Zeichen des gefunden Teilstrings. */
    private final int end;

    /**
     * Konstruktor.
     *
     * @param begin
     *            Die Position des ersten Zeichens des gefundenen Teilstrings.
     * @param end
     *            Die Position hinter dem letzten Zeichen des gefunden Teilstrings.
     * @throws IllegalArgumentException
     *             Falls end kleiner ist als begin oder einer der Werte negativ ist.
     */
    public TextPosition(int begin, int end) {
        if (end < begin) {
            throw new IllegalArgumentException("'end' darf nicht kleiner sein als 'begin' (begin="
                    + begin + ", end = " + end + ")");
        }
        if (end < 0) {
            throw new IllegalArgumentException("'end' darf nicht negativ sein (end = " + end + ")");
        }
        if (begin < 0) {
            throw new IllegalArgumentException("'begin' darf nicht negativ sein (begin = "
                    + begin + ")");
        }
        this.begin = begin;
        this.end = end;
    }

    /** Getter für die Position des ersten Zeichens des gefundenen Teilstrings. */
    public int getBegin() {
        return begin;
    }

    /** Getter für die Position hinter dem letzten Zeichen des gefunden Teilstrings. */
    public int getEnd() {
        return end;
    }

    /**
     * Liefert in einem gegebenen Text das Teilstück an dieser Position.
     *
     * @param fullText
     *            Text, dessen Teilstück ermittelt werden soll.
     * @return Teilstück an dieser Position. Ist der Text zu kurz, wird ein entsprechend kürzeres
     *         Teilstück am Ende des Textes zurückgegeben oder gar der leere String, wenn auch der
     *         Anfang dieser Position zu groß ist.
     */
    public String getTextPartAtPostion(String fullText) {
        if (begin >= fullText.length()) {
            return "";
        }
        else if (end >= fullText.length()) {
            return fullText.substring(begin);
        }
        else {
            return fullText.substring(begin, end);
        }
    }

    /**
     * Vergleicht ein anderes Element dieser Klasse mit diesem Element.
     *
     * @param that
     *            Das andere zu vergleichende Element.
     * @return Ein negativer Wert, wenn dieses Objekt kleiner ist, ein positiver Wert, wenn das zu
     *         vergleichende Objekt kleiner ist und Null, wenn beide gleich sind.
     */
    @Override
    public int compareTo(TextPosition that) {
        if (that == this) {
            return 0;
        }
        else if (this.begin != that.begin) {
            return this.begin - that.begin;
        }
        else {
            return this.end - that.end;
        }
    }

    /**
     * Prüft, ob sich diese Textposition mit der übergebenen überschneidet.
     *
     * @param that
     *            Andere Textposition.
     * @return Wahrheitswert: true genau dann, wenn die beiden Positionen sich überschneiden.
     */
    public boolean overlapp(TextPosition that) {
        if (this.end <= that.begin) {
            return false;
        }
        else if (that.end <= this.begin) {
            return false;
        }
        else {
            return true;
        }
    }

    /**
     * Verschmilzt diese Position mit der übergebenen. Macht nur Sinn, wenn diese sich überlappen.
     *
     * @param that
     *            Position, mit der diese verschmolzen werden soll.
     * @return Verschmolzene Position.
     * @throws IllegalArgumentException
     *             Falls sich die Positionen nicht überlappen.
     */
    public TextPosition meltWith(TextPosition that) {
        if (!this.overlapp(that)) {
            throw new IllegalArgumentException("Die beiden positionen überlappen sich nicht! "
                    + "this = " + this + ", that = " + that);
        }
        return new TextPosition(Math.min(this.begin, that.begin), Math.max(this.end, that.end));
    }

    /** Liefert eine Stringrepräsentation. */
    @Override
    public String toString() {
        return "TextPosition [begin=" + begin + ", end=" + end + "]";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + begin;
        result = prime * result + end;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        TextPosition other = (TextPosition) obj;
        if (begin != other.begin) {
            return false;
        }
        if (end != other.end) {
            return false;
        }
        return true;
    }

}
