/**
   * 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);
    }
  }
  /** Stop the internal threads */
  public void stop() {

    // Stop the Threads
    toReceive.interrupt();
    toSend.interrupt();

    // Disconnect from the service
    communicationsVPNConnection.close();
  }
  /**
   * 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"));
    }
  }
  /**
   * This method read for new messages pending to send on the data base in the table <code>
   * outbox_messages</code> and encrypt the message content, sing the message and send it
   */
  public void processMessageToSend() {

    try {

      try {

        Map<String, Object> filters = new HashMap<>();
        filters.put(
            CommunicationNetworkServiceDatabaseConstants.OUTGOING_MESSAGES_STATUS_COLUMN_NAME,
            MessagesStatus.PENDING_TO_SEND.getCode());
        filters.put(
            CommunicationNetworkServiceDatabaseConstants.OUTGOING_MESSAGES_RECEIVER_ID_COLUMN_NAME,
            communicationsVPNConnection.getRemoteParticipant().getIdentityPublicKey());

        /*
         * Read all pending message from database
         */
        List<FermatMessage> messages = outgoingMessageDao.findAll(filters);
        /*
         * For each message
         */
        for (FermatMessage message : messages) {

          if (communicationsVPNConnection.isActive()
              && (message.getFermatMessagesStatus() != FermatMessagesStatus.SENT)) {

            /*
             * Encrypt the content of the message whit the remote network service public key
             */
            ((FermatMessageCommunication) message)
                .setContent(
                    AsymmetricCryptography.encryptMessagePublicKey(
                        message.getContent(),
                        communicationsVPNConnection
                            .getRemoteParticipantNetworkService()
                            .getIdentityPublicKey()));

            /*
             * Sing the message
             */
            String signature =
                AsymmetricCryptography.createMessageSignature(
                    message.getContent(), eccKeyPair.getPrivateKey());
            ((FermatMessageCommunication) message).setSignature(signature);

            /*
             * Send the message
             */
            communicationsVPNConnection.sendMessage(message);

            /*
             * Change the message and update in the data base
             */

            ((FermatMessageCommunication) message)
                .setFermatMessagesStatus(FermatMessagesStatus.SENT);
            outgoingMessageDao.update(message);

            /*
             * Put the message on a event and fire new event
             */
            FermatEvent fermatEvent =
                eventManager.getNewEvent(
                    P2pEventType.NEW_NETWORK_SERVICE_MESSAGE_SENT_NOTIFICATION);
            fermatEvent.setSource(AssetIssuerActorNetworkServicePluginRoot.EVENT_SOURCE);
            ((NewNetworkServiceMessageSentNotificationEvent) fermatEvent).setData(message);
            eventManager.raiseEvent(fermatEvent);
          }
        }

      } catch (CantUpdateRecordDataBaseException e) {
        errorManager.reportUnexpectedPluginException(
            Plugins.BITDUBAI_DAP_ASSET_ISSUER_ACTOR_NETWORK_SERVICE,
            UnexpectedPluginExceptionSeverity.DISABLES_SOME_FUNCTIONALITY_WITHIN_THIS_PLUGIN,
            new Exception("Can not process messages to send. Error reason: " + e.getMessage()));
      } catch (CantReadRecordDataBaseException e) {
        errorManager.reportUnexpectedPluginException(
            Plugins.BITDUBAI_DAP_ASSET_ISSUER_ACTOR_NETWORK_SERVICE,
            UnexpectedPluginExceptionSeverity.DISABLES_SOME_FUNCTIONALITY_WITHIN_THIS_PLUGIN,
            new Exception("Can not process messages to send. Error reason: " + e.getMessage()));
      }

      // Sleep for a time
      toSend.sleep(CommunicationNetworkServiceRemoteAgent.SLEEP_TIME);

    } catch (InterruptedException e) {
      errorManager.reportUnexpectedPluginException(
          Plugins.BITDUBAI_DAP_ASSET_ISSUER_ACTOR_NETWORK_SERVICE,
          UnexpectedPluginExceptionSeverity.DISABLES_SOME_FUNCTIONALITY_WITHIN_THIS_PLUGIN,
          new Exception("Can not sleep"));
    }
  }
  /**
   * This method process the message received and save on the data base in the table <code>
   * incoming_messages</code> and notify all observers to the new messages received
   */
  private void processMessageReceived() {

    try {

      // System.out.println("CommunicationNetworkServiceRemoteAgent -
      // communicationsVPNConnection.isActive() = "+communicationsVPNConnection.isActive());

      /** Verified the status of the connection */
      if (communicationsVPNConnection.isActive()) {

        // System.out.println("CommunicationNetworkServiceRemoteAgent -
        // communicationsVPNConnection.getUnreadMessagesCount() =
        // "+communicationsVPNConnection.getUnreadMessagesCount());

        /** process all pending messages */
        for (int i = 0; i < communicationsVPNConnection.getUnreadMessagesCount(); i++) {

          /*
           * Read the next message in the queue
           */
          FermatMessage message = communicationsVPNConnection.readNextMessage();

          /*
           * Validate the message signature
           */
          AsymmetricCryptography.verifyMessageSignature(
              message.getSignature(),
              message.getContent(),
              communicationsVPNConnection
                  .getRemoteParticipantNetworkService()
                  .getIdentityPublicKey());

          /*
           * Decrypt the message content
           */
          ((FermatMessageCommunication) message)
              .setContent(
                  AsymmetricCryptography.decryptMessagePrivateKey(
                      message.getContent(), eccKeyPair.getPrivateKey()));

          /*
           * Change to the new status
           */
          ((FermatMessageCommunication) message)
              .setFermatMessagesStatus(FermatMessagesStatus.NEW_RECEIVED);

          /*
           * Save to the data base table
           */
          incomingMessageDao.create(message);

          /*
           * Remove the message from the queue
           */
          communicationsVPNConnection.removeMessageRead(message);

          /*
           * Notify all observer of this agent that Received a new message
           */
          setChanged();
          notifyObservers(message);
        }
      }

      // Sleep for a time
      toReceive.sleep(CommunicationNetworkServiceRemoteAgent.SLEEP_TIME);

    } catch (InterruptedException e) {
      errorManager.reportUnexpectedPluginException(
          Plugins.BITDUBAI_DAP_ASSET_ISSUER_ACTOR_NETWORK_SERVICE,
          UnexpectedPluginExceptionSeverity.DISABLES_SOME_FUNCTIONALITY_WITHIN_THIS_PLUGIN,
          new Exception("Can not sleep"));
    } catch (CantInsertRecordDataBaseException e) {
      errorManager.reportUnexpectedPluginException(
          Plugins.BITDUBAI_DAP_ASSET_ISSUER_ACTOR_NETWORK_SERVICE,
          UnexpectedPluginExceptionSeverity.DISABLES_SOME_FUNCTIONALITY_WITHIN_THIS_PLUGIN,
          new Exception("Can not process message received. Error reason: " + e.getMessage()));
    }
  }