/**
   * Method that search the PlatformComponentProfiles tha mach with the parameters
   *
   * @param platformComponentType
   * @param networkServiceType
   * @param communicationCloudClientIdentity
   * @return List<PlatformComponentProfile>
   */
  private List<PlatformComponentProfile> searchProfileByCommunicationCloudClientIdentity(
      PlatformComponentType platformComponentType,
      NetworkServiceType networkServiceType,
      String communicationCloudClientIdentity) {

    /*
     * Prepare the list
     */
    List<PlatformComponentProfile> temporalList = null;
    List<PlatformComponentProfile> finalFilteredList = new ArrayList<>();

    /*
     * Switch between platform component type
     */
    switch (platformComponentType) {
      case COMMUNICATION_CLOUD_SERVER:
        temporalList =
            new ArrayList<>(
                wsCommunicationCloudServer.getRegisteredCommunicationsCloudServerCache().values());
        break;

      case COMMUNICATION_CLOUD_CLIENT:
        temporalList =
            new ArrayList<>(
                wsCommunicationCloudServer.getRegisteredCommunicationsCloudClientCache().values());
        break;

      case NETWORK_SERVICE:
        temporalList =
            new ArrayList<>(
                wsCommunicationCloudServer
                    .getRegisteredNetworkServicesCache()
                    .get(networkServiceType));
        break;

        // Others
      default:
        temporalList =
            wsCommunicationCloudServer
                .getRegisteredOtherPlatformComponentProfileCache()
                .get(platformComponentType);
        break;
    }

    /*
     * Find the component that match with the CommunicationCloudClientIdentity
     */
    for (PlatformComponentProfile platformComponentProfile : temporalList) {

      if (platformComponentProfile
          .getCommunicationCloudClientIdentity()
          .equals(communicationCloudClientIdentity)) {
        finalFilteredList.add(platformComponentProfile);
      }
    }

    return finalFilteredList;
  }
  /**
   * Handles events that indicate a connection to been established between two network services and
   * prepares all objects to work with this new connection
   *
   * @param remoteComponentProfile
   */
  public final void handleEstablishedRequestedNetworkServiceConnection(
      PlatformComponentProfile remoteComponentProfile) {

    try {

      /*
       * Get the active connection
       */
      CommunicationsVPNConnection communicationsVPNConnection =
          communicationsClientConnection.getCommunicationsVPNConnectionStablished(
              platformComponentProfile.getNetworkServiceType(), remoteComponentProfile);

      // Validate the connection
      if (communicationsVPNConnection != null && communicationsVPNConnection.isActive()) {

        /*
         * Instantiate the local reference
         */
        CommunicationNetworkServiceLocal communicationNetworkServiceLocal =
            buildCommunicationNetworkServiceLocal(remoteComponentProfile);

        /*
         * Instantiate the remote reference
         */
        CommunicationNetworkServiceRemoteAgent communicationNetworkServiceRemoteAgent =
            buildCommunicationNetworkServiceRemoteAgent(communicationsVPNConnection);

        /*
         * Register the observer to the observable agent
         */
        communicationNetworkServiceRemoteAgent.addObserver(communicationNetworkServiceLocal);

        /*
         * Start the service thread
         */
        communicationNetworkServiceRemoteAgent.start();

        /*
         * Add to the cache
         */
        communicationNetworkServiceLocalsCache.put(
            remoteComponentProfile.getIdentityPublicKey(), communicationNetworkServiceLocal);
        communicationNetworkServiceRemoteAgentsCache.put(
            remoteComponentProfile.getIdentityPublicKey(), communicationNetworkServiceRemoteAgent);
      }

    } catch (final Exception e) {
      errorManager.reportUnexpectedPluginException(
          pluginVersionReference,
          UnexpectedPluginExceptionSeverity.DISABLES_SOME_FUNCTIONALITY_WITHIN_THIS_PLUGIN,
          e);
    }
  }
  @Override
  public void handleFailureComponentRegistrationNotificationEvent(
      PlatformComponentProfile networkServiceApplicant,
      PlatformComponentProfile remoteParticipant) {
    System.out.println(
        "----------------------------------\n"
            + "FAILED CONNECTION WITH "
            + remoteParticipant.getAlias()
            + "\n"
            + "--------------------------------------------------------");
    cryptoPaymentRequestExecutorAgent.connectionFailure(remoteParticipant.getIdentityPublicKey());

    // I check my time trying to send the message
    checkFailedDeliveryTime(remoteParticipant.getIdentityPublicKey());
  }
  /**
   * (non-javadoc)
   *
   * @see CommunicationsClientConnection#registerComponentForCommunication(NetworkServiceType,
   *     PlatformComponentProfile)
   */
  @Override
  public void registerComponentForCommunication(
      NetworkServiceType networkServiceNetworkServiceTypeApplicant,
      PlatformComponentProfile platformComponentProfile)
      throws CantRegisterComponentException {

    try {

      System.out.println(
          "WsCommunicationsCloudClientConnection - registerComponentForCommunication");

      /*
       * Validate parameter
       */
      if (platformComponentProfile == null) {

        throw new IllegalArgumentException(
            "The platformComponentProfile is required, can not be null");
      }

      Gson gson = new Gson();
      JsonObject jsonObject = new JsonObject();
      jsonObject.addProperty(
          JsonAttNamesConstants.NETWORK_SERVICE_TYPE,
          networkServiceNetworkServiceTypeApplicant.toString());
      jsonObject.addProperty(
          JsonAttNamesConstants.PROFILE_TO_REGISTER, platformComponentProfile.toJson());

      /*
       * Construct a fermat packet whit the PlatformComponentProfile
       */
      FermatPacket fermatPacket =
          FermatPacketCommunicationFactory.constructFermatPacketEncryptedAndSinged(
              wsCommunicationsCloudClientChannel.getServerIdentity(), // Destination
              wsCommunicationsCloudClientChannel.getClientIdentity().getPublicKey(), // Sender
              gson.toJson(jsonObject), // Message Content
              FermatPacketType.COMPONENT_REGISTRATION_REQUEST, // Packet type
              wsCommunicationsCloudClientChannel
                  .getClientIdentity()
                  .getPrivateKey()); // Sender private key

      String fermatPacketEncode = FermatPacketEncoder.encode(fermatPacket);

      /*
       * Send the encode packet to the server
       */
      wsCommunicationsCloudClientChannel.send(fermatPacketEncode);

    } catch (Exception e) {

      CantRegisterComponentException pluginStartException =
          new CantRegisterComponentException(
              CantRegisterComponentException.DEFAULT_MESSAGE,
              e,
              e.getLocalizedMessage(),
              e.getLocalizedMessage());
      throw pluginStartException;
    }
  }
  /**
   * (non-javadoc)
   *
   * @see CommunicationsClientConnection#requestListComponentRegistered(PlatformComponentProfile,
   *     DiscoveryQueryParameters)
   */
  @Override
  public void requestListComponentRegistered(
      PlatformComponentProfile networkServiceApplicant,
      DiscoveryQueryParameters discoveryQueryParameters)
      throws CantRequestListException {

    try {

      System.out.println("WsCommunicationsCloudClientConnection - requestListComponentRegistered");

      /*
       * Validate parameter
       */
      if (discoveryQueryParameters == null) {

        throw new IllegalArgumentException(
            "The discoveryQueryParameters is required, can not be null");
      }

      Gson gson = new Gson();
      JsonObject jsonObject = new JsonObject();
      jsonObject.addProperty(
          JsonAttNamesConstants.NETWORK_SERVICE_TYPE,
          networkServiceApplicant.getNetworkServiceType().toString());
      jsonObject.addProperty(
          JsonAttNamesConstants.DISCOVERY_PARAM, discoveryQueryParameters.toJson());

      /*
       * Construct a fermat packet whit the filters
       */
      FermatPacket fermatPacketRespond =
          FermatPacketCommunicationFactory.constructFermatPacketEncryptedAndSinged(
              wsCommunicationsCloudClientChannel.getServerIdentity(), // Destination
              wsCommunicationsCloudClientChannel.getClientIdentity().getPublicKey(), // Sender
              gson.toJson(jsonObject), // Message Content
              FermatPacketType.REQUEST_LIST_COMPONENT_REGISTERED, // Packet type
              wsCommunicationsCloudClientChannel
                  .getClientIdentity()
                  .getPrivateKey()); // Sender private key

      /*
       * Send the encode packet to the server
       */
      wsCommunicationsCloudClientChannel.send(FermatPacketEncoder.encode(fermatPacketRespond));

    } catch (Exception e) {

      CantRequestListException pluginStartException =
          new CantRequestListException(
              CantRequestListException.DEFAULT_MESSAGE,
              e,
              e.getLocalizedMessage(),
              e.getLocalizedMessage());
      throw pluginStartException;
    }
  }
  /** Handles the events CompleteComponentRegistrationNotification */
  public void handleCompleteComponentRegistrationNotificationEvent(
      final PlatformComponentProfile platformComponentProfileRegistered) {

    /*
     * If the component registered have my profile and my identity public key
     */
    if (platformComponentProfileRegistered.getPlatformComponentType()
            == PlatformComponentType.NETWORK_SERVICE
        && platformComponentProfileRegistered.getNetworkServiceType()
            == NetworkServiceType.CRYPTO_PAYMENT_REQUEST
        && platformComponentProfileRegistered
            .getIdentityPublicKey()
            .equals(identity.getPublicKey())) {

      /*
       * Mark as register
       */
      this.register = Boolean.TRUE;

      try {

        cryptoPaymentRequestExecutorAgent =
            new CryptoPaymentRequestExecutorAgent(
                this,
                errorManager,
                eventManager,
                cryptoPaymentRequestNetworkServiceDao,
                wsCommunicationsCloudClientManager,
                getPluginVersionReference());

        cryptoPaymentRequestExecutorAgent.start();

      } catch (CantStartAgentException e) {

        CantStartPluginException pluginStartException =
            new CantStartPluginException(e, "", "Problem initializing crypto payment request dao.");
        errorManager.reportUnexpectedPluginException(
            this.getPluginVersionReference(),
            UnexpectedPluginExceptionSeverity.DISABLES_THIS_PLUGIN,
            pluginStartException);
      }
    }
  }
  /**
   * Method that apply geo location filter to the list
   *
   * @param listToApply
   * @return List<PlatformComponentProfile>
   */
  private List<PlatformComponentProfile> applyGeoLocationFilter(
      List<PlatformComponentProfile> listToApply,
      DiscoveryQueryParameters discoveryQueryParameters) {

    /*
     * Hold the data ordered by distance
     */
    Map<Double, PlatformComponentProfile> orderedByDistance = new TreeMap<>();

    /*
     * For each component
     */
    for (PlatformComponentProfile platformComponentProfile : listToApply) {

      /*
       * If component have a geo location
       */
      if (platformComponentProfile.getLocation() != null) {

        /*
         * Calculate the distance between the two points
         */
        Double componentDistance =
            DistanceCalculator.distance(
                discoveryQueryParameters.getLocation(),
                platformComponentProfile.getLocation(),
                DistanceCalculator.KILOMETERS);

        /*
         * Compare the distance
         */
        if (componentDistance <= discoveryQueryParameters.getDistance()) {

          /*
           * Add to the list
           */
          orderedByDistance.put(componentDistance, platformComponentProfile);
        }
      }
    }

    return new ArrayList<>(orderedByDistance.values());
  }
 protected CommunicationNetworkServiceLocal buildCommunicationNetworkServiceLocal(
     final PlatformComponentProfile remoteComponentProfile) {
   // TODO: Leon tenes que pasarle la instancia del network service plugin root acá
   return new CommunicationNetworkServiceLocal(
       remoteComponentProfile,
       errorManager,
       eventManager,
       outgoingMessageDao,
       platformComponentProfile.getNetworkServiceType(),
       networkServicePluginRoot);
 }
  protected CommunicationNetworkServiceLocal buildCommunicationNetworkServiceLocal(
      final PlatformComponentProfile remoteComponentProfile) {

    return new CommunicationNetworkServiceLocal(
        remoteComponentProfile,
        errorManager,
        eventManager,
        outgoingMessageDao,
        platformComponentProfile.getNetworkServiceType(),
        eventSource);
  }
  @Override
  public void beforeRequest(Map<String, List<String>> headers) {

    /*
     * Get json representation
     */
    JsonObject jsonObject = new JsonObject();
    jsonObject.addProperty(
        JsonAttNamesConstants.NETWORK_SERVICE_TYPE,
        remoteParticipantNetworkService.getNetworkServiceType().toString());
    jsonObject.addProperty(
        JsonAttNamesConstants.CLIENT_IDENTITY_VPN, vpnClientIdentity.getPublicKey());
    jsonObject.addProperty(
        JsonAttNamesConstants.APPLICANT_PARTICIPANT_VPN, registerParticipant.toJson());
    jsonObject.addProperty(
        JsonAttNamesConstants.REMOTE_PARTICIPANT_VPN,
        remotePlatformComponentProfile.getIdentityPublicKey());

    /*
     * Add the att to the header
     */
    headers.put(JsonAttNamesConstants.HEADER_ATT_NAME_TI, Arrays.asList(jsonObject.toString()));
    // headers.put("Origin", Arrays.asList("myOrigin"));
  }
  /**
   * Filter the PlatformComponentProfiles that match with the discoveryQueryParameters that get from
   * other component
   *
   * @param discoveryQueryParameters
   * @param clientIdentityPublicKey
   * @return List<PlatformComponentProfile>
   */
  private List<PlatformComponentProfile> applyDiscoveryQueryParametersFromOtherComponent(
      DiscoveryQueryParameters discoveryQueryParameters, String clientIdentityPublicKey) {

    System.out.println(
        "ComponentRegisteredListWebService - applyDiscoveryQueryParametersFromOtherComponent    = ");

    List<PlatformComponentProfile> filteredListFromOtherComponentType = new ArrayList<>();

    /*
     * Get the list from the cache that match with the other componet
     */
    List<PlatformComponentProfile> otherComponentList =
        (List<PlatformComponentProfile>)
            new ArrayList<>(
                    searchProfile(
                        discoveryQueryParameters.getFromOtherPlatformComponentType(),
                        discoveryQueryParameters.getFromOtherNetworkServiceType(),
                        discoveryQueryParameters.getIdentityPublicKey()))
                .clone();
    System.out.println(
        "ComponentRegisteredListWebService - otherComponentList  = " + otherComponentList.size());

    /*
     * Find the other component that match with the identity
     */
    for (PlatformComponentProfile platformComponentProfile : otherComponentList) {

      if (discoveryQueryParameters.getIdentityPublicKey() != null
          && discoveryQueryParameters.getIdentityPublicKey() != "") {
        List<PlatformComponentProfile> newList =
            searchProfileByCommunicationCloudClientIdentity(
                discoveryQueryParameters.getPlatformComponentType(),
                discoveryQueryParameters.getNetworkServiceType(),
                platformComponentProfile.getCommunicationCloudClientIdentity());
        filteredListFromOtherComponentType.addAll(newList);
      }
    }

    /*
     * Remove the requester from the list
     */
    Iterator<PlatformComponentProfile> iterator = filteredListFromOtherComponentType.iterator();
    while (iterator.hasNext()) {

      PlatformComponentProfile platformComponentProfileRegistered = iterator.next();
      if (platformComponentProfileRegistered
          .getCommunicationCloudClientIdentity()
          .equals(clientIdentityPublicKey)) {
        System.out.println(
            "ComponentRegisteredListWebService - removing ="
                + platformComponentProfileRegistered.getName());
        iterator.remove();
      }
    }

    System.out.println(
        "ComponentRegisteredListWebService - filteredListFromOtherComponentType  = "
            + filteredListFromOtherComponentType.size());

    return filteredListFromOtherComponentType;
  }
  /**
   * Filter the PlatformComponentProfile that match with the discoveryQueryParameters
   *
   * @param discoveryQueryParameters
   * @return List<PlatformComponentProfile>
   */
  private List<PlatformComponentProfile> applyDiscoveryQueryParameters(
      DiscoveryQueryParameters discoveryQueryParameters, String clientIdentityPublicKey) {

    int totalFilterToApply = countFilers(discoveryQueryParameters);
    int filterMatched = 0;

    List<PlatformComponentProfile> list =
        getPrimaryFilteredListFromCache(
            discoveryQueryParameters.getPlatformComponentType(),
            discoveryQueryParameters.getNetworkServiceType(),
            clientIdentityPublicKey);
    List<PlatformComponentProfile> filteredLis = new ArrayList<>();

    System.out.println(
        "ComponentRegisteredListWebService - totalFilterToApply    = " + totalFilterToApply);

    if (totalFilterToApply > 0) {

      /*
       * Apply the basic filter
       */
      for (PlatformComponentProfile platformComponentProfile : list) {

        if (discoveryQueryParameters.getIdentityPublicKey() != null
            && discoveryQueryParameters.getIdentityPublicKey() != "") {
          if (platformComponentProfile
              .getIdentityPublicKey()
              .equals(discoveryQueryParameters.getIdentityPublicKey())) {
            filterMatched += 1;
          }
        }

        if (discoveryQueryParameters.getAlias() != null
            && discoveryQueryParameters.getAlias() != "") {
          if (discoveryQueryParameters
              .getAlias()
              .toLowerCase()
              .contains(platformComponentProfile.getAlias().toLowerCase())) {
            filterMatched += 1;
          }
        }

        if (discoveryQueryParameters.getName() != null
            && discoveryQueryParameters.getName() != "") {
          if (discoveryQueryParameters
              .getName()
              .toLowerCase()
              .contains(platformComponentProfile.getName().toLowerCase())) {
            filterMatched += 1;
          }
        }

        if (discoveryQueryParameters.getExtraData() != null
            && discoveryQueryParameters.getExtraData() != "") {
          if (discoveryQueryParameters
              .getExtraData()
              .toLowerCase()
              .contains(platformComponentProfile.getExtraData().toLowerCase())) {
            filterMatched += 1;
          }
        }

        // if all filter matched
        if (totalFilterToApply == filterMatched) {
          // Add to the list
          filteredLis.add(platformComponentProfile);
        }
      }

    } else {

      filteredLis = list;
    }

    /*
     * Apply geo location filter
     */
    if (discoveryQueryParameters.getLocation() != null
        && discoveryQueryParameters.getLocation().getLatitude() != 0
        && discoveryQueryParameters.getLocation().getLongitude() != 0) {

      filteredLis = applyGeoLocationFilter(filteredLis, discoveryQueryParameters);
    }

    /*
     * Apply pagination
     */
    if ((discoveryQueryParameters.getMax() != 0) && (discoveryQueryParameters.getOffset() != 0)) {

      /*
       * Apply pagination
       */
      if (filteredLis.size() > discoveryQueryParameters.getMax()
          && filteredLis.size() > discoveryQueryParameters.getOffset()) {
        filteredLis =
            filteredLis.subList(
                discoveryQueryParameters.getOffset(), discoveryQueryParameters.getMax());
      } else if (filteredLis.size() > 100) {
        filteredLis = filteredLis.subList(discoveryQueryParameters.getOffset(), 100);
      }

    } else if (filteredLis.size() > 100) {
      filteredLis = filteredLis.subList(0, 100);
    }

    return filteredLis;
  }
  /**
   * Return the primary list from the cache filtered by the platformComponentType or
   * networkServiceType
   *
   * @param platformComponentType
   * @param networkServiceType
   * @return List<PlatformComponentProfile>
   */
  public List<PlatformComponentProfile> getPrimaryFilteredListFromCache(
      PlatformComponentType platformComponentType,
      NetworkServiceType networkServiceType,
      String clientIdentityPublicKey) {

    /*
     * Get the list
     */
    List<PlatformComponentProfile> list = new ArrayList<>();

    /*
     * Switch between platform component type
     */
    switch (platformComponentType) {
      case COMMUNICATION_CLOUD_SERVER:
        if (!wsCommunicationCloudServer.getRegisteredCommunicationsCloudServerCache().isEmpty()) {
          list =
              (List<PlatformComponentProfile>)
                  new ArrayList<>(
                          wsCommunicationCloudServer
                              .getRegisteredCommunicationsCloudServerCache()
                              .values())
                      .clone();
        }
        break;

      case COMMUNICATION_CLOUD_CLIENT:
        if (!wsCommunicationCloudServer.getRegisteredCommunicationsCloudClientCache().isEmpty()) {
          list =
              (List<PlatformComponentProfile>)
                  new ArrayList<>(
                          wsCommunicationCloudServer
                              .getRegisteredCommunicationsCloudClientCache()
                              .values())
                      .clone();
        }
        break;

      case NETWORK_SERVICE:
        if (wsCommunicationCloudServer
                .getRegisteredNetworkServicesCache()
                .containsKey(networkServiceType)
            && !wsCommunicationCloudServer
                .getRegisteredNetworkServicesCache()
                .get(networkServiceType)
                .isEmpty()) {
          list =
              (List<PlatformComponentProfile>)
                  new ArrayList<>(
                          wsCommunicationCloudServer
                              .getRegisteredNetworkServicesCache()
                              .get(networkServiceType))
                      .clone();
        }
        break;

        // Others
      default:
        if (wsCommunicationCloudServer
                .getRegisteredOtherPlatformComponentProfileCache()
                .containsKey(platformComponentType)
            && !wsCommunicationCloudServer
                .getRegisteredOtherPlatformComponentProfileCache()
                .get(platformComponentType)
                .isEmpty()) {
          list =
              (List<PlatformComponentProfile>)
                  new ArrayList<>(
                          wsCommunicationCloudServer
                              .getRegisteredOtherPlatformComponentProfileCache()
                              .get(platformComponentType))
                      .clone();
        }
        break;
    }

    /*
     * Remove the requester from the list
     */
    Iterator<PlatformComponentProfile> iterator = list.iterator();
    while (iterator.hasNext()) {

      PlatformComponentProfile platformComponentProfileRegistered = iterator.next();
      if (platformComponentProfileRegistered
          .getCommunicationCloudClientIdentity()
          .equals(clientIdentityPublicKey)) {
        System.out.println(
            "ComponentRegisteredListWebService - removing ="
                + platformComponentProfileRegistered.getName());
        iterator.remove();
      }
    }

    return list;
  }
  /**
   * (non-javadoc)
   *
   * @see CommunicationsClientConnection#requestVpnConnection(PlatformComponentProfile,
   *     PlatformComponentProfile)
   */
  @Override
  public void requestVpnConnection(
      PlatformComponentProfile applicant, PlatformComponentProfile remoteDestination)
      throws CantEstablishConnectionException {

    try {

      System.out.println("WsCommunicationsCloudClientConnection - requestVpnConnection");

      /*
       * Validate parameter
       */
      if (applicant == null || remoteDestination == null) {

        throw new IllegalArgumentException("All parameters are required, can not be null");
      }

      List<PlatformComponentProfile> participants = new ArrayList();
      participants.add(applicant);
      participants.add(remoteDestination);

      /** Validate all are the same type and NETWORK_SERVICE */
      for (PlatformComponentProfile participant : participants) {

        if (participant.getPlatformComponentType() != PlatformComponentType.NETWORK_SERVICE) {
          throw new IllegalArgumentException(
              "All the PlatformComponentProfile has to be NETWORK_SERVICE ");
        }

        if (participant.getNetworkServiceType() != applicant.getNetworkServiceType()) {
          throw new IllegalArgumentException(
              "All the PlatformComponentProfile has to be the same type of network service type ");
        }
      }

      /*
       * Construct the json object
       */
      Gson gson = new Gson();

      /*
       * Convert to json representation
       */
      String jsonListRepresentation =
          gson.toJson(
              participants,
              new TypeToken<List<PlatformComponentProfileCommunication>>() {}.getType());

      /*
       * Construct a fermat packet whit the request
       */
      FermatPacket fermatPacketRespond =
          FermatPacketCommunicationFactory.constructFermatPacketEncryptedAndSinged(
              wsCommunicationsCloudClientChannel.getServerIdentity(), // Destination
              wsCommunicationsCloudClientChannel.getClientIdentity().getPublicKey(), // Sender
              jsonListRepresentation, // Message Content
              FermatPacketType.COMPONENT_CONNECTION_REQUEST, // Packet type
              wsCommunicationsCloudClientChannel
                  .getClientIdentity()
                  .getPrivateKey()); // Sender private key
      /*
       * Send the encode packet to the server
       */
      wsCommunicationsCloudClientChannel.send(FermatPacketEncoder.encode(fermatPacketRespond));

    } catch (Exception e) {

      CantEstablishConnectionException pluginStartException =
          new CantEstablishConnectionException(
              CantEstablishConnectionException.DEFAULT_MESSAGE,
              e,
              e.getLocalizedMessage(),
              e.getLocalizedMessage());
      throw pluginStartException;
    }
  }
  /** Method tha send a new Message */
  public void sendNewMessage(
      PlatformComponentProfile sender, PlatformComponentProfile destination, String messageContent)
      throws CantSendMessageException {

    try {

      /*
       * ask for a previous connection
       */
      CommunicationNetworkServiceLocal communicationNetworkServiceLocal =
          communicationNetworkServiceConnectionManager.getNetworkServiceLocalInstance(
              destination.getIdentityPublicKey());

      if (communicationNetworkServiceLocal != null) {
        System.out.println(
            "*** 12345 case 7:send msg in NS P2P layer active connection"
                + new Timestamp(System.currentTimeMillis()));
        // Send the message
        communicationNetworkServiceLocal.sendMessage(
            sender.getIdentityPublicKey(),
            sender.getPlatformComponentType(),
            sender.getNetworkServiceType(),
            messageContent);

      } else {
        System.out.println(
            "*** 12345 case 6:send msg in NS P2P layer not active connection"
                + new Timestamp(System.currentTimeMillis()));
        /*
         * Created the message
         */
        FermatMessage fermatMessage =
            FermatMessageCommunicationFactory.constructFermatMessage(
                sender.getIdentityPublicKey(), // Sender
                sender.getPlatformComponentType(), // Sender Type
                sender.getNetworkServiceType(), // Sender NS Type
                destination.getIdentityPublicKey(), // Receiver
                destination.getPlatformComponentType(), // Receiver Type
                destination.getNetworkServiceType(), // Receiver NS Type
                messageContent, // Message Content
                FermatMessageContentType.TEXT // Type
                );

        /*
         * Configure the correct status
         */
        ((FermatMessageCommunication) fermatMessage)
            .setFermatMessagesStatus(FermatMessagesStatus.PENDING_TO_SEND);

        /*
         * Save to the data base table
         */
        communicationNetworkServiceConnectionManager.getOutgoingMessageDao().create(fermatMessage);

        /*
         * Ask the client to connect
         */
        communicationNetworkServiceConnectionManager.connectTo(
            sender, getNetworkServiceProfile(), destination);
      }

    } catch (Exception e) {

      System.out.println("Error sending message: " + e.getMessage());
      throw new CantSendMessageException(CantSendMessageException.DEFAULT_MESSAGE, e);
    }
  }
  public void springTest() {

    System.out.println("Iniciando springTest() = ");

    List<PlatformComponentProfile> resultList = new ArrayList<>();

    try {

      /*
       * Construct a jsonObject whit the parameters
       */
      Gson gson = new Gson();
      JsonObject jsonObject = new JsonObject();
      jsonObject.addProperty(
          JsonAttNamesConstants.NAME_IDENTITY,
          "09A3B707D154r3B12C7CC626BCD7CF19EA8813B1B56A1B75E1C27335F8086C7ED588A7A06BCA67A289B73097FF67F5B1A0844FF2D550A6FCEFB66277EFDEB13A1");
      jsonObject.addProperty(
          JsonAttNamesConstants.DISCOVERY_PARAM,
          "{\"networkServiceType\":\"UNDEFINED\",\"platformComponentType\":\"ACTOR_INTRA_USER\"}");

      // Create a new RestTemplate instance
      HttpHeaders requestHeaders = new HttpHeaders();
      requestHeaders.setAccept(
          Collections.singletonList(new org.springframework.http.MediaType("application", "json")));
      HttpEntity<?> requestEntity = new HttpEntity<Object>(jsonObject.toString(), requestHeaders);
      RestTemplate restTemplate = new RestTemplate();
      restTemplate.getMessageConverters().add(new StringHttpMessageConverter());

      ResponseEntity<String> responseEntity =
          restTemplate.exchange(WEB_SERVICE_URL, HttpMethod.POST, requestEntity, String.class);

      String respond = responseEntity.getBody();
      System.out.println("responseEntity = " + respond);

      /*
       * if respond have the result list
       */
      if (respond.length() > 39) {

        /*
         * Decode into a json object
         */
        JsonParser parser = new JsonParser();
        JsonObject respondJsonObject = (JsonObject) parser.parse(respond.toString());

        // JsonObject respondJsonObject = (JsonObject) parser.parse(stringRepresentation.getText());

        /*
         * Get the receivedList
         */
        resultList =
            gson.fromJson(
                respondJsonObject.get(JsonAttNamesConstants.RESULT_LIST).getAsString(),
                new TypeToken<List<PlatformComponentProfileCommunication>>() {}.getType());

        System.out.println("resultList.size() = " + resultList.size());

        for (PlatformComponentProfile componentProfile : resultList) {
          System.out.println(
              "componentProfile.getIdentityPublicKey() = "
                  + componentProfile.getIdentityPublicKey());
          System.out.println("componentProfile.getAlias() = " + componentProfile.getAlias());
          System.out.println("componentProfile.getName() = " + componentProfile.getName());
          System.out.println(
              "componentProfile.getExtraData() = " + componentProfile.getExtraData().length());
          System.out.println("----------------------------------------------------------------");
          System.out.println("\n");
        }

      } else {
        System.out.println(
            "WsCommunicationsCloudClientConnection - Requested list is not available, resultList.size() = "
                + resultList.size());
      }

    } catch (Exception e) {

      e.printStackTrace();
    }
  }
  /**
   * (non-javadoc)
   *
   * @see CommunicationsClientConnection#requestDiscoveryVpnConnection(PlatformComponentProfile,
   *     PlatformComponentProfile, PlatformComponentProfile)
   */
  @Override
  public void requestDiscoveryVpnConnection(
      PlatformComponentProfile applicantParticipant,
      PlatformComponentProfile applicantNetworkService,
      PlatformComponentProfile remoteParticipant)
      throws CantEstablishConnectionException {

    try {

      System.out.println("WsCommunicationsCloudClientConnection - requestDiscoveryVpnConnection");

      /*
       * Validate parameter
       */
      if (applicantParticipant == null
          || applicantNetworkService == null
          || remoteParticipant == null) {

        throw new IllegalArgumentException("All parameters are required, can not be null");
      }

      /*
       * Validate are the  type NETWORK_SERVICE
       */
      if (applicantNetworkService.getPlatformComponentType()
          != PlatformComponentType.NETWORK_SERVICE) {
        throw new IllegalArgumentException(
            "All the PlatformComponentProfile has to be NETWORK_SERVICE ");
      }

      /*
       * Construct the json object
       */
      Gson gson = new Gson();
      JsonObject packetContent = new JsonObject();
      packetContent.addProperty(
          JsonAttNamesConstants.APPLICANT_PARTICIPANT_VPN, applicantParticipant.toJson());
      packetContent.addProperty(
          JsonAttNamesConstants.APPLICANT_PARTICIPANT_NS_VPN, applicantNetworkService.toJson());
      packetContent.addProperty(
          JsonAttNamesConstants.REMOTE_PARTICIPANT_VPN, remoteParticipant.toJson());

      /*
       * Convert to json representation
       */
      String packetContentJson = gson.toJson(packetContent);

      /*
       * Construct a fermat packet whit the request
       */
      FermatPacket fermatPacketRespond =
          FermatPacketCommunicationFactory.constructFermatPacketEncryptedAndSinged(
              wsCommunicationsCloudClientChannel.getServerIdentity(), // Destination
              wsCommunicationsCloudClientChannel.getClientIdentity().getPublicKey(), // Sender
              packetContentJson, // Message Content
              FermatPacketType.DISCOVERY_COMPONENT_CONNECTION_REQUEST, // Packet type
              wsCommunicationsCloudClientChannel
                  .getClientIdentity()
                  .getPrivateKey()); // Sender private key
      /*
       * Send the encode packet to the server
       */
      wsCommunicationsCloudClientChannel.send(FermatPacketEncoder.encode(fermatPacketRespond));

    } catch (Exception e) {

      CantEstablishConnectionException pluginStartException =
          new CantEstablishConnectionException(
              CantEstablishConnectionException.DEFAULT_MESSAGE,
              e,
              e.getLocalizedMessage(),
              e.getLocalizedMessage());
      throw pluginStartException;
    }
  }
  /**
   * Handles events that indicate a connection to been established between two network services and
   * prepares all objects to work with this new connection
   *
   * @param remoteComponentProfile
   */
  public void handleEstablishedRequestedNetworkServiceConnection(
      PlatformComponentProfile remoteComponentProfile) {

    try {

      /*
       * Get the active connection
       */
      CommunicationsVPNConnection communicationsVPNConnection =
          communicationsClientConnection.getCommunicationsVPNConnectionStablished(
              platformComponentProfile.getNetworkServiceType(), remoteComponentProfile);

      // Validate the connection
      if (communicationsVPNConnection != null && communicationsVPNConnection.isActive()) {

        /*
         * Instantiate the local reference
         */
        CommunicationNetworkServiceLocal communicationNetworkServiceLocal =
            new CommunicationNetworkServiceLocal(
                remoteComponentProfile,
                errorManager,
                eventManager,
                outgoingMessageDao,
                platformComponentProfile.getNetworkServiceType());

        /*
         * Instantiate the remote reference
         */
        CommunicationNetworkServiceRemoteAgent communicationNetworkServiceRemoteAgent =
            new CommunicationNetworkServiceRemoteAgent(
                identity,
                communicationsVPNConnection,
                errorManager,
                eventManager,
                incomingMessageDao,
                outgoingMessageDao);

        /*
         * Register the observer to the observable agent
         */
        communicationNetworkServiceRemoteAgent.addObserver(communicationNetworkServiceLocal);

        /*
         * Start the service thread
         */
        communicationNetworkServiceRemoteAgent.start();

        /*
         * Add to the cache
         */
        communicationNetworkServiceLocalsCache.put(
            remoteComponentProfile.getIdentityPublicKey(), communicationNetworkServiceLocal);
        communicationNetworkServiceRemoteAgentsCache.put(
            remoteComponentProfile.getIdentityPublicKey(), communicationNetworkServiceRemoteAgent);
      }

    } catch (Exception e) {
      e.printStackTrace();
      errorManager.reportUnexpectedPluginException(
          Plugins.CHAT_NETWORK_SERVICE,
          UnexpectedPluginExceptionSeverity.DISABLES_SOME_FUNCTIONALITY_WITHIN_THIS_PLUGIN,
          new Exception("Can not get connection"));
    }
  }
  /**
   * (no-javadoc)
   *
   * @see FermatTyrusPacketProcessor#processingPackage(FermatPacket)
   */
  @Override
  public void processingPackage(final FermatPacket receiveFermatPacket) {

    // System.out.println(" ---------------------------------------------------------------------
    // ");
    // System.out.println("ServerHandshakeRespondTyrusPacketProcessor - processingPackage");

    /* -----------------------------------------------------------------------------------------
     * IMPORTANT: This Message Content of this packet come encrypted with the temporal identity public key
     * and contain the server identity whit the communications cloud client that
     * have to use to talk with the server.
     * -----------------------------------------------------------------------------------------
     */

    /*
     * Decrypt the message content
     */
    String jsonRepresentation =
        AsymmetricCryptography.decryptMessagePrivateKey(
            receiveFermatPacket.getMessageContent(),
            getWsCommunicationsTyrusCloudClientChannel().getTemporalIdentity().getPrivateKey());

    /*
     * Construct the json object
     */
    JsonParser parser = new JsonParser();
    JsonObject serverIdentity = parser.parse(jsonRepresentation).getAsJsonObject();

    /*
     * Get the server identity and set into the communication cloud client
     */
    getWsCommunicationsTyrusCloudClientChannel()
        .setServerIdentity(serverIdentity.get(JsonAttNamesConstants.SERVER_IDENTITY).getAsString());

    // System.out.println("ServerHandshakeRespondTyrusPacketProcessor - ServerIdentity = "+
    // getWsCommunicationsTyrusCloudClientChannel().getServerIdentity());

    /*
     * Construct a Communications Cloud Client Profile for this component and send and fermat packet type FermatPacketType.COMPONENT_REGISTRATION_REQUEST
     */

    HardwareManager hardwareManager =
        getWsCommunicationsTyrusCloudClientChannel().getHardwareManager();
    CloudClientExtraData cloudClientExtraData = null;
    if (hardwareManager != null) {
      cloudClientExtraData =
          new CloudClientExtraData(
              hardwareManager.getOperativeSystem(),
              hardwareManager.getBoard(),
              hardwareManager.getBrand(),
              hardwareManager.getDevice());
    }

    PlatformComponentProfile communicationsCloudClientProfile =
        getWsCommunicationsTyrusCloudClientChannel()
            .getWsCommunicationsTyrusCloudClientConnection()
            .constructPlatformComponentProfileFactory(
                getWsCommunicationsTyrusCloudClientChannel().getClientIdentity().getPublicKey(),
                "WsCommunicationsCloudClientChannel",
                "Web Socket Communications Cloud Client",
                NetworkServiceType.UNDEFINED,
                PlatformComponentType.COMMUNICATION_CLOUD_CLIENT,
                (hardwareManager != null) ? new Gson().toJson(cloudClientExtraData) : null);
    getWsCommunicationsTyrusCloudClientChannel()
        .setPlatformComponentProfile(communicationsCloudClientProfile);

    /* ------------------------------------
     * IMPORTANT: At this moment the server only
     * know the temporal identity of the client
     * the packet has construct with this identity
     * --------------------------------------
     */

    /*
     * Construc the jsonObject
     */
    Gson gson = new Gson();
    JsonObject jsonObject = new JsonObject();
    jsonObject.addProperty(
        JsonAttNamesConstants.NETWORK_SERVICE_TYPE, NetworkServiceType.UNDEFINED.toString());
    jsonObject.addProperty(
        JsonAttNamesConstants.PROFILE_TO_REGISTER, communicationsCloudClientProfile.toJson());

    /*
     * Construct a fermat packet whit the server identity
     */
    FermatPacket fermatPacketRespond =
        FermatPacketCommunicationFactory.constructFermatPacketEncryptedAndSinged(
            getWsCommunicationsTyrusCloudClientChannel().getServerIdentity(), // Destination
            getWsCommunicationsTyrusCloudClientChannel()
                .getTemporalIdentity()
                .getPublicKey(), // Sender
            gson.toJson(jsonObject), // Message Content
            FermatPacketType.COMPONENT_REGISTRATION_REQUEST, // Packet type
            getWsCommunicationsTyrusCloudClientChannel()
                .getTemporalIdentity()
                .getPrivateKey()); // Sender private key

    /*
     * Send the encode packet to the server
     */
    getWsCommunicationsTyrusCloudClientChannel()
        .sendMessage(FermatPacketEncoder.encode(fermatPacketRespond));
  }