package votorola.s.gwt.scene.feed.ss; // Copyright 2011, 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.gson.stream.*; import java.io.IOException; import java.sql.SQLException; import java.util.*; import javax.xml.stream.XMLStreamException; import votorola.a.count.*; import votorola.a.trust.*; import votorola.a.voter.*; import votorola.g.util.*; import votorola.s.gwt.scene.feed.*; import static votorola.g.util.ArrayListX.EMPTY_LIST; /** A mutable and serializeable person. */ public final class PersonJig implements Person, SerialJig { /** Constructs a PersonJig. * * @param _bite the parent bite jig. */ public PersonJig( BiteJig _bite ) { bite = _bite; } // ------------------------------------------------------------------------------------ // adding fields? ensure they are cleared in serialize() /** Fetches this person's count node and caches it for reuse. * * @see PollJig#count(PollService.VoteServerScope.Run) * @throws NullPointerException if setUser() was not called */ public CountNodeW countNode( final Count count ) throws NoSuchItem, SQLException, XMLStreamException { if( !isCountNodeFresh ) { if( user == null ) throw new NullPointerException(); // fail fast if( countNode == null || !countNode.email().equals( user.email() )) { countNode = count.countTablePV().get( user.email() ); } isCountNodeFresh = true; } if( countNode == null ) throw new NoSuchItem( "countNode" ); return countNode; } private CountNodeW countNode; private boolean isCountNodeFresh; /** Fetches this person's trace node and caches it for reuse. * * @throws NullPointerException if setUser() was not called */ public TraceNode traceNode( final NetworkTrace trace ) throws NoSuchItem, SQLException { if( !isTraceNodeFresh ) { if( user == null ) throw new NullPointerException(); // fail fast if( traceNode == null || !traceNode.registrant().equals( user )) { traceNode = trace.traceNodeTable().get( user ); } isTraceNodeFresh = true; } if( traceNode == null ) throw new NoSuchItem( "traceNode" ); return traceNode; } private TraceNode traceNode; private boolean isTraceNodeFresh; /** This person's user identifier, if it is known. */ public IDPair user() { return user; } private IDPair user; private void user( JsonWriter out ) throws IOException { if( user == null ) return; out.name( "username" ).value( user.username() ); user = null; } /** Sets the user identifier. * * @throws IllegalStateException if the user identifier was already set. */ public void setUser( IDPair _user ) { if( user != null ) throw new IllegalStateException( "user was already set" ); user = _user; } // - P e r s o n ---------------------------------------------------------------------- public byte dartSector() { return dartSector; } private byte dartSector = -1; private void dartSector( final JsonWriter out ) throws IOException { if( dartSector == -1 ) return; // unknown, this is the default in PersonJS out.name( "dartSector" ).value( dartSector ); dartSector = -1; } /** Sets the dart sector. * * @see #countNode(Count) */ public void setDartSector( final CountNodeW countNode ) { dartSector = countNode.dartSector(); } public ResidenceJig residence() { return residence; } private ResidenceJig residence; private void residence( final JsonWriter out ) throws IOException { if( residence == null ) return; out.name( "residence" ); residence.serialize( out ); residence = null; } private ResidenceJig residenceC; /** Ensures the residence is set to a jig and caches the jig for reuse. * * @return the jig that was set. */ public ResidenceJig setResidence() { if( residenceC == null ) residenceC = new ResidenceJig(); residence = residenceC; return residenceC; } public String username() { return user.username(); } public List voteTrace() { return voteTrace; } private ArrayList voteTrace = ArrayListX.emptyList(); // i.e. EMPTY_LIST private boolean areVoteTracesFresh; private void voteTrace( final JsonWriter out ) throws IOException { if( !areVoteTracesFresh ) return; // unknown, this is the default in PersonJS out.name( "voteTrace" ); out.beginArray(); final int pN = voteTrace.size(); for( int p = 1; p < pN; ++p ) voteTrace.get(p).serialize( out ); // ommiting zero, filled in by PersonJS out.endArray(); bite.encachePersons( voteTrace, 1 ); } /** Ensures the vote trace is set. * * @see #countNode(Count) */ public void setVoteTrace( final CountNodeW countNode ) throws SQLException, XMLStreamException { if( areVoteTracesFresh ) return; areVoteTracesFresh = true; // one shot, despite any exception below final CountNodeW[] nodeTrace = countNode.trace(); if( voteTrace == EMPTY_LIST ) voteTrace = new ArrayList( /*initial capacity*/Math.max( nodeTrace.length, 7 )); final int nN = nodeTrace.length; assert nodeTrace[0].email().equals( user.email() ); voteTrace.add( PersonJig.this ); // origin for( int n = 1; n < nN; ++n ) { final PersonJig candidate = bite.uncachePerson(); voteTrace.add( candidate ); final CountNodeW candidateNode = nodeTrace[n]; candidate.setUser( candidateNode.person() ); candidate.setDartSector( candidateNode ); } } public List voteTraceProjected() { return voteTraceProjected; } private ArrayList voteTraceProjected; private void voteTraceProjected( final JsonWriter out ) throws IOException { if( voteTraceProjected == null ) return; // that is the default in PersonJS out.name( "voteTraceProjected" ); out.beginArray(); final int pN = voteTraceProjected.size(); for( int p = 1; p < pN; ++p ) voteTraceProjected.get(p).serialize( out ); // ommiting zero, filled in by PersonJS out.endArray(); bite.encachePersons( voteTraceProjected, 1 ); voteTraceProjected = null; } private ArrayList voteTraceProjectedC; // /** Sets both vote traces from a trace pair. // * // * @throws IllegalStateException if it is detected that a trace was already // * set. // */ // public void setVoteTraces( final CR_Vote.TracePair pair ) // { // setVoteTrace( pair.traceAtLastCount ); // final CountNodeW[] newTrace = pair.traceProjected; // if( newTrace == null ) return; // // if( voteTraceProjectedC == null ) voteTraceProjectedC = new ArrayList( // /*initial capacity*/Math.max( newTrace.length, 7 )); // voteTraceProjected = voteTraceProjectedC; // final int nN = newTrace.length; // assert newTrace[0].voter().username().equals( username ); // voteTrace.add( PersonJig.this ); // origin // for( int n = 1; n < nN; ++n ) // { // final CountNodeW node = newTrace[n]; // final PersonJig jig = bite.uncachePerson(); // voteTraceProjected.add( jig ); // jig.setUser( node.voter() ); // } // } ///// update to take CountNodeW per setVoteTrace, so no cost if areVoteTracesFresh already // - S e r i a l - J i g -------------------------------------------------------------- public void serialize( final JsonWriter out ) throws IOException { out.beginObject(); dartSector( out ); residence( out ); user( out ); voteTrace( out ); voteTraceProjected( out ); out.endObject(); isCountNodeFresh = false; isTraceNodeFresh = false; areVoteTracesFresh = false; } //// P r i v a t e /////////////////////////////////////////////////////////////////////// private final BiteJig bite; }