001package votorola.s.gwt.stage.vote; // 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.Scheduler;
004import votorola.a.diff.*;
005import votorola.g.lang.*;
006import votorola.g.web.gwt.*;
007import votorola.g.web.gwt.event.*;
008import votorola.s.gwt.stage.*;
009import votorola.s.gwt.stage.link.*;
010
011import static votorola.s.gwt.stage.link.NominalDifferenceTargeter.NOMINAL_DIFF;
012
013
014/** The stager of differences for the {@linkplain DifferenceLight difference light}.
015  * Whenever the staged actor and poll match a lighted difference, the stager sets the
016  * {@linkplain Stage#getDifference() difference on the stage}.  If the difference cannot
017  * be staged and {@linkplain NominalDifferenceLight nominal targeting} is enabled, then
018  * any incompatible difference on stage is cleared to allow the difference link to be set
019  * to the nominal target.
020  */
021final class DifferenceStager implements PropertyChangeHandler
022{
023
024
025    /** Constructs a DifferenceStager.
026      */
027    DifferenceStager( final DifferenceLight<?> light, final Stage stage )
028    {
029        keyLight = light.hasDiffLooks()? light: null;
030        GWTX.i().bus().addHandlerToSource( PropertyChange.TYPE, /*source*/stage,
031          DifferenceStager.this ); // no need to unregister, registry does not outlive this listener
032        restage( stage, stage.getActorName(), /*toClobber*/false );
033    }
034
035
036
037   // - P r o p e r t y - C h a n g e - H a n d l e r ------------------------------------
038
039
040    public void onPropertyChange( final PropertyChange e )
041    {
042        final String name = e.propertyName();
043     // if( name.equals( "difference" )) clean( (Stage)e.getSource() ); else
044        if( name.equals( "actorName" ))
045        {
046            final Stage stage = (Stage)e.getSource();
047            final String actorName = stage.getActorName();
048            restage( stage, actorName,
049           // /*toClobber*/!ObjectX.nullEquals(actorName,stage.getDefaultActorName()) );
050           // // allow clobber for non-default actor under assumption he/she was
051           // // deliberately staged by user in order to light difference
052           /////// but then cannot deselect other author to clear the inverted DiffLook1 below,
053           /////// so allow all author de-selections to clobber, which also makes sense:
054              /*toClobber*/true );
055        }
056        else if( name.equals( "pollName" ))
057        {
058            final Stage stage = (Stage)e.getSource();
059            restage( stage, stage.getActorName(), /*toClobber*/false );
060        }
061    }
062
063
064
065//// P r i v a t e ///////////////////////////////////////////////////////////////////////
066
067
068    private final boolean isTargetingNominal = NominalDifferenceTargeter.isEnabled();
069
070
071
072    private final DifferenceLight<?> keyLight; // or null if !hasDiffLooks
073
074
075
076    private final @Warning("init call") void restage( final Stage stage, final String actorName,
077      final boolean toClobber )
078    {
079        final DiffLook dOld = stage.getDifference();
080        final String pollName = stage.getPollName();
081        if( dOld != null )
082        {
083            if( LightableDifference.TYPIFIER.isInstance( dOld ))
084            {
085                final LightableDifference dOldL = (LightableDifference)dOld;
086                if( dOldL.personName().equals(actorName)
087                 && dOldL.pollName().equals(pollName) ) return; // diff already staged
088            }
089            else if( !toClobber ) return; // diff set by another controller, do not clobber
090        }
091
092        final DiffLook dNew;
093        dNew: if( keyLight != null ) dNew = (DiffLook)keyLight.differenceFor( actorName, pollName );
094        else
095        {
096            if( sceneName != null && sceneName.equals( actorName )) // other author of scene diff staged
097            {
098                final DiffLook d = stage.getDefaultDifference();
099                if( d != null )
100                {
101                    // Stage the same diff as scene, but with selectand inverted.  So diff
102                    // link will simply switch selectand even if diff is old.  Nominal
103                    // targeting (below) would instead link to latest diff.
104                    dNew = new DiffLook1( d.key(),
105                      /*selectand, other*/"a".equals(d.selectand())?"b":"a", /*toPersist*/true );
106                    break dNew;
107                }
108            }
109
110            if( isTargetingNominal ) dNew = NOMINAL_DIFF; // cannot stage, so clear instead
111            else return; // nothing helpful to do, so do nothing
112        }
113
114        stage.setDifference( dNew );
115    }
116
117
118
119    private final String sceneName = DifferenceLight.sceneName();
120
121
122}