/**
   * Returns a Page of DocumentPackages, that last updated in time range, which represents a
   * paginated query response. Important once you have many DocumentPackages.
   *
   * @param status Returned DocumentPackages must have their status set to this value to be included
   *     in the result set
   * @param request Identifying which page of results to return
   * @param from Date range starting from this date included
   * @param to Date range ending of this date included
   * @return List of DocumentPackages that populate the specified page
   */
  public Page<DocumentPackage> getUpdatedPackagesWithinDateRange(
      PackageStatus status, PageRequest request, Date from, Date to) {
    String fromDate = DateHelper.dateToIsoUtcFormat(from);
    String toDate = DateHelper.dateToIsoUtcFormat(to);

    String path =
        template
            .urlFor(UrlTemplate.PACKAGE_LIST_STATUS_DATE_RANGE_PATH)
            .replace("{status}", new PackageStatusConverter(status).toAPIPackageStatus())
            .replace("{from}", Integer.toString(request.getFrom()))
            .replace("{to}", Integer.toString(request.to()))
            .replace("{lastUpdatedStartDate}", fromDate)
            .replace("{lastUpdatedEndDate}", toDate)
            .build();

    try {
      String response = client.get(path);
      Result<Package> results =
          JacksonUtil.deserialize(response, new TypeReference<Result<Package>>() {});
      return convertToPage(results, request);
    } catch (RequestException e) {
      throw new EslServerException("Could not get package list.", e);
    } catch (Exception e) {
      e.printStackTrace();
      throw new EslException("Could not get package list. Exception: " + e.getMessage());
    }
  }
  /**
   * Get the document's metadata from the package.
   *
   * @param documentPackage The DocumentPackage we want to get document from.
   * @param documentId Id of document to get.
   * @return the document's metadata
   */
  public com.silanis.esl.sdk.Document getDocumentMetadata(
      DocumentPackage documentPackage, String documentId) {
    String path =
        template
            .urlFor(UrlTemplate.DOCUMENT_ID_PATH)
            .replace("{packageId}", documentPackage.getId().getId())
            .replace("{documentId}", documentId)
            .build();

    try {
      String response = client.get(path);
      Document apilDocument = Serialization.fromJson(response, Document.class);

      // Wipe out the members not related to the metadata
      apilDocument.setApprovals(new ArrayList<Approval>());
      apilDocument.setFields(new ArrayList<Field>());
      apilDocument.setPages(new ArrayList<com.silanis.esl.api.model.Page>());

      return new DocumentConverter(
              apilDocument, new DocumentPackageConverter(documentPackage).toAPIPackage())
          .toSDKDocument();
    } catch (RequestException e) {
      throw new EslServerException("Could not get the document's metadata.", e);
    } catch (Exception e) {
      throw new EslException(
          "Could not get the document's metadata." + " Exception: " + e.getMessage());
    }
  }
  /**
   * Get Journal Entries.
   *
   * @param userId The ID of the user whose e-journal entries are being retrieved.
   * @return all of the user's notary e-journal entries.
   */
  public List<com.silanis.esl.sdk.NotaryJournalEntry> getJournalEntries(String userId) {
    List<com.silanis.esl.sdk.NotaryJournalEntry> result =
        new ArrayList<com.silanis.esl.sdk.NotaryJournalEntry>();
    String path =
        template.urlFor(UrlTemplate.NOTARY_JOURNAL_PATH).replace("{userId}", userId).build();

    try {
      String stringResponse = client.get(path);
      Result<com.silanis.esl.api.model.NotaryJournalEntry> apiResponse =
          JacksonUtil.deserialize(
              stringResponse,
              new TypeReference<Result<com.silanis.esl.api.model.NotaryJournalEntry>>() {});
      for (com.silanis.esl.api.model.NotaryJournalEntry apiNotaryJournalEntry :
          apiResponse.getResults()) {
        result.add(
            new NotaryJournalEntryConverter(apiNotaryJournalEntry).toSDKNotaryJournalEntry());
      }
      return result;

    } catch (RequestException e) {
      throw new EslException("Could not get Journal Entries.", e);
    } catch (Exception e) {
      throw new EslException("Could not get Journal Entries." + " Exception: " + e.getMessage());
    }
  }
  /**
   * Gets the package.
   *
   * @param packageId
   * @return Package
   * @throws EslException
   */
  public Package getApiPackage(String packageId) throws EslException {
    String path =
        template.urlFor(UrlTemplate.PACKAGE_ID_PATH).replace("{packageId}", packageId).build();
    String stringResponse;
    try {
      stringResponse = client.get(path);
    } catch (RequestException e) {
      throw new EslServerException("Could not get package.", e);
    } catch (Exception e) {
      throw new EslException("Could not get package.", e);
    }

    return Serialization.fromJson(stringResponse, Package.class);
  }
 /**
  * Gets the roles for a package.
  *
  * @param packageId
  * @return A list of the roles in the package
  * @throws EslException
  */
 public List<Role> getRoles(PackageId packageId) throws EslException {
   String path =
       template.urlFor(UrlTemplate.ROLE_PATH).replace("{packageId}", packageId.getId()).build();
   String stringResponse;
   try {
     stringResponse = client.get(path);
   } catch (RequestException e) {
     throw new EslServerException(
         "Could not retrieve list of roles for package with id " + packageId.getId(), e);
   } catch (Exception e) {
     throw new EslException(
         "Could not retrieve list of roles for package with id " + packageId.getId(), e);
   }
   return Serialization.fromJson(stringResponse, RoleList.class).getResults();
 }
  /**
   * Gets the documents from the history list
   *
   * @return
   */
  public List<com.silanis.esl.sdk.Document> getDocuments() {
    String path = template.urlFor(UrlTemplate.PROVIDER_DOCUMENTS).build();

    try {
      String stringResponse = client.get(path);
      List<Document> apiResponse =
          JacksonUtil.deserialize(stringResponse, new TypeReference<List<Document>>() {});
      List<com.silanis.esl.sdk.Document> documents = new ArrayList<com.silanis.esl.sdk.Document>();
      for (Document document : apiResponse) {
        documents.add(new DocumentConverter(document, null).toSDKDocument());
      }
      return documents;
    } catch (RequestException e) {
      throw new EslServerException("Failed to retrieve documents from history List.", e);
    } catch (Exception e) {
      throw new EslException("Failed to retrieve documents from history list.", e);
    }
  }
  /**
   * Get thank you dialog content.
   *
   * @param packageId The id of the package to get thank you dialog content.
   * @return thank you dialog content
   */
  public String getThankYouDialogContent(PackageId packageId) {
    String path =
        template
            .urlFor(UrlTemplate.THANK_YOU_DIALOG_PATH)
            .replace("{packageId}", packageId.getId())
            .build();

    try {
      String json = client.get(path);
      Properties thankYouDialogContent = Serialization.fromJson(json, Properties.class);
      return thankYouDialogContent.getProperty("body");
    } catch (RequestException e) {
      throw new EslException("Could not get thank you dialog content.", e);
    } catch (Exception e) {
      throw new EslException(
          "Could not get thank you dialog content." + " Exception: " + e.getMessage());
    }
  }
  private String getFastTrackUrl(PackageId packageId, Boolean signing) {
    String path =
        template
            .urlFor(UrlTemplate.FAST_TRACK_URL_PATH)
            .replace("{packageId}", packageId.getId())
            .replace("{signing}", signing.toString())
            .build();

    try {
      String json = client.get(path);
      SigningUrl signingUrl = Serialization.fromJson(json, SigningUrl.class);
      return signingUrl.getUrl();
    } catch (RequestException e) {
      throw new EslException("Could not get a fastTrack url.", e);
    } catch (Exception e) {
      throw new EslException("Could not get a fastTrack url." + " Exception: " + e.getMessage());
    }
  }
  /**
   * Get package support configuration.
   *
   * @param packageId The id of the package to get package support configuration.
   * @return package support configuration
   */
  public SupportConfiguration getConfig(PackageId packageId) {
    String path =
        template
            .urlFor(UrlTemplate.PACKAGE_INFORMATION_CONFIG_PATH)
            .replace("{packageId}", packageId.getId())
            .build();

    try {
      String json = client.get(path);
      com.silanis.esl.api.model.SupportConfiguration apiSupportConfiguration =
          Serialization.fromJson(json, com.silanis.esl.api.model.SupportConfiguration.class);
      return new SupportConfigurationConverter(apiSupportConfiguration).toSDKSupportConfiguration();
    } catch (RequestException e) {
      throw new EslException("Could not get support configuration.", e);
    } catch (Exception e) {
      throw new EslException(
          "Could not get support configuration." + " Exception: " + e.getMessage());
    }
  }
  private String getSigningUrl(PackageId packageId, Role role) {

    String path =
        template
            .urlFor(UrlTemplate.SIGNER_URL_PATH)
            .replace("{packageId}", packageId.getId())
            .replace("{roleId}", role.getId())
            .build();

    try {
      String response = client.get(path);
      SigningUrl signingUrl = Serialization.fromJson(response, SigningUrl.class);
      return signingUrl.getUrl();
    } catch (RequestException e) {
      throw new EslException("Could not get a signing url.", e);
    } catch (Exception e) {
      throw new EslException("Could not get a signing url." + " Exception: " + e.getMessage());
    }
  }
  /**
   * Get a signer from the specified package
   *
   * @param packageId The id of the package in which to get the signer
   * @param signerId The id of signer to get
   * @return The signer
   */
  public com.silanis.esl.sdk.Signer getSigner(PackageId packageId, String signerId) {
    String path =
        template
            .urlFor(UrlTemplate.SIGNER_PATH)
            .replace("{packageId}", packageId.getId())
            .replace("{roleId}", signerId)
            .build();

    try {
      String response = client.get(path);
      Role apiRole = Serialization.fromJson(response, Role.class);
      return new SignerConverter(apiRole).toSDKSigner();

    } catch (RequestException e) {
      throw new EslServerException("Could not get signer.", e);
    } catch (Exception e) {
      throw new EslException("Could not get signer." + " Exception: " + e.getMessage());
    }
  }
  public Page<DocumentPackage> getTemplates(PageRequest request) {
    String path =
        template
            .urlFor(UrlTemplate.TEMPLATE_LIST_PATH)
            .replace("{from}", Integer.toString(request.getFrom()))
            .replace("{to}", Integer.toString(request.to()))
            .build();

    try {
      String response = client.get(path);
      Result<Package> results =
          JacksonUtil.deserialize(response, new TypeReference<Result<Package>>() {});

      return convertToPage(results, request);
    } catch (RequestException e) {
      throw new EslServerException("Could not get template list.", e);
    } catch (Exception e) {
      throw new EslException("Could not get template list. Exception: " + e.getMessage());
    }
  }
  /**
   * Retrieves the current signing status of the DocumentPackage, Document or Signer specified.
   *
   * @param packageId Id of the DocumentPackage who's status we are to retrieve
   * @param signerId If not null, the id of the signer who's status we are to retrieve
   * @param documentId If not null, the id of the document who's status we are to retrieve
   * @return One of the following values: INACTIVE - process is not active COMPLETE - process has
   *     been completed ARCHIVED - process has been archived SIGNING-PENDING - process is active,
   *     but not all signatures have been added SIGNING-COMPLETE - process is active, all signaures
   *     have been added
   */
  public SigningStatus getSigningStatus(
      PackageId packageId, SignerId signerId, DocumentId documentId) {
    String path =
        template
            .urlFor(UrlTemplate.SIGNING_STATUS_PATH)
            .replace("{packageId}", packageId.getId())
            .replace("{signerId}", signerId != null ? signerId.getId() : "")
            .replace("{documentId}", documentId != null ? documentId.getId() : "")
            .build();

    try {
      String stringResponse = client.get(path);
      ObjectMapper objectMapper = new ObjectMapper();
      JsonNode topNode = objectMapper.readTree(stringResponse);
      String statusString = topNode.get("status").textValue();
      return SigningStatus.statusForToken(statusString);
    } catch (RequestException e) {
      throw new EslServerException("Could not retrieve signing status.", e);
    } catch (Exception e) {
      throw new EslException("Could not retrieve signing status.", e);
    }
  }