package votorola.a.diff; // Copyright 2011-2013, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. import votorola.a.count.*; import votorola.g.lang.*; /** The identifier of a difference between two draft revisions (a and b). A difference * key is unique within the context of a single vote-server. It is expressed as a string * in the following form:
  *
  *     a0 [. a1 [. a2]] - b0 [. b1 [. b2]] [! series]
  *    |----------------| |----------------|
  *     revision path (a)  revision path (b)
* *

For example:

     9712-8303.441
  *
  *     9059.9863.524-9360.9851.486!1
* *

Each of the two draft revisions (left and right) is identified by a sequence of one * to {@value votorola.a.position.DraftRevision#MAX_PATH_LENGTH} page revisions that is * known as a {@linkplain votorola.a.position.DraftRevision draft revision path}. A * series identifier is appended if the {@linkplain * votorola.a.PollwikiVS#revisionSeries() pollwiki revision series} is non-zero.

* *

Normal order between draft revisions (R/C/U)

* *

Which of the two draft revisions is expressed as 'a' and which as 'b' is determined * by the first applicable rule from the rule lists below. The following rule list * applies only if both revisions have the same author. In that case they are ordered * numerically by revision number. Traversing the two revision paths beginning at index * zero yields a sequence of numeric pairs, one of which eventually differs:

The next rule list applies only if both revisions are position drafts in the * same poll. In that case they are ordered by exclusive cast relation:

Otherwise the order is lexical by username:

*/ public @ThreadSafe final class DiffKey { private DiffKey() {} /** Answers whether aNode is dart-wise or lexically prior to * bNode for purposes of {@linkplain DiffKey normal ordering}. * * @throws IllegalArgumentException if aName and * bName are equal. */ public static boolean isDartOrdered( final CountNode aNode, final String aName, final CountNode bNode, final String bName ) { final byte aS = aNode.dartSector(); final byte bS = bNode.dartSector(); return aS == bS? isLexicallyOrdered(aName,bName): aS < bS; } /** Answers whether aName is lexically prior to bName for * purposes of {@linkplain DiffKey normal ordering}. * * @throws IllegalArgumentException if aName and * bName are equal. */ public static boolean isLexicallyOrdered( final String aName, final String bName ) { int signum = aName.compareToIgnoreCase( bName ); if( signum == 0 ) { signum = aName.compareTo( bName ); if( signum == 0 ) throw new IllegalArgumentException(); } return signum < 0; } /** Constructs the reverse of the specified diff key in which the a-draft revision * path and b-draft revision path are interchanged. */ public static String newReverseKey( final String diffKey ) { final int aEndBound = diffKey.indexOf( '-' ); if( aEndBound < 0 ) throw new IllegalArgumentException(); final int bStart = aEndBound + 1; final String seriesSpecifier; // with its leading ! delimiter int bEndBound = diffKey.indexOf( '!', bStart + 1 ); if( bEndBound < 0 ) { seriesSpecifier = ""; bEndBound = diffKey.length(); } else seriesSpecifier = diffKey.substring( bEndBound ); return diffKey.substring(bStart,bEndBound) + '-' + diffKey.substring(0,aEndBound) + seriesSpecifier; } }