package votorola.s.gwt.mediawiki; // Copyright 2012, 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 com.google.gwt.core.client.*; import votorola.a.count.gwt.*; import votorola.a.diff.*; import votorola.g.lang.*; import votorola.s.gwt.stage.*; import votorola.s.gwt.stage.vote.*; import static votorola.a.count.CountNode.DART_SECTOR_MAX; import static votorola.s.gwt.stage.vote.LightableDifference.REL_TIGHT_CYCLE; /** The set of all {@linkplain ShadowedDiff shadowed differences} for an {@linkplain * #anchor() anchoring author}. Acknowledgement: The need for something like difference * shadows was first pointed out by Ed Pastore in the Metagovernent mailing list. See this post. * * @see DifferenceShadowsV */ final class DifferenceShadows { /** Constructs an instance of DifferenceShadows that co-exists permanently with the * stage. * * @param _voterDiffBoard a sparse array of length {@value * votorola.a.count.CountNode#DART_SECTOR_MAX} containing the differences * between the anchor and her voters. * @param _peerDiffBoard a sparse array of length {@value * votorola.a.count.CountNode#DART_SECTOR_MAX} containing the differences * between the anchor and her peers. * * @see #count() * @see #anchor() * @see #peers() * @see #candidate() * @see #candidateDiff() */ DifferenceShadows( CountJS _count, CountNodeJS _anchor, ShadowedDiff[] _voterDiffBoard, JsArray _peers, ShadowedDiff[] _peerDiffBoard, CountNodeJS _candidate, ShadowedDiff _candidateDiff, final TheatrePage referrer ) { count = _count; assert count != null; anchor = _anchor; assert anchor != null; voterDiffBoard = _voterDiffBoard; assert voterDiffBoard != null; peers = _peers; assert peers != null; peerDiffBoard = _peerDiffBoard; assert peerDiffBoard != null; candidate = _candidate; candidateDiff = _candidateDiff; setReferrer( referrer ); } // ------------------------------------------------------------------------------------ /** The count node of the anchoring author complete with {@linkplain * CountNodeJS#voters() voters}. */ CountNodeJS anchor() { return anchor; } private final CountNodeJS anchor; /** The count node of the anchor's candidate complete with her {@linkplain * CountNodeJS#voters() voters}, or null if there is no candidate. */ CountNodeJS candidate() { return candidate; } private final CountNodeJS candidate; /** Returns the difference between the anchor's position draft and the candidate's; or * null if there is no candidate, or the difference is unknown. */ ShadowedDiff candidateDiff() { return candidateDiff; } private final ShadowedDiff candidateDiff; /** The overall count for the anchor and other count nodes. */ CountJS count() { return count; } private final CountJS count; /** Returns the shadowed version of the specified difference, or null if there is * none. */ ShadowedDiff diffFor( final DiffLook d1 ) { if( d1 == null ) return null; if( ShadowedDiff.looksLikeShadowedDiff( d1 )) return (ShadowedDiff)d1; // all here in shadows ShadowedDiff d2 = candidateDiff; if( d2 != null && d2.key().equals(d1.key()) ) return d2; for( int n = 0; n < DART_SECTOR_MAX; ++n ) { d2 = voterDiff( n ); if( d2 != null && d2.key().equals(d1.key()) ) return d2; d2 = peerDiff( n ); if( d2 != null && d2.key().equals(d1.key()) ) return d2; } return null; } /** Returns the shadowed difference for the specified person and poll, or null if * there is none. */ ShadowedDiff diffFor( final String personName, final String pollName ) { return count.pollName().equals(pollName)? diffFor(personName): null; } /** A sparse array of the anchor's {@linkplain votorola.a.count.CountNode#dartSector() * dart sectored} peers. These are her {@linkplain * votorola.a.count.XCastRelation#CO_VOTER co-voters} unless she is a root * candidate, in which case they are her fellow {@linkplain * CountJS#baseCandidates() base candidates}. The array is indexed from zero with * null elements for empty sectors. * * @return an array of length {@value * votorola.a.count.CountNode#DART_SECTOR_MAX}. */ JsArray peers() { return peers; } private final JsArray peers; /** Returns the difference between the position drafts of the anchor and her peer at * the specified index; or null if there is no such peer, or the difference is * unknown. If there is no candidate and the anchor is a root candidate, then the * peers will be fellow base candidates. * * @param n the {@linkplain votorola.a.count.CountNode#dartSector() dart sector} * of the peer less one, from zero (inclusive) to {@value * votorola.a.count.CountNode#DART_SECTOR_MAX} (non-inclusive). */ ShadowedDiff peerDiff( final int n ) { return peerDiffBoard[n]; } private final ShadowedDiff[] peerDiffBoard; /** Passes all shadowed differences through the specified runner. */ void run( final LightableDifference.Runner runner ) { ShadowedDiff diff; for( int n = 0; n < DART_SECTOR_MAX; ++n ) { diff = voterDiff( n ); if( diff != null && !diff.stageRelClass().equals(REL_TIGHT_CYCLE) ) runner.run( diff ); // REL_TIGHT_CYCLE means diff will definitely run later as candidate. // Cannot filter out *then*, because cannot be sure that voter was run, // which only happens when candidate is dart sectored } for( int n = 0; n < DART_SECTOR_MAX; ++n ) { diff = peerDiff( n ); if( diff != null ) runner.run( diff ); } diff = candidateDiff(); if( diff != null ) runner.run( diff ); } /** Stages and lights the HTTP referrer's difference, if it is shadowed. */ @Warning("init call") final void setReferrer( final TheatrePage referrer ) { if( referrer == null ) return; // no referrer state to transfer final String anchorName = anchor.name(); final Stage stage = Stage.i(); if( !( anchorName.equals(stage.getActorName()) && stage.getDifference() == null )) return; // changed by user or prop, do not clobber final String oldActorName = referrer.getActorName(); ShadowedDiff shadowedDiff = diffFor( oldActorName ); if( shadowedDiff == null ) { final String oldDefaultActorName = referrer.getDefaultActorName(); if( !ObjectX.nullEquals( oldActorName, oldDefaultActorName )) { shadowedDiff = diffFor( oldDefaultActorName ); } } if( shadowedDiff == null ) shadowedDiff = diffFor( referrer.getDifference() ); // last for sake of bridge referrer, so bridge's scene diff not lighted when // another was targeted by NominalDifferenceTargeter, for which only the author // was staged if( shadowedDiff == null ) return; // nothing on referrer matches a shadowed diff stage.setDifference( shadowedDiff ); Stage.setActorName( shadowedDiff.node().name() ); } /** Returns the difference between the anchor's position draft and the voter's at the * specified index; or null if there is no such voter, or the difference is unknown. * * @param n the {@linkplain votorola.a.count.CountNode#dartSector() dart sector} * of the voter less one, from zero (inclusive) to {@value * votorola.a.count.CountNode#DART_SECTOR_MAX} (non-inclusive). */ ShadowedDiff voterDiff( final int n ) { return voterDiffBoard[n]; } private final ShadowedDiff[] voterDiffBoard; //// P r i v a t e /////////////////////////////////////////////////////////////////////// private ShadowedDiff diffFor( final String personName ) { if( personName == null ) return null; if( personName.equals( anchor.name() )) return null; // no self diff if( candidate != null && personName.equals( candidate.name() )) return candidateDiff; CountNodeJS node; for( int n = 0; n < DART_SECTOR_MAX; ++n ) { node = anchor.voters().get( n ); if( node != null && personName.equals( node.name() )) return voterDiff( n ); node = peers.get( n ); if( node != null && personName.equals( node.name() )) return peerDiff( n ); } return null; } }