gt:           if (newState != null && newState.length() > 0) {
context: /*
   * Copyright (c) 2011-2013 by Brent Easton
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Library General Public
   * License (LGPL) as published by the Free Software Foundation.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * Library General Public License for more details.
   *
   * You should have received a copy of the GNU Library General Public
   * License along with this library; if not, copies are available
   * at http://www.opensource.org.
   */
  
  package VASSAL.build;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  
  import VASSAL.build.widget.PieceSlot;
  import VASSAL.counters.BasicPiece;
  import VASSAL.counters.Decorator;
  import VASSAL.counters.GamePiece;
  import VASSAL.counters.PieceCloner;
  import VASSAL.counters.PlaceMarker;
  import VASSAL.counters.Properties;
  
  /**
   * Build a cross-reference of all GpId-able elements in a module or ModuleExtension,
   * Check for missing, duplicate or illegal GamePieceId's
   * Update if necessary
   *
   */
  public class GpIdChecker {
  
    protected GpIdSupport gpIdSupport;
    protected int maxId;
    protected boolean useName = false;
    final HashMap<String, SlotElement> goodSlots = new HashMap<String, SlotElement>();
    final ArrayList<SlotElement> errorSlots = new ArrayList<SlotElement>();
  
    public GpIdChecker() {
      this(null);
    }
  
    public GpIdChecker(GpIdSupport gpIdSupport) {
      this.gpIdSupport = gpIdSupport;
      maxId = -1;
    }
  
    public GpIdChecker(boolean useName) {
      this();
      this.useName = useName;
    }
  
    /**
     * Add a PieceSlot to our cross-reference and any PlaceMarker
     * traits it contains.
     *
     * @param pieceSlot
     */
    public void add(PieceSlot pieceSlot) {
      testGpId(pieceSlot.getGpId(), new SlotElement(pieceSlot));
  
      // PlaceMarker traits within the PieceSlot definition also contain GpId's.
      GamePiece gp = pieceSlot.getPiece();
      checkTrait(gp, pieceSlot);
    }
  
    /**
     * Check for PlaceMarker traits in a GamePiece and add them to
     * the cross-reference
     *
     * @param gp
     * @param slot
     */
    protected void checkTrait(GamePiece gp, PieceSlot slot) {
      if (gp == null || gp instanceof BasicPiece) {
        return;
      }
  
      if (gp instanceof PlaceMarker) {
         final PlaceMarker pm = (PlaceMarker) gp;
         testGpId (pm.getGpId(), new SlotElement(pm, slot));
      }
  
      checkTrait(((Decorator) gp).getInner(), slot);
  
    }
  
    /**
     * Validate a GamePieceId.
     *  - non-null
     *  - Integer
     *  - Not a duplicate of any other GpId
     *  Keep a list of the good Slots and the slots with errors.
     *  Also track the maximum GpId
     *
     * @param id
     * @param element
     */
    protected void testGpId(String id, SlotElement element) {
      /*
       *  If this has been called from a ModuleExtension, the GpId is prefixed with
       *  the Extension Id. Remove the Extension Id and just process the numerid part.
       */
      if (id.contains(":")) {
        id = id.split(":")[1];
      }
  
      if (id == null || id.length() == 0) {   // gpid not generated yet?
        errorSlots.add(element);
      }
      else {
        if (goodSlots.get(id) != null) {      // duplicate gpid?
          errorSlots.add(element);
        }
        try {
          final int iid = Integer.parseInt(id);
          goodSlots.put(id, element);         // gpid is good.
          if (iid >= maxId) {
            maxId = iid+1;
          }
        }
        catch (Exception e) {
          errorSlots.add(element);            // non-numeric gpid?
        }
      }
    }
  
    /**
     * Where any errors found?
     * @return
     */
    public boolean hasErrors() {
      return errorSlots.size() > 0;
    }
  
    /**
     * Repair any errors
     *  - Update the next GpId in the module if necessary
     *  - Generate new GpId's for slots with errors.
     */
    public void fixErrors() {
      if (maxId >= gpIdSupport.getNextGpId()) {
        gpIdSupport.setNextGpId(maxId+1);
      }
      for (SlotElement slotElement : errorSlots) {
        slotElement.updateGpId();
      }
    }
  
    /**
     * Locate the SlotElement that matches oldPiece and return a new GamePiece
     * created from that Slot.
     *
     *
     *
     * @param oldPiece
     * @return
     */
    public GamePiece createUpdatedPiece (GamePiece oldPiece) {
      // Find a slot with a matching gpid
      final String gpid = (String) oldPiece.getProperty(Properties.PIECE_ID);
      if (gpid != null && gpid.length() > 0) {
        final SlotElement element = goodSlots.get(gpid);
        if (element != null) {
           return element.createPiece(oldPiece);
        }
      }
  
      // Failed to find a slot by gpid, try by matching piece name if option selected
      if (useName) {
        final String oldPieceName = Decorator.getInnermost(oldPiece).getName();
        for (SlotElement el : goodSlots.values()) {
          final GamePiece newPiece = el.getPiece();
          final String newPieceName = Decorator.getInnermost(newPiece).getName();
          if (oldPieceName.equals(newPieceName)) {
            return el.createPiece(oldPiece);
          }
        }
      }
  
      return oldPiece;
    }
  
  
    public boolean findUpdatedPiece (GamePiece oldPiece) {
      // Find a slot with a matching gpid
      final String gpid = (String) oldPiece.getProperty(Properties.PIECE_ID);
      if (gpid != null && gpid.length() > 0) {
        final SlotElement element = goodSlots.get(gpid);
        if (element != null) {
           return true;
        }
      }
  
      // Failed to find a slot by gpid, try by matching piece name if option selected
      if (useName) {
        final String oldPieceName = Decorator.getInnermost(oldPiece).getName();
        for (SlotElement el : goodSlots.values()) {
          final GamePiece newPiece = el.getPiece();
          final String newPieceName = Decorator.getInnermost(newPiece).getName();
          if (oldPieceName.equals(newPieceName)) {
            return true;
          }
        }
      }
  
      return false;
    }
  
  
    /**
     * Wrapper class for components that contain a GpId - They will all be either
     * PieceSlot components or PlaceMarker Decorator's.
     * Ideally we would add an interface to these components, but this
     * will break any custom code based on PlaceMarker
     *
     */
    class SlotElement {
  
      private PieceSlot slot;
      private PlaceMarker marker;
      private String id;
  
      public SlotElement() {
        slot = null;
        marker = null;
      }
  
      public SlotElement(PieceSlot ps) {
        this();
        slot = ps;
        id = ps.getGpId();
      }
  
      public SlotElement(PlaceMarker pm, PieceSlot ps) {
        this();
        marker = pm;
        slot = ps;
        id = pm.getGpId();
      }
  
      public String getGpId() {
        return id;
      }
  
      public void updateGpId() {
        if (marker == null) {
          slot.updateGpId();
        }
        else {
          marker.updateGpId();
        }
      }
  
      public GamePiece getPiece() {
        if (slot == null) {
          return marker;
        }
        else {
          return slot.getPiece();
        }
      }
  
      /**
       * Create a new GamePiece based on this Slot Element. Use oldPiece
       * to copy state information over to the new piece.
       *
       * @param oldPiece Old Piece for state information
       * @return New Piece
       */
      public GamePiece createPiece(GamePiece oldPiece) {
        GamePiece newPiece = (slot != null) ? slot.getPiece() : marker.createMarker();
        // The following two steps create a complete new GamePiece with all
        // prototypes expanded
        newPiece = PieceCloner.getInstance().clonePiece(newPiece);
        copyState(oldPiece, newPiece);
        newPiece.setProperty(Properties.PIECE_ID, getGpId());
        return newPiece;
      }
  
      /**
       * Copy as much state information as possible from the old
       * piece to the new piece
       *
       * @param oldPiece Piece to copy state from
       * @param newPiece Piece to copy state to
       */
      protected void copyState(GamePiece oldPiece, GamePiece newPiece) {
        GamePiece p = newPiece;
        while (p != null) {
          if (p instanceof BasicPiece) {
            ((BasicPiece) p).setState(((BasicPiece) Decorator.getInnermost(oldPiece)).getState());
            p = null;
          }
          else {
            final Decorator decorator = (Decorator) p;
            final String type = decorator.myGetType();
            final String newState = findStateFromType(oldPiece, type, p.getClass());
  