001package 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.
002
003import com.google.gwt.core.client.*;
004import votorola.a.count.gwt.*;
005import votorola.a.diff.*;
006import votorola.g.lang.*;
007import votorola.s.gwt.stage.*;
008import votorola.s.gwt.stage.vote.*;
009
010import static votorola.a.count.CountNode.DART_SECTOR_MAX;
011import static votorola.s.gwt.stage.vote.LightableDifference.REL_TIGHT_CYCLE;
012
013
014/** The set of all {@linkplain ShadowedDiff shadowed differences} for an {@linkplain
015  * #anchor() anchoring author}.  Acknowledgement: The need for something like difference
016  * shadows was first pointed out by Ed Pastore in the Metagovernent mailing list.  See <a
017  * href='http://metagovernment.org/pipermail/start_metagovernment.org/2011-February/003588.html'
018  * target='_top'>this post</a>.
019  *
020  *     @see DifferenceShadowsV
021  */
022final class DifferenceShadows
023{
024
025
026    /** Constructs an instance of DifferenceShadows that co-exists permanently with the
027      * stage.
028      *
029      *     @param _voterDiffBoard a sparse array of length {@value
030      *       votorola.a.count.CountNode#DART_SECTOR_MAX} containing the differences
031      *       between the anchor and her voters.
032      *     @param _peerDiffBoard a sparse array of length {@value
033      *       votorola.a.count.CountNode#DART_SECTOR_MAX} containing the differences
034      *       between the anchor and her peers.
035      *
036      *     @see #count()
037      *     @see #anchor()
038      *     @see #peers()
039      *     @see #candidate()
040      *     @see #candidateDiff()
041      */
042    DifferenceShadows( CountJS _count, CountNodeJS _anchor, ShadowedDiff[] _voterDiffBoard,
043      JsArray<CountNodeJS> _peers, ShadowedDiff[] _peerDiffBoard, CountNodeJS _candidate,
044      ShadowedDiff _candidateDiff, final TheatrePage referrer )
045    {
046        count = _count; assert count != null;
047        anchor = _anchor; assert anchor != null;
048        voterDiffBoard = _voterDiffBoard; assert voterDiffBoard != null;
049        peers = _peers; assert peers != null;
050        peerDiffBoard = _peerDiffBoard; assert peerDiffBoard != null;
051        candidate = _candidate;
052        candidateDiff = _candidateDiff;
053        setReferrer( referrer );
054    }
055
056
057
058   // ------------------------------------------------------------------------------------
059
060
061    /** The count node of the anchoring author complete with {@linkplain
062      * CountNodeJS#voters() voters}.
063      */
064    CountNodeJS anchor() { return anchor; }
065
066
067        private final CountNodeJS anchor;
068
069
070
071    /** The count node of the anchor's candidate complete with her {@linkplain
072      * CountNodeJS#voters() voters}, or null if there is no candidate.
073      */
074    CountNodeJS candidate() { return candidate; }
075
076
077        private final CountNodeJS candidate;
078
079
080
081    /** Returns the difference between the anchor's position draft and the candidate's; or
082      * null if there is no candidate, or the difference is unknown.
083      */
084    ShadowedDiff candidateDiff() { return candidateDiff; }
085
086
087        private final ShadowedDiff candidateDiff;
088
089
090
091    /** The overall count for the anchor and other count nodes.
092      */
093    CountJS count() { return count; }
094
095
096        private final CountJS count;
097
098
099
100    /** Returns the shadowed version of the specified difference, or null if there is
101      * none.
102      */
103    ShadowedDiff diffFor( final DiffLook d1 )
104    {
105        if( d1 == null ) return null;
106
107        if( ShadowedDiff.looksLikeShadowedDiff( d1 )) return (ShadowedDiff)d1; // all here in shadows
108
109        ShadowedDiff d2 = candidateDiff;
110        if( d2 != null && d2.key().equals(d1.key()) ) return d2;
111
112        for( int n = 0; n < DART_SECTOR_MAX; ++n )
113        {
114            d2 = voterDiff( n );
115            if( d2 != null && d2.key().equals(d1.key()) ) return d2;
116
117            d2 = peerDiff( n );
118            if( d2 != null && d2.key().equals(d1.key()) ) return d2;
119        }
120
121        return null;
122    }
123
124
125
126    /** Returns the shadowed difference for the specified person and poll, or null if
127      * there is none.
128      */
129    ShadowedDiff diffFor( final String personName, final String pollName )
130    {
131        return count.pollName().equals(pollName)? diffFor(personName): null;
132    }
133
134
135
136    /** A sparse array of the anchor's {@linkplain votorola.a.count.CountNode#dartSector()
137      * dart sectored} peers.  These are her {@linkplain
138      * votorola.a.count.XCastRelation#CO_VOTER co-voters} unless she is a <a
139      * href='../../../../../../d/theory.xht#base-candidate' target='_top'>root
140      * candidate</a>, in which case they are her fellow {@linkplain
141      * CountJS#baseCandidates() base candidates}.  The array is indexed from zero with
142      * null elements for empty sectors.
143      *
144      *     @return an array of length {@value
145      *       votorola.a.count.CountNode#DART_SECTOR_MAX}.
146      */
147    JsArray<CountNodeJS> peers() { return peers; }
148
149
150        private final JsArray<CountNodeJS> peers;
151
152
153
154    /** Returns the difference between the position drafts of the anchor and her peer at
155      * the specified index; or null if there is no such peer, or the difference is
156      * unknown.  If there is no candidate and the anchor is a root candidate, then the
157      * peers will be fellow base candidates.
158      *
159      *     @param n the {@linkplain votorola.a.count.CountNode#dartSector() dart sector}
160      *       of the peer less one, from zero (inclusive) to {@value
161      *       votorola.a.count.CountNode#DART_SECTOR_MAX} (non-inclusive).
162      */
163    ShadowedDiff peerDiff( final int n ) { return peerDiffBoard[n]; }
164
165
166        private final ShadowedDiff[] peerDiffBoard;
167
168
169
170    /** Passes all shadowed differences through the specified runner.
171      */
172    void run( final LightableDifference.Runner<ShadowedDiff> runner )
173    {
174        ShadowedDiff diff;
175        for( int n = 0; n < DART_SECTOR_MAX; ++n )
176        {
177            diff = voterDiff( n );
178            if( diff != null && !diff.stageRelClass().equals(REL_TIGHT_CYCLE) ) runner.run( diff );
179              // REL_TIGHT_CYCLE means diff will definitely run later as candidate.
180              // Cannot filter out *then*, because cannot be sure that voter was run,
181              // which only happens when candidate is dart sectored
182        }
183        for( int n = 0; n < DART_SECTOR_MAX; ++n )
184        {
185            diff = peerDiff( n );
186            if( diff != null ) runner.run( diff );
187        }
188        diff = candidateDiff();
189        if( diff != null ) runner.run( diff );
190    }
191
192
193
194    /** Stages and lights the HTTP referrer's difference, if it is shadowed.
195      */
196    @Warning("init call") final void setReferrer( final TheatrePage referrer )
197    {
198        if( referrer == null ) return; // no referrer state to transfer
199
200        final String anchorName = anchor.name();
201        final Stage stage = Stage.i();
202        if( !( anchorName.equals(stage.getActorName()) && stage.getDifference() == null )) return;
203          // changed by user or prop, do not clobber
204
205        final String oldActorName = referrer.getActorName();
206        ShadowedDiff shadowedDiff = diffFor( oldActorName );
207        if( shadowedDiff == null )
208        {
209            final String oldDefaultActorName = referrer.getDefaultActorName();
210            if( !ObjectX.nullEquals( oldActorName, oldDefaultActorName ))
211            {
212                shadowedDiff = diffFor( oldDefaultActorName );
213            }
214        }
215        if( shadowedDiff == null ) shadowedDiff = diffFor( referrer.getDifference() );
216          // last for sake of bridge referrer, so bridge's scene diff not lighted when
217          // another was targeted by NominalDifferenceTargeter, for which only the author
218          // was staged
219        if( shadowedDiff == null ) return; // nothing on referrer matches a shadowed diff
220
221        stage.setDifference( shadowedDiff );
222        Stage.setActorName( shadowedDiff.node().name() );
223    }
224
225
226
227    /** Returns the difference between the anchor's position draft and the voter's at the
228      * specified index; or null if there is no such voter, or the difference is unknown.
229      *
230      *     @param n the {@linkplain votorola.a.count.CountNode#dartSector() dart sector}
231      *       of the voter less one, from zero (inclusive) to {@value
232      *       votorola.a.count.CountNode#DART_SECTOR_MAX} (non-inclusive).
233      */
234    ShadowedDiff voterDiff( final int n ) { return voterDiffBoard[n]; }
235
236
237        private final ShadowedDiff[] voterDiffBoard;
238
239
240
241//// P r i v a t e ///////////////////////////////////////////////////////////////////////
242
243
244    private ShadowedDiff diffFor( final String personName )
245    {
246        if( personName == null ) return null;
247
248        if( personName.equals( anchor.name() )) return null; // no self diff
249
250        if( candidate != null && personName.equals( candidate.name() )) return candidateDiff;
251
252        CountNodeJS node;
253        for( int n = 0; n < DART_SECTOR_MAX; ++n )
254        {
255            node = anchor.voters().get( n );
256            if( node != null && personName.equals( node.name() )) return voterDiff( n );
257
258            node = peers.get( n );
259            if( node != null && personName.equals( node.name() ))  return peerDiff( n );
260        }
261
262        return null;
263    }
264
265
266
267}