/**
   * (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;
    }
  }
  /**
   * 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());
  }
  /**
   * Count the number of filter to apply
   *
   * @param discoveryQueryParameters
   * @return int
   */
  private int countFilers(DiscoveryQueryParameters discoveryQueryParameters) {

    int total = 0;

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

    if (discoveryQueryParameters.getAlias() != null && discoveryQueryParameters.getAlias() != "") {
      total += 1;
    }

    if (discoveryQueryParameters.getName() != null && discoveryQueryParameters.getName() != "") {
      total += 1;
    }

    if (discoveryQueryParameters.getExtraData() != null
        && discoveryQueryParameters.getExtraData() != "") {
      total += 1;
    }

    return total;
  }
  @Post("application/json")
  public String getList(Representation entity) {

    System.out.println(" --------------------------------------------------------------------- ");
    System.out.println("ComponentRegisteredListWebService - Starting getList");
    JsonObject jsonObjectRespond = new JsonObject();

    try {

      wsCommunicationCloudServer =
          (WsCommunicationCloudServer)
              getContext().getAttributes().get(WebServicesApplication.PLUGIN_ROOT_ATT_NAME);

      /*
       * Construct the json object
       */
      JSONObject requestParametersJsonObject = (new JsonRepresentation(entity)).getJsonObject();

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

      String clientIdentityPublicKey =
          requestParametersJsonObject.getString(JsonAttNamesConstants.NAME_IDENTITY);
      DiscoveryQueryParameters discoveryQueryParameters =
          new DiscoveryQueryParametersCommunication()
              .fromJson(
                  requestParametersJsonObject.getString(JsonAttNamesConstants.DISCOVERY_PARAM));

      /*
       * hold the result list
       */
      List<PlatformComponentProfile> resultList = null;

      if (discoveryQueryParameters.getFromOtherPlatformComponentType() == null
          && discoveryQueryParameters.getFromOtherNetworkServiceType() == null) {

        resultList =
            applyDiscoveryQueryParameters(discoveryQueryParameters, clientIdentityPublicKey);

      } else {

        resultList =
            applyDiscoveryQueryParametersFromOtherComponent(
                discoveryQueryParameters, clientIdentityPublicKey);
      }

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

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

      /*
       * Create the respond
       */
      jsonObjectRespond.addProperty(JsonAttNamesConstants.RESULT_LIST, jsonListRepresentation);

    } catch (Exception e) {

      System.out.println("ComponentRegisteredListWebService - requested list is not available");
      jsonObjectRespond.addProperty(
          JsonAttNamesConstants.FAILURE, "Requested list is not available");
      e.printStackTrace();
    }

    String jsonString = gson.toJson(jsonObjectRespond);

    JsonRepresentation jsonRepresentationRespond = new JsonRepresentation(jsonString.trim());

    System.out.println(
        "ComponentRegisteredListWebService - jsonString.length() = " + jsonString.length());
    System.out.println(
        "ComponentRegisteredListWebService - jsonRepresentationRespond.getSize() = "
            + jsonRepresentationRespond.getSize());

    return jsonString;
  }
  /**
   * 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;
  }
  /**
   * Method that request to the communication cloud server the list of component registered that
   * match whit the discovery query params
   *
   * @param discoveryQueryParameters
   * @throws CantRequestListException this exception means the list receive is empty or a internal
   *     error
   */
  public List<PlatformComponentProfile> requestListComponentRegisteredSocket(
      DiscoveryQueryParameters discoveryQueryParameters) throws CantRequestListException {

    System.out.println(
        "WsCommunicationsCloudClientConnection - new requestListComponentRegistered");
    List<PlatformComponentProfile> resultList = new ArrayList<>();
    Socket clientConnect = null;
    BufferedReader bufferedReader = null;
    PrintWriter printWriter = null;

    try {

      /*
       * Validate parameter
       */
      if (discoveryQueryParameters == null) {
        throw new IllegalArgumentException(
            "The discoveryQueryParameters is required, can not be null");
      }

      /*
       * Construct a jsonObject whit the parameters
       */
      Gson gson = new Gson();
      JsonObject jsonObject = new JsonObject();
      jsonObject.addProperty(
          JsonAttNamesConstants.NAME_IDENTITY,
          wsCommunicationsCloudClientChannel.getIdentityPublicKey());
      jsonObject.addProperty(
          JsonAttNamesConstants.DISCOVERY_PARAM, discoveryQueryParameters.toJson());

      clientConnect = new Socket(WsCommunicationsCloudClientPluginRoot.SERVER_IP, 9001);
      bufferedReader = new BufferedReader(new InputStreamReader(clientConnect.getInputStream()));

      printWriter = new PrintWriter(clientConnect.getOutputStream());
      printWriter.println(gson.toJson(jsonObject));
      printWriter.flush();

      String respondServer = bufferedReader.readLine();

      if (respondServer != null
          && respondServer != ""
          && respondServer.contains(JsonAttNamesConstants.RESULT_LIST)) {

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

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

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

      bufferedReader.close();
      printWriter.close();
      clientConnect.close();

    } catch (Exception e) {

      try {

        if (clientConnect != null) {
          bufferedReader.close();
          printWriter.close();
          clientConnect.close();
        }

      } catch (Exception ex) {
      }

      e.printStackTrace();
      CantRequestListException cantRequestListException =
          new CantRequestListException(
              CantRequestListException.DEFAULT_MESSAGE,
              e,
              e.getLocalizedMessage(),
              e.getLocalizedMessage());
      throw cantRequestListException;
    }

    return resultList;
  }
  /**
   * (non-javadoc)
   *
   * @see CommunicationsClientConnection#requestListComponentRegistered(DiscoveryQueryParameters)
   */
  @Override
  public List<PlatformComponentProfile> requestListComponentRegistered(
      DiscoveryQueryParameters discoveryQueryParameters) throws CantRequestListException {

    System.out.println(
        "WsCommunicationsCloudClientConnection - new requestListComponentRegistered");
    List<PlatformComponentProfile> resultList = new ArrayList<>();

    try {

      /*
       * Validate parameter
       */
      if (discoveryQueryParameters == null) {
        throw new IllegalArgumentException(
            "The discoveryQueryParameters is required, can not be null");
      }

      /*
       * Construct a jsonObject whit the parameters
       */
      Gson gson = new Gson();
      JsonObject jsonObject = new JsonObject();
      jsonObject.addProperty(
          JsonAttNamesConstants.NAME_IDENTITY,
          wsCommunicationsCloudClientChannel.getIdentityPublicKey());
      jsonObject.addProperty(
          JsonAttNamesConstants.DISCOVERY_PARAM, discoveryQueryParameters.toJson());

      // Create a new RestTemplate instance
      HttpHeaders requestHeaders = new HttpHeaders();
      requestHeaders.set("Connection", "Close");
      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(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));

      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.contains(JsonAttNamesConstants.RESULT_LIST)) {

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

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

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

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

    } catch (Exception e) {
      e.printStackTrace();
      CantRequestListException cantRequestListException =
          new CantRequestListException(
              CantRequestListException.DEFAULT_MESSAGE,
              e,
              e.getLocalizedMessage(),
              e.getLocalizedMessage());
      throw cantRequestListException;
    }

    return resultList;
  }