/**
   * create a 1-d String array from a network, for easy transmission to R. triples (source,
   * edgeType, target) are filled in to an array of length 3 * # of interactions
   *
   * @param network a gaggle network
   * @return the edge attributes of the network as a string array
   */
  protected String[] networkEdgeAttributesToStringArray(Network network) {
    Interaction[] interactions = network.getInteractions();
    String source, target, type;
    String[] attributeNames = network.getEdgeAttributeNames();
    ArrayList<String> list = new ArrayList<String>();

    for (Interaction interaction : interactions) {
      source = interaction.getSource();
      type = interaction.getType();
      target = interaction.getTarget();
      String edgeName = source + " (" + type + ") " + target;
      String terseEdgeName = source + "::" + target + "::" + type;
      for (String name : attributeNames) {
        HashMap hash = network.getEdgeAttributes(name);
        if (hash.containsKey(edgeName)) {
          Object value = hash.get(edgeName);
          StringBuffer sb = new StringBuffer();
          sb.append(terseEdgeName);
          sb.append("::");
          sb.append(name);
          sb.append("::");
          sb.append(value.toString());
          list.add(sb.toString());
        } else {
          System.out.println("no " + name + " attribute for " + edgeName);
        }
      } // for a
    } // for r

    return list.toArray(new String[0]);
  } // networkEdgeAttributesToStringArray
  // ----------------------------------------------------------------------------------------
  public void handleNetwork(String source, Network newNetwork) {
    System.out.println(
        "network ready, node count "
            + newNetwork.getNodes().length
            + ", edges: "
            + newNetwork.edgeCount());

    network = newNetwork;
    defaultSpecies = newNetwork.getSpecies();
  }
  /**
   * create a 1-d String array from a network's node attributes, for easy transmission to R. use
   * this format for each attribute of each node: nodeName::attributeName::value
   *
   * @param network a gaggle network
   * @return the network's node attributes as a string array
   */
  protected String[] networkNodeAttributesToStringArray(Network network) {
    String[] attributeNames = network.getNodeAttributeNames();
    // System.out.println (" nnatsa, attribute name count: " + attributeNames.length);
    ArrayList<String> list = new ArrayList<String>();

    for (String attributeName : attributeNames) {
      // System.out.println (" nnatsa, attribute name: " + attributeName);
      HashMap attributeHash = network.getNodeAttributes(attributeName);
      // can't remove this warning until Network is genericized in next api release:
      String[] nodeNames = (String[]) attributeHash.keySet().toArray(new String[0]);
      for (String nodeName : nodeNames) {
        // System.out.println (" nnatsa, node name: " + nodeName);
        Object value = attributeHash.get(nodeName);
        String terseForm = nodeName + "::" + attributeName + "::" + value.toString();
        list.add(terseForm);
      } // for n
    } // for i

    return list.toArray(new String[0]);
  } // networkEdgeAttributesToStringArray
 protected void addMetaDataToNetwork(Network network) {
   if (networkMetadata.size() == 0) {
     return;
   }
   Tuple metadata = new Tuple();
   Set<String> keys = networkMetadata.keySet();
   for (Iterator<String> it = keys.iterator(); it.hasNext(); ) {
     String key = it.next();
     metadata.addSingle(new Single(key, networkMetadata.get(key)));
   }
   network.setMetadata(metadata);
 }
  // ----------------------------------------------------------------------------------------
  // is this called from anywhere? doesn't look like it
  public void createAndBroadcastNetwork(
      String sourceNode, String[] targetNodes, double[] weights, String[] targetTypes) {
    // System.out.println ("createAndBroadcastNetwork, source: " + sourceNode);
    Network network = new Network();
    addMetaDataToNetwork(network);
    network.setSpecies(defaultSpecies);

    for (int i = 0; i < targetNodes.length; i++) {
      Interaction interaction = new Interaction(sourceNode, targetNodes[i], targetTypes[i]);
      network.add(interaction);
      String edgeName = sourceNode + " (" + targetTypes[i] + ") " + targetNodes[i];
      // System.out.println ("adding weight " + weights [i] + " for edge " + edgeName);
      network.addEdgeAttribute(edgeName, "weight", weights[i]);
    }

    try {
      gaggleBoss.broadcastNetwork(myGaggleName, targetGoose, network);
    } catch (RemoteException rex) {
      System.err.println("error broadcasting network from RShellGoose " + myGaggleName);
      rex.printStackTrace();
    }
  } // createAndBroadcastNetwork
  /**
   * create a 1-d String array from a network, for easy transmission to R. each element in the array
   * is a string, with format sourceNode::targetNode::edgeType
   *
   * @param network the network to convert to a string
   * @return an array of strings representing a network
   */
  protected String[] networkToStringArray(Network network) {
    Interaction[] interactions = network.getInteractions();
    ArrayList<String> list = new ArrayList<String>();

    // System.out.println ("networkToStringArray, interaction ount: " + interactions.length);
    for (Interaction interaction : interactions) {
      String source = interaction.getSource();
      String target = interaction.getTarget();
      String type = interaction.getType();
      String combined = source + "::" + target + "::" + type;
      // System.out.println ("   interaction: " + combined);
      list.add(combined);
    } // for i

    String[] orphanNodes = network.getOrphanNodes();
    // System.out.println ("networkToStringArray, orphanCount: " + orphanNodes.length);
    for (String orphanNode : orphanNodes) {
      // System.out.println ("    orphan: " + orphanNodes [i]);
      list.add(orphanNode);
    }

    return list.toArray(new String[0]);
  } // networkToStringArray
  /**
   * a network is a collection of (possibly degenerate) interactions. the R client should pass 3
   * arrays of strings, having the following structure
   *
   * <p>edges consist of strings like "VNG0723G::VNG1233G::PhylogeneticProfile" node attributes:
   * "VNG1233G::commonName::pepq2" edge attributes:
   * "VNG0723G::VNG1233G::PhylogeneticProfile::confidence::0.533"
   */
  public void createAndBroadcastNetwork(
      String[] interactionStrings,
      String[] nodeAttributeStrings,
      String[] edgeAttributeStrings,
      String name) {

    Network network = new Network();
    addMetaDataToNetwork(network);
    network.setName(name);
    network.setSpecies(defaultSpecies);

    for (String interactionString : interactionStrings) {
      String[] tokens = interactionString.split("::");
      int tokenCount = tokens.length;
      // for (int t=0; t < tokens.length; t++)
      //  System.out.println ("  edge token " + t + ": " + tokens [t]);
      if (tokenCount == 1 && tokens[0].trim().length() > 0) {
        // System.out.println ("adding one orphan node to network: " + tokens [0]);
        network.add(tokens[0]);
      } else if (tokenCount == 3) {
        String sourceNode = tokens[0];
        String targetNode = tokens[1];
        String interactionType = tokens[2];
        network.add(new Interaction(sourceNode, targetNode, interactionType));
      } // else:  good interaction
    } // for i

    // System.out.println ("nodeAttributeStrings count: " + nodeAttributeStrings.length);
    for (String nodeAttributeString : nodeAttributeStrings) {
      // System.out.println ("   " + nodeAttributeStrings [i]);
      String[] tokens = nodeAttributeString.split("::");
      if (tokens.length == 3) {
        String nodeName = tokens[0].trim();
        String attributeName = tokens[1].trim();
        String rawValue = tokens[2].trim();
        Object value = StringToObjectConverter.convert(rawValue);
        network.addNodeAttribute(nodeName, attributeName, value);
      } // if 3 tokens
    } // for i

    // System.out.println ("edgeAttributeStrings count: " + edgeAttributeStrings.length);
    for (String edgeAttributeString : edgeAttributeStrings) {
      // System.out.println ("   " + edgeAttributeStrings [i]);
      String[] tokens = edgeAttributeString.split("::");
      if (tokens.length == 5) {
        String sourceNode = tokens[0].trim();
        String targetNode = tokens[1].trim();
        String edgeType = tokens[2].trim();
        String attributeName = tokens[3].trim();
        String rawValue = tokens[4].trim();
        Object value = StringToObjectConverter.convert(rawValue);
        String edgeName = sourceNode + " (" + edgeType + ") " + targetNode;
        network.addEdgeAttribute(edgeName, attributeName, value);
      } // if 5 tokens
    } // for i

    // System.out.println ("RShellGoose, about to broadcast network");
    // System.out.println ("     node count: " + network.getNodes().length);
    // System.out.println ("      connected: " + network.getConnectedNodes ().size ());
    // System.out.println ("         orphan: " + network.getOrphanNodes().length);

    try {
      gaggleBoss.broadcastNetwork(myGaggleName, targetGoose, network);
    } catch (RemoteException rex) {
      System.err.println("error broadcasting network from RShellGoose " + myGaggleName);
      rex.printStackTrace();
    }
  } // createAndBroadcastNetwork