/*
* This file is part of JGrasstools (http://www.jgrasstools.org)
* (C) HydroloGIS - www.hydrologis.com
*
* JGrasstools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jgrasstools.hortonmachine.modules.network;
import org.jgrasstools.gears.utils.StringUtilities;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Pattern;
/**
* The object for OmsPfafstetter numbers, supplying several methods to compare and analyse a
* hierarchial network numbered following a OmsPfafstetter modified network.
*
* @author Andrea Antonello - www.hydrologis.com
*/
public class PfafstetterNumber implements Comparable<PfafstetterNumber> {
final private String pfafstetterNumberString;
private String pfafstetterUpToLastLevel = null;
private int order = -1;
private List<Integer> ordersList = null;
public PfafstetterNumber(String pfafstetterNumberString) {
this.pfafstetterNumberString = pfafstetterNumberString;
ordersList = new ArrayList<Integer>();
int lastDot = pfafstetterNumberString.lastIndexOf('.');
if (lastDot == -1) {
this.order = 1;
ordersList.add(Integer.parseInt(pfafstetterNumberString));
pfafstetterUpToLastLevel = ""; //$NON-NLS-1$
} else {
String[] order = StringUtilities.REGEX_PATTER_DOT.split(pfafstetterNumberString);
this.order = order.length;
for (String string : order) {
ordersList.add(Integer.parseInt(string));
}
pfafstetterUpToLastLevel = pfafstetterNumberString.substring(0, lastDot + 1);
}
}
/**
* @return the hierarchic order of the channel defined by this pfafstetter number
*/
public int getOrder() {
return order;
}
/**
* @return the list of all the numbers composing this pfafstetter number
*/
public List<Integer> getOrdersList() {
return ordersList;
}
/**
* The pfafstetter string without the last level, useful for comparison. The dot is added at the
* end in order have defined levels. *
*
* @return the pfafstetter string without the last level.
*/
public String toStringUpToLastLevel() {
return pfafstetterUpToLastLevel;
}
/**
* Check if the number is of a certain order or minor to that order
*
* @return <code>true</code> if the supplied order is of same or minor order of the current.
*/
public boolean isOfOrderOrMinor(int order) {
return this.order >= order;
}
/**
* Checks if the actual pfafstetter object is downstream or not of the passed argument
*
* @param pfafstetterNumber the pfafstetterNumber to check against.
* @return true if the actual obj is downstream of the passed one.
*/
public boolean isDownStreamOf(PfafstetterNumber pfafstetterNumber) {
/*
* all the upstreams will have same numbers until the last dot
*/
int lastDot = pfafstetterNumberString.lastIndexOf('.');
String pre = pfafstetterNumberString.substring(0, lastDot + 1);
String lastNum = pfafstetterNumberString.substring(lastDot + 1, pfafstetterNumberString
.length());
int lastNumInt = Integer.parseInt(lastNum);
if (lastNumInt % 2 == 0) {
// it has to be the last piece of a river, therefore no piece contained
return false;
} else {
/*
* check if the passed one is upstream
*/
String pfaff = pfafstetterNumber.toString();
if (pfaff.startsWith(pre)) {
// search for all those with a higher next number
String lastPart = pfaff.substring(lastDot + 1, pfaff.length());
String lastPartParent = StringUtilities.REGEX_PATTER_DOT.split(lastPart)[0];
if (Integer.parseInt(lastPartParent) >= lastNumInt) {
return true;
}
}
}
return false;
}
/**
* @return true if the queried piece is end piece of a reach, i.e. pfafstetter is even
*/
public boolean isEndPiece() {
return ordersList.get(ordersList.size() - 1) % 2 == 0;
}
@Override
public int compareTo(PfafstetterNumber o) {
List<Integer> p1OrdersList = getOrdersList();
List<Integer> p2OrdersList = o.getOrdersList();
int levels = p1OrdersList.size();
if (p2OrdersList.size() < levels) {
levels = p2OrdersList.size();
}
/*
* check the numbers to the minor level of the two
*/
for (int i = 0; i < levels; i++) {
int thisone = p1OrdersList.get(i);
int otherone = p2OrdersList.get(i);
if (thisone > otherone) {
/*
* if this has major number of the other, then this has to be sorted as minor of the
* other, following the pfafstetter logic that has major numbers towards valley
*/
return -1;
} else if (thisone < otherone) {
return 1;
}
// if they are equal, go on to the next level
}
return 0;
}
/**
* Checks if two pfafstetter are connected upstream, i.e. p1 is more downstream than p2
*
* @param p1 the first pfafstetter.
* @param p2 the second pfafstetter.
* @return <code>true</code> if the first is more upstream than the second.
*/
public synchronized static boolean areConnectedUpstream(PfafstetterNumber p1,
PfafstetterNumber p2) {
List<Integer> p1OrdersList = p1.getOrdersList();
List<Integer> p2OrdersList = p2.getOrdersList();
int levelDiff = p1OrdersList.size() - p2OrdersList.size();
if (levelDiff == 0) {
if (p1.toStringUpToLastLevel().equals(p2.toStringUpToLastLevel())) {
int p1Last = p1OrdersList.get(p1OrdersList.size() - 1);
int p2Last = p2OrdersList.get(p2OrdersList.size() - 1);
if (p2Last == p1Last + 1 || p2Last == p1Last + 2) {
return p1Last % 2 != 0;
}
}
} else if (levelDiff == -1) {
if (p2.toString().startsWith(p1.toStringUpToLastLevel())) {
int p2Last = p2OrdersList.get(p2OrdersList.size() - 1);
if (p2Last != 1) {
return false;
}
int p1Last = p1OrdersList.get(p1OrdersList.size() - 1);
int p2LastMinus1 = p2OrdersList.get(p2OrdersList.size() - 2);
if (p2LastMinus1 == p1Last + 1 || p2Last == p1Last + 2) {
return p1Last % 2 != 0;
}
}
}
return false;
}
/**
* Inverse of {@link #areConnectedUpstream(org.jgrasstools.hortonmachine.modules.network.PfafstetterNumber, org.jgrasstools.hortonmachine.modules.network.PfafstetterNumber)} .
*
* @param p1 the first pfafstetter.
* @param p2 the second pfafstetter.
* @return <code>true</code> if the first is more downstream than the second.
*/
public synchronized static boolean areConnectedDownstream(PfafstetterNumber p1,
PfafstetterNumber p2) {
return areConnectedUpstream(p2, p1);
}
public String toString() {
return pfafstetterNumberString;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PfafstetterNumber that = (PfafstetterNumber) o;
if (!pfafstetterNumberString.equals(that.pfafstetterNumberString)) return false;
return true;
}
@Override
public int hashCode() {
return pfafstetterNumberString.hashCode();
}
}