/**
   * Sets up all the network links to be simulated,
   *
   * @param datacenters the datacenters being simulated.
   * @param brokers the brokers being simulated.
   * @since 1.0
   */
  static void setUpNetworkLinks(
      HashMap<String, PowerDatacenter> datacenters, HashMap<String, DatacenterBroker> brokers) {
    NetworkMapEntryDAO neDAO = new NetworkMapEntryDAO();

    /*
     * Establish all links whose source is a datacenter
     */
    DatacenterRegistryDAO drDAO = new DatacenterRegistryDAO();
    String[] datacenterNames = drDAO.getAllDatacentersNames();

    for (String source : datacenterNames) {
      PowerDatacenter src = datacenters.get(source);

      List<NetworkMapEntry> destinationList = neDAO.getListOfDestinations(source);

      for (NetworkMapEntry entry : destinationList) {
        String destinationName = entry.getDestination();

        if (drDAO.getDatacenterRegistry(destinationName) != null) { // destination is a datacenter
          PowerDatacenter dest = datacenters.get(destinationName);
          NetworkTopology.addLink(
              src.getId(), dest.getId(), entry.getBandwidth(), entry.getLatency());
        } else { // destination is a customer
          DatacenterBroker dest = brokers.get(destinationName);
          NetworkTopology.addLink(
              src.getId(), dest.getId(), entry.getBandwidth(), entry.getLatency());
        }
      }
    }

    /*
     * Establish all links whose source is a customer
     */
    CustomerRegistryDAO crDAO = new CustomerRegistryDAO();
    String[] customerNames = crDAO.getCustomersNames();

    for (String source : customerNames) {
      DatacenterBroker src = brokers.get(source);

      List<NetworkMapEntry> destinationList = neDAO.getListOfDestinations(source);

      for (NetworkMapEntry entry : destinationList) {
        String destinationName = entry.getDestination();

        if (drDAO.getDatacenterRegistry(destinationName) != null) { // destination is a datacenter
          PowerDatacenter dest = datacenters.get(destinationName);
          NetworkTopology.addLink(
              src.getId(), dest.getId(), entry.getBandwidth(), entry.getLatency());
        } else { // destination is a customer
          DatacenterBroker dest = brokers.get(destinationName);
          NetworkTopology.addLink(
              src.getId(), dest.getId(), entry.getBandwidth(), entry.getLatency());
        }
      }
    }
  }
 /** Store data to StorageNode with the Node is selected randomly */
 public void bindReplicasToStorageNodeRand_Net() {
   int replicaNum = replicaList.size();
   int nodeSize = nodeList.size();
   for (int i = 0; i < replicaNum; i++) {
     BlockReplica replica = replicaList.get(i);
     StorageNode node =
         nodeList.get(java.util.concurrent.ThreadLocalRandom.current().nextInt(nodeSize));
     double replicaSize = replica.getSize();
     if (node.getAvailableSpace() - replicaSize >= 0.000000000000000000000001
         && !node.contains(replica.getName())) {
       double time = node.addFile(replica);
       double accrossLatency = NetworkTopology.getDelay(getId(), node.getDatacenter().getId());
       time += accrossLatency;
       /*Log.printLine("it take " + time
       + " seconds to write the replica #" + replica.getId()
       + " to be stored in datacenter "
       + node.getDatacenter().getName() + " node #"
       + node.getId());*/
       Log.printLine(
           "replica #"
               + replica.getId()
               + "    			"
               + node.getDatacenter().getName()
               + " node #"
               + node.getId()
               + " 			"
               + time);
     } else {
       i--;
     }
   }
 }
 /** store the data in the data center's nodes just by first fit first service */
 public void bindReplicasToStorageNodesSimple_Net() {
   int replicaNum = replicaList.size();
   nodeList = this.getNodeList();
   int nodeNum = nodeList.size();
   int idx = 0;
   for (int i = 0; i < replicaNum; i++) {
     StorageNode node = nodeList.get(idx);
     // BlockReplica replica = replicaList.remove(i);
     BlockReplica replica = replicaList.get(i);
     double replicaSize = replica.getSize();
     if (node.getAvailableSpace() - replicaSize >= 0.000000000000000000000001
         && !node.contains(replica.getName())) {
       double time = node.addFile(replica);
       double accrossLatency = NetworkTopology.getDelay(getId(), node.getDatacenter().getId());
       time += accrossLatency;
       Log.printLine(
           "it take "
               + time
               + " seconds to write the replica #"
               + replica.getId()
               + " to be stored in datacenter "
               + node.getDatacenter().getName()
               + " node #"
               + node.getId());
       // node.setCapacity(node.getCapacity()-replicaSize);
       idx = (idx + 1) % nodeNum;
     } else {
       idx = (idx + 1) % nodeNum;
       i--; // 该副本还未分配到node上,故重新再看接下来的node能否有空间存副本
     }
   }
 }
  /**
   * Store data to StorageNode with the Node is selected based on backward-cloud generator and AHP
   */
  public void bindReplicasToStorageNode_DcSelectAHP_Net() {
    int replicaNum = replicaList.size();
    //		int numDc = datacenterList.size();
    // 这里等于先赋值为0的话,对后面选择数据中心索引有误导
    /*rankedDCindex = new int[numDc];
    for(int i=0;i<numDc;i++){
    	rankedDCindex[i] = 0;
    }*/

    int dcIndex = 0, nodeId = 0;
    for (int i = 0; i < replicaNum; i++) {
      BlockReplica replica = replicaList.get(i);

      // 采用AHP-逆向云算法生成排序好了的数据中心索引
      AHP_BackwardCloud.AHP_BackwardCloud_Init(datacenterList);
      dcIndex = dcIndex % AHP_BackwardCloud.rankedDCindex.length;
      //			int localNodeId
      // =TOPSIS_Local(datacenterList.get(AHP_BackwardCloud.rankedDCindex[dcIndex]));
      TOPSIS_Local(datacenterList.get(AHP_BackwardCloud.rankedDCindex[dcIndex]));
      nodeId = nodeId % TOPSIS.rankedTOPSISnodeIndex.length;
      int localNodeId = TOPSIS.rankedTOPSISnodeIndex[nodeId];
      double replicaSize = replica.getSize();
      StorageDatacenter dc = datacenterList.get(AHP_BackwardCloud.rankedDCindex[dcIndex]);
      List<StorageNode> localNodeLst = (List<StorageNode>) dc.nodeList;
      StorageNode node = dc.NodeList.getById(localNodeLst, localNodeId);
      if (node.getAvailableSpace() - replicaSize >= 0.000000000000000000000001
          && !node.contains(replica.getName())) {
        double time = node.addFile(replica);
        double accrossLatency = NetworkTopology.getDelay(getId(), node.getDatacenter().getId());
        time += accrossLatency;
        /*Log.printLine("it take " + time
        + " seconds to write the replica #" + replica.getId()
        + " to be stored in datacenter "
        + node.getDatacenter().getName() + " node #"
        + node.getId());*/
        Log.printLine(
            "replica #"
                + replica.getId()
                + "    			"
                + node.getDatacenter().getName()
                + " node #"
                + node.getId()
                + " 			"
                + time);
      } else {
        i--;
      }
      dcIndex++;
      nodeId++;
    }
  }
 /**
  * store data in the data center's nodes according the TOPSIS( Technique for Order Preference by
  * Similarity to Ideal Solution)
  *
  * @param none
  */
 @SuppressWarnings("unchecked")
 public void bindReplicasToStorageNodesTOPSIS_Net() {
   // TODO Auto-generated method stub
   int replicaNum = replicaList.size();
   int nodeSize = nodeList.size();
   int idx = 0;
   for (int i = 0; i < replicaNum; i++) {
     TOPSIS.buildTOPSIS(this.datacenterList, (List<StorageNode>) this.nodeList);
     BlockReplica rep = replicaList.get(i);
     double replicaSize = rep.getSize();
     // rankedTOPSISnodeIndex中对于小数据不行呢
     StorageNode node = nodeList.get(TOPSIS.rankedTOPSISnodeIndex[idx]);
     if (node.getAvailableSpace() - replicaSize > 0.000000000000000001
         && !node.contains(rep.getName())) {
       double time = node.addFile(rep); // if the node has already added
       // this file,the time just
       // include networkLatency internal and
       // transport time
       double accrossLatency = NetworkTopology.getDelay(getId(), node.getDatacenter().getId());
       time += accrossLatency;
       /*Log.printLine("it take " + time
       + " seconds to write the replica #" + rep.getId()
       + "to be stored in datacenter "
       + node.getDatacenter().getName() + " node #"
       + node.getId());*/
       Log.printLine(
           "replica #"
               + rep.getId()
               + "    			"
               + node.getDatacenter().getName()
               + " node #"
               + node.getId()
               + " 			"
               + time);
     } else { // rep没有加进去
       i--;
     }
     idx = (idx + 1) % nodeSize;
   }
 }
  /** Creates main() to run this example */
  public static void main(String[] args) {

    Log.printLine("Starting NetworkExample3...");

    try {
      // First step: Initialize the CloudSim package. It should be called
      // before creating any entities.
      int num_user = 2; // number of cloud users
      Calendar calendar = Calendar.getInstance();
      boolean trace_flag = false; // mean trace events

      // Initialize the CloudSim library
      CloudSim.init(num_user, calendar, trace_flag);

      // Second step: Create Datacenters
      // Datacenters are the resource providers in CloudSim. We need at list one of them to run a
      // CloudSim simulation
      Datacenter datacenter0 = createDatacenter("Datacenter_0");
      Datacenter datacenter1 = createDatacenter("Datacenter_1");

      // Third step: Create Brokers
      DatacenterBroker broker1 = createBroker(1);
      int brokerId1 = broker1.getId();

      DatacenterBroker broker2 = createBroker(2);
      int brokerId2 = broker2.getId();

      // Fourth step: Create one virtual machine for each broker/user
      vmlist1 = new ArrayList<Vm>();
      vmlist2 = new ArrayList<Vm>();

      // VM description
      int vmid = 0;
      long size = 10000; // image size (MB)
      int mips = 250;
      int ram = 512; // vm memory (MB)
      long bw = 1000;
      int pesNumber = 1; // number of cpus
      String vmm = "Xen"; // VMM name

      // create two VMs: the first one belongs to user1
      Vm vm1 =
          new Vm(
              vmid,
              brokerId1,
              mips,
              pesNumber,
              ram,
              bw,
              size,
              vmm,
              new CloudletSchedulerTimeShared());

      // the second VM: this one belongs to user2
      Vm vm2 =
          new Vm(
              vmid,
              brokerId2,
              mips,
              pesNumber,
              ram,
              bw,
              size,
              vmm,
              new CloudletSchedulerTimeShared());

      // add the VMs to the vmlists
      vmlist1.add(vm1);
      vmlist2.add(vm2);

      // submit vm list to the broker
      broker1.submitVmList(vmlist1);
      broker2.submitVmList(vmlist2);

      // Fifth step: Create two Cloudlets
      cloudletList1 = new ArrayList<Cloudlet>();
      cloudletList2 = new ArrayList<Cloudlet>();

      // Cloudlet properties
      int id = 0;
      long length = 40000;
      long fileSize = 300;
      long outputSize = 300;
      UtilizationModel utilizationModel = new UtilizationModelFull();

      Cloudlet cloudlet1 =
          new Cloudlet(
              id,
              length,
              pesNumber,
              fileSize,
              outputSize,
              utilizationModel,
              utilizationModel,
              utilizationModel);
      cloudlet1.setUserId(brokerId1);

      Cloudlet cloudlet2 =
          new Cloudlet(
              id,
              length,
              pesNumber,
              fileSize,
              outputSize,
              utilizationModel,
              utilizationModel,
              utilizationModel);
      cloudlet2.setUserId(brokerId2);

      // add the cloudlets to the lists: each cloudlet belongs to one user
      cloudletList1.add(cloudlet1);
      cloudletList2.add(cloudlet2);

      // submit cloudlet list to the brokers
      broker1.submitCloudletList(cloudletList1);
      broker2.submitCloudletList(cloudletList2);

      // Sixth step: configure network
      // load the network topology file
      NetworkTopology.buildNetworkTopology("topology.brite");

      // maps CloudSim entities to BRITE entities
      // Datacenter0 will correspond to BRITE node 0
      int briteNode = 0;
      NetworkTopology.mapNode(datacenter0.getId(), briteNode);

      // Datacenter1 will correspond to BRITE node 2
      briteNode = 2;
      NetworkTopology.mapNode(datacenter1.getId(), briteNode);

      // Broker1 will correspond to BRITE node 3
      briteNode = 3;
      NetworkTopology.mapNode(broker1.getId(), briteNode);

      // Broker2 will correspond to BRITE node 4
      briteNode = 4;
      NetworkTopology.mapNode(broker2.getId(), briteNode);

      // Sixth step: Starts the simulation
      CloudSim.startSimulation();

      // Final step: Print results when simulation is over
      List<Cloudlet> newList1 = broker1.getCloudletReceivedList();
      List<Cloudlet> newList2 = broker2.getCloudletReceivedList();

      CloudSim.stopSimulation();

      Log.print("=============> User " + brokerId1 + "    ");
      printCloudletList(newList1);

      Log.print("=============> User " + brokerId2 + "    ");
      printCloudletList(newList2);

      // Print the debt of each user to each datacenter
      datacenter0.printDebts();
      datacenter1.printDebts();

      Log.printLine("NetworkExample3 finished!");
    } catch (Exception e) {
      e.printStackTrace();
      Log.printLine("Unwanted errors happen");
    }
  }