gt:         for (NodeInGroup groupLeader : leaderGroup.keySet()) {
context: /*
   * Copyright (c) 2005-2008 by Masoud Moshref Javadi <moshref@ce.sharif.edu>, http://ce.sharif.edu/~moshref
   * The license.txt file describes the conditions under which this software may be distributed.
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   *
   * This program 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 General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>
   */
  
  package edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.model.group;
  
  import edu.sharif.ce.dml.common.data.entity.DataLocation;
  import edu.sharif.ce.dml.common.logic.entity.Location;
  import edu.sharif.ce.dml.common.parameters.logic.Parameter;
  import edu.sharif.ce.dml.common.parameters.logic.complex.LazySelectOneParameterable;
  import edu.sharif.ce.dml.common.parameters.logic.exception.InvalidParameterInputException;
  import edu.sharif.ce.dml.common.parameters.logic.primitives.*;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.logic.GeneratorNode;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.logic.SensorNode;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.logic.Simulation;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.model.MapHandleSupport;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.model.Model;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.model.Model.NodePainter;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.model.ModelInitializationException;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.model.SubModelException;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.model.maps.IncludableMap;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.model.maps.IncludingMap;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.model.maps.ReflectiveMap;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.model.poweralgorithm.PowerAlgorithm;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.model.randomwalk.RandomWalkModel;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.ui.map.MapHandle;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.ui.map.MapHandleGroup;
  import edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.ui.map.multi.MultiMapHandleGroup;
  
  import java.awt.*;
  import java.util.*;
  import java.util.List;
  
  
  /**
   * Created by IntelliJ IDEA.
   * User: Masoud
   * Date: Oct 28, 2006
   * Time: 9:16:51 PM
   * <br/>this implementation is with hypothosis that all timeSteps are equal (because of generating nextDestNode of
   * member nodes according to random speed and angle deviation from leader.
   * as leaders mobility model is {@link RandomWalkModel} so we have not any pause time
   * <br/> list of uiparameters: <br/>
   * {@link Integer} maxspeed<br/>
   * {@link Integer} minspeed<br/>
   * {@link Integer} maxpausetime: in this implementation it is not used it.<br/>
   * {@link Double} adr: a double number 1>= adr >=0 <br/>
   * {@link Double} sdr: a double number 1>= sdr >=0<br/>
   * {@link Integer} maxinitialdistance: maximum initial distance of group nodes from group leader<br/>
   * {@link edu.sharif.ce.dml.common.parameters.logic.primitives.IntegerArrayParameter} groupsizes:
   * shows the distributions of nodes into the groups by describing
   * size of each group as a comma separated String. what does happen if number of nodes is not equal to
   * sum of groups size see {@link edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.model.Model#setModelNodes(java.util.List < edu.sharif.ce.dml.mobisim.mobilitygenerator.simulation.logic.GeneratorNode >)}  <br/>
   */
  
  //{@link Double} groupmaxspeed: speed deviation of groups members from group leader will be:
  // * <tt>groupmaxspeed*adr*randomNumber</tt><br/>
  // * {@link Double} groupmaxangle: angle deviation of groups members from group leader will be:
  // * <tt>groupmaxangle*adr*randomNumber</tt><br/>
  public abstract class AbstractGroupModel extends Model implements IncludableMap, MapHandleSupport {
      protected static final int MAX_STACK_DEPTH = 50;
      protected final Map<NodeInGroup, Group> leaderGroup = new HashMap<NodeInGroup, Group>();
      protected final Map<GeneratorNode, NodeInGroup> nodeNodeInGroup = new TreeMap<GeneratorNode, NodeInGroup>();
      protected final String[] traceLabels = new String[]{"GroupNumber", "Is Leader"};
      protected LazySelectOneParameterable leadersModel = null;
      protected Location leadersModelOffset = new Location(0, 0);
      protected int maxInitialDistance;
      protected double maxAngle = 2 * Math.PI;
      protected double ADR;
      protected double SDR;
      protected boolean extraTraces = true;
      protected boolean perGroupRange = false;
      protected List<Integer> groupMembersNum;
      protected int stackDepth = 0;
      protected List<SensorNode> sensors = new LinkedList<SensorNode>();
      private HashSet coverednodes = new HashSet();
    
      
      
              
  
  
      public AbstractGroupModel() {
          super();
  
          ADR = 0;
          SDR = 0;
          maxInitialDistance = 0;
          groupMembersNum = new LinkedList<Integer>();
          leadersModel = new LazySelectOneParameterable();
          perGroupRange = false;
        
      }
      
                    
             
  
      public Map<String, Parameter> getParameters() {
          Map<String, Parameter> parameters = super.getParameters();
          parameters.put("extratraces", new BooleanParameter("extratraces", extraTraces));
          parameters.put("pergrouprange", new BooleanParameter("pergrouprange", perGroupRange));
  
          parameters.put("leadersmodel", leadersModel);
          parameters.put("adr", new DoubleParameter("adr", ADR));
          parameters.put("sdr", new DoubleParameter("sdr", SDR));
          parameters.put("maxinitialdistance", new IntegerParameter("maxinitialdistance", maxInitialDistance));
          parameters.put("groupsizes", new IntegerArrayParameter
                  ("groupsizes", groupMembersNum.toArray(new Integer[groupMembersNum.size()])));
          parameters.put("leadersmodeloffset", new DoubleArrayParameter
                  ("leadersmodeloffset", new double[]{leadersModelOffset.getX(), leadersModelOffset.getY()}));
          return parameters;
      }
  
      public void setParameters(Map<String, Parameter> parameters) throws InvalidParameterInputException {
          super.setParameters(parameters);
  
          extraTraces = (Boolean) parameters.get("extratraces").getValue();
          perGroupRange = (Boolean) parameters.get("pergrouprange").getValue();
  
  //        maxAngle = Double.parseDouble(uiparameters.get("groupmaxangle"));
          ADR = (Double) parameters.get("adr").getValue();
          SDR = (Double) parameters.get("sdr").getValue();
          maxInitialDistance = (Integer) parameters.get("maxinitialdistance").getValue();
  //        if (leadersModel != null) {
  //            leadersModel.setParameters(parameters);
  //        }
          leadersModel = (LazySelectOneParameterable) parameters.get("leadersmodel");
          int[] tempGroupSizes = (int[]) parameters.get("groupsizes").getValue();
  
          groupMembersNum = new LinkedList<Integer>();
          for (Integer gsize : tempGroupSizes) {
              groupMembersNum.add(gsize);
          }
          double[] iap = (double[]) ((DoubleArrayParameter) parameters.get("leadersmodeloffset")).getValue();
          leadersModelOffset.setX(iap[0]);
          leadersModelOffset.setY(iap[1]);
  
      }
  
      /**
       * {@inheritDoc}
       * <br/>if the sum of group sizes is not equal to <code>modelNodes.size()</code>
       * nodes will be distributed equally on groups and additional nodes will be set in last group.
       * if groupsizes indicates more groups than
       * <code>modelNodes.size</code> model creates <code>modelNodes.size</code> groups,
       * each group will have <code>size=1</code>
       *
       * @param modelNodes
       */
      public void setModelNodes(List<GeneratorNode> modelNodes) throws ModelInitializationException {
         // System.out.println("Abstract group " + modelNodes.size());
          super.setModelNodes(modelNodes);
            
          //calculating group members
          if (sumGroupNodes() != (modelNodes.size())) {
              int numberOfGroups = Math.min(groupMembersNum.size(), modelNodes.size());//number of groups at most can be equal to number of nodes.
              groupMembersNum = new LinkedList<Integer>();
              int currentGroupSize = (modelNodes.size()) / numberOfGroups;
              for (int i = 0; i < numberOfGroups - 1; i++) {
                  groupMembersNum.add(currentGroupSize);
              }
              groupMembersNum.add(modelNodes.size() - groupMembersNum.size() * currentGroupSize);
          }
  
          //create group structures
          nodeNodeInGroup.clear();
          leaderGroup.clear();
          Iterator<GeneratorNode> itr = modelNodes.iterator();
          int groupId = 0;
          List<GeneratorNode> leadersNode = new LinkedList<GeneratorNode>();
          for (Integer groupSize : groupMembersNum) {
              if (groupSize > 0) {
                  NodeInGroup groupLeader = new NodeInGroup(itr.next(), NodeInGroup.GROUP_LEADER, null);
                  Group group = new Group(groupLeader, groupId++);
                  groupLeader.setGroup(group);
                  group.setNodes(new LinkedList<NodeInGroup>());
                  group.getNodes().add(groupLeader);
                  leaderGroup.put(groupLeader, group);
                  leadersNode.add(groupLeader.getNode());
                  nodeNodeInGroup.put(groupLeader.getNode(), groupLeader);
                  for (int i = 1; i < groupSize; i++) {
                      NodeInGroup member = createNodeInGroup(itr.next(), NodeInGroup.GROUP_MEMBER, group);
                      group.getNodes().add(member);
                      nodeNodeInGroup.put(member.getNode(), member);
                  }
              }
          }
          getLeadersModel().setModelNodes(leadersNode);
          nodePainter = new GroupMemberNodePainter(getLeadersModel().getNodePainter());
      }
  
      protected Model getLeadersModel() {
          return (Model) leadersModel.getValue();
      }
  
      protected NodeInGroup createNodeInGroup(GeneratorNode node, String groupMemeber, Group group) {
          return new NodeInGroup(node, groupMemeber, group);
      }
  
      public MapHandleSupport getMapHandleSupport() {
          return this;
      }
  
      /**
       * @param leaderNode
       * @return new random speed of a node in a group with <code>leaderGroup</code> leader.
       *         between leadergroup-maxGroupSpeed
       */
      protected double generateSpeed(GeneratorNode leaderNode) {
          double leaderSpeed = leaderNode.getSpeed();
          double speedDev = ((getRandomValue() * SDR * 2) - SDR) * leaderSpeed;
          return leaderSpeed + speedDev;
      }
  
      /**
       * overridden to make group by group update location for nodes. may be it can have a better implementation.
       *
       * @param timeStep
       */
      public void updateNodes(double timeStep) {
          super.setNodeCoverage(0);
          coverednodes.clear();
          getLeadersModel().updateNodes(timeStep);
          //for each group (by each group leader)
  