/**
   * Gets all the Event Item Attributes.<br>
   * Implements the get Event Item Attributes operation of the EventSpot API by calling the
   * ConstantContact server side.
   *
   * @param accessToken Constant Contact OAuth2 access token.
   * @param eventId The event id.
   * @param itemId The event item id.
   * @return A {@link List} of {@link EventItemAttribute} containing data as returned by the server
   *     on success; <br>
   *     An exception is thrown otherwise.
   * @throws ConstantContactServiceException When something went wrong in the Constant Contact flow
   *     or an error is returned from server.
   */
  @Override
  public List<EventItemAttribute> getEventItemAttributes(
      String accessToken, String eventId, String itemId) throws ConstantContactServiceException {
    List<EventItemAttribute> eventItemAttributes = null;
    try {
      String url =
          String.format(
              "%1$s%2$s",
              Config.Endpoints.BASE_URL,
              String.format(Config.Endpoints.EVENT_ITEM_ATTRIBUTES, eventId, itemId));

      CUrlResponse response = getRestClient().get(url, accessToken);

      if (response.hasData()) {
        eventItemAttributes = Component.listFromJSON(response.getBody(), EventItemAttribute.class);
      }
      if (response.isError()) {
        ConstantContactServiceException constantContactException =
            new ConstantContactServiceException(
                ConstantContactServiceException.RESPONSE_ERR_SERVICE);
        response.getInfo().add(new CUrlRequestError("url", url));
        constantContactException.setErrorInfo(response.getInfo());
        throw constantContactException;
      }
    } catch (ConstantContactServiceException e) {
      throw new ConstantContactServiceException(e);
    } catch (Exception e) {
      throw new ConstantContactServiceException(e);
    }
    return eventItemAttributes;
  }
  /**
   * Updates a single Event Item.<br>
   * Implements the update Event Item operation of the EventSpot API by calling the ConstantContact
   * server side.
   *
   * @param accessToken Constant Contact OAuth2 access token.
   * @param eventId The id of the event.
   * @param item The event item to update.
   * @return An {@link EventItem} containing data as returned by the server on success; <br>
   *     An exception is thrown otherwise.
   * @throws ConstantContactServiceException When something went wrong in the Constant Contact flow
   *     or an error is returned from server.
   */
  @Override
  public EventItem updateEventItem(String accessToken, String eventId, EventItem item)
      throws ConstantContactServiceException {
    EventItem eventItem = null;
    try {
      String url =
          String.format(
              "%1$s%2$s",
              Config.Endpoints.BASE_URL,
              String.format(Config.Endpoints.EVENT_ITEM_ID, eventId, item.getId()));
      String json = item.toJSON();

      CUrlResponse response = getRestClient().put(url, accessToken, json);
      if (response.hasData()) {
        eventItem = Component.fromJSON(response.getBody(), EventItem.class);
      }
      if (response.isError()) {
        ConstantContactServiceException constantContactException =
            new ConstantContactServiceException(
                ConstantContactServiceException.RESPONSE_ERR_SERVICE);
        response.getInfo().add(new CUrlRequestError("url", url));
        constantContactException.setErrorInfo(response.getInfo());
        throw constantContactException;
      }
    } catch (ConstantContactServiceException e) {
      throw new ConstantContactServiceException(e);
    } catch (Exception e) {
      throw new ConstantContactServiceException(e);
    }
    return eventItem;
  }
  /**
   * Deletes a single Event Item.<br>
   * Implements the delete Event Item operation of the EventSpot API by calling the ConstantContact
   * server side.
   *
   * @param accessToken Constant Contact OAuth2 access token.
   * @param eventId The id of the event.
   * @param itemId The id of the event item to delete.
   * @return true on success; <br>
   *     An exception is thrown otherwise.
   * @throws ConstantContactServiceException When something went wrong in the Constant Contact flow
   *     or an error is returned from server.
   */
  @Override
  public boolean deleteEventItem(String accessToken, String eventId, String itemId)
      throws ConstantContactServiceException {
    try {
      String url =
          String.format(
              "%1$s%2$s",
              Config.Endpoints.BASE_URL,
              String.format(Config.Endpoints.EVENT_ITEM_ID, eventId, itemId));

      CUrlResponse response = getRestClient().delete(url, accessToken);
      if (response.isError()) {
        ConstantContactServiceException constantContactException =
            new ConstantContactServiceException(
                ConstantContactServiceException.RESPONSE_ERR_SERVICE);
        response.getInfo().add(new CUrlRequestError("url", url));
        constantContactException.setErrorInfo(response.getInfo());
        throw constantContactException;
      }
      return response.getStatusCode() == HttpURLConnection.HTTP_NO_CONTENT;
    } catch (ConstantContactServiceException e) {
      throw new ConstantContactServiceException(e);
    } catch (Exception e) {
      throw new ConstantContactServiceException(e);
    }
  }
  /**
   * Gets all the Event Registrants.<br>
   * Implements the get Event Registrants operation of the EventSpot API by calling the
   * ConstantContact server side.
   *
   * @param accessToken Constant Contact OAuth2 access token.
   * @param eventId The id of the event.
   * @param limit The limit.
   * @return A {@link ResultSet} of {@link Registrant} containing data as returned by the server on
   *     success; <br>
   *     An exception is thrown otherwise.
   * @throws ConstantContactServiceException When something went wrong in the Constant Contact flow
   *     or an error is returned from server.
   */
  @Override
  public ResultSet<Registrant> getEventRegistrants(
      String accessToken, String eventId, Integer limit) throws ConstantContactServiceException {
    ResultSet<Registrant> eventRegistrants = null;
    try {
      String url =
          paginateUrl(
              String.format(
                  "%1$s%2$s",
                  Config.Endpoints.BASE_URL,
                  String.format(Config.Endpoints.EVENT_REGISTRANTS, eventId)),
              limit);

      CUrlResponse response = getRestClient().get(url, accessToken);

      if (response.hasData()) {
        eventRegistrants = Component.resultSetFromJSON(response.getBody(), Registrant.class);
      }
      if (response.isError()) {
        ConstantContactServiceException constantContactException =
            new ConstantContactServiceException(
                ConstantContactServiceException.RESPONSE_ERR_SERVICE);
        response.getInfo().add(new CUrlRequestError("url", url));
        constantContactException.setErrorInfo(response.getInfo());
        throw constantContactException;
      }
    } catch (ConstantContactServiceException e) {
      throw new ConstantContactServiceException(e);
    } catch (Exception e) {
      throw new ConstantContactServiceException(e);
    }
    return eventRegistrants;
  }
  /**
   * Gets a single Event Registrant.<br>
   * Implements the get Event Registrant operation of the EventSpot API by calling the
   * ConstantContact server side.
   *
   * @param accessToken Constant Contact OAuth2 access token.
   * @param eventId The id of the event.
   * @param registrantId The id of the event registrant.
   * @return An {@link RegistrantDetails} containing data as returned by the server on success; <br>
   *     An exception is thrown otherwise.
   * @throws ConstantContactServiceException When something went wrong in the Constant Contact flow
   *     or an error is returned from server.
   */
  @Override
  public RegistrantDetails getEventRegistrant(
      String accessToken, String eventId, String registrantId)
      throws ConstantContactServiceException {
    RegistrantDetails registrant = null;
    try {
      String url =
          String.format(
              "%1$s%2$s",
              Config.Endpoints.BASE_URL,
              String.format(Config.Endpoints.EVENT_REGISTRANT_ID, eventId, registrantId));

      CUrlResponse response = getRestClient().get(url, accessToken);

      if (response.hasData()) {
        registrant = Component.fromJSON(response.getBody(), RegistrantDetails.class);
      }
      if (response.isError()) {
        ConstantContactServiceException constantContactException =
            new ConstantContactServiceException(
                ConstantContactServiceException.RESPONSE_ERR_SERVICE);
        response.getInfo().add(new CUrlRequestError("url", url));
        constantContactException.setErrorInfo(response.getInfo());
        throw constantContactException;
      }
    } catch (ConstantContactServiceException e) {
      throw new ConstantContactServiceException(e);
    } catch (Exception e) {
      throw new ConstantContactServiceException(e);
    }
    return registrant;
  }
  /**
   * Adds a single Event Fee.<br>
   * Implements the add Event Fee operation of the EventSpot API by calling the ConstantContact
   * server side.
   *
   * @param accessToken Constant Contact OAuth2 access token.
   * @param eventId The id of the event.
   * @param eventFee The event fee to add.
   * @return An {@link EventFee} containing data as returned by the server on success; <br>
   *     An exception is thrown otherwise.
   * @throws ConstantContactServiceException When something went wrong in the Constant Contact flow
   *     or an error is returned from server.
   */
  @Override
  public EventFee addEventFee(String accessToken, String eventId, EventFee eventFee)
      throws ConstantContactServiceException {
    EventFee newEventFee = null;
    try {
      String url =
          String.format(
              "%1$s%2$s",
              Config.Endpoints.BASE_URL, String.format(Config.Endpoints.EVENT_FEES, eventId));
      String json = eventFee.toJSON();

      CUrlResponse response = getRestClient().post(url, accessToken, json);
      if (response.hasData()) {
        newEventFee = Component.fromJSON(response.getBody(), EventFee.class);
      }
      if (response.isError()) {
        ConstantContactServiceException constantContactException =
            new ConstantContactServiceException(
                ConstantContactServiceException.RESPONSE_ERR_SERVICE);
        response.getInfo().add(new CUrlRequestError("url", url));
        constantContactException.setErrorInfo(response.getInfo());
        throw constantContactException;
      }
    } catch (ConstantContactServiceException e) {
      throw new ConstantContactServiceException(e);
    } catch (Exception e) {
      throw new ConstantContactServiceException(e);
    }
    return newEventFee;
  }
  /**
   * Updates a single Event Promocode.<br>
   * Implements the update Event Promocode operation of the EventSpot API by calling the
   * ConstantContact server side.
   *
   * @param accessToken Constant Contact OAuth2 access token.
   * @param eventId The id of the event.
   * @param promocode The event promocode to update.
   * @return An {@link Promocode} containing data as returned by the server on success; <br>
   *     An exception is thrown otherwise.
   * @throws ConstantContactServiceException When something went wrong in the Constant Contact flow
   *     or an error is returned from server.
   */
  @Override
  public Promocode updateEventPromocode(String accessToken, String eventId, Promocode promocode)
      throws ConstantContactServiceException {
    Promocode newPromocode = null;
    try {
      String url =
          String.format(
              "%1$s%2$s",
              Config.Endpoints.BASE_URL,
              String.format(Config.Endpoints.EVENT_PROMOCODE_ID, eventId, promocode.getId()));
      String json = promocode.toJSON();

      CUrlResponse response = getRestClient().put(url, accessToken, json);
      if (response.hasData()) {
        newPromocode = Component.fromJSON(response.getBody(), Promocode.class);
      }
      if (response.isError()) {
        ConstantContactServiceException constantContactException =
            new ConstantContactServiceException(
                ConstantContactServiceException.RESPONSE_ERR_SERVICE);
        response.getInfo().add(new CUrlRequestError("url", url));
        constantContactException.setErrorInfo(response.getInfo());
        throw constantContactException;
      }
    } catch (ConstantContactServiceException e) {
      throw new ConstantContactServiceException(e);
    } catch (Exception e) {
      throw new ConstantContactServiceException(e);
    }
    return newPromocode;
  }
  /**
   * Updates the Event status.<br>
   * Implements the update Event Status operation of the EventSpot API by calling the
   * ConstantContact server side.
   *
   * @param accessToken Constant Contact OAuth2 access token.
   * @param eventId The id of the event to update.
   * @param status The status of the event.
   * @return true on success;<br>
   *     An exception is thrown otherwise.
   * @throws ConstantContactServiceException When something went wrong in the Constant Contact flow
   *     or an error is returned from server.
   */
  @Override
  public boolean updateEventStatus(String accessToken, String eventId, String status)
      throws ConstantContactServiceException {
    try {
      String url =
          String.format(
              "%1$s%2$s",
              Config.Endpoints.BASE_URL, String.format(Config.Endpoints.EVENT_ID, eventId));

      EventUpdateStatus eventUpdateStatus = new EventUpdateStatus(status);
      List<EventUpdateStatus> eventUpdateStatusRequestList = new ArrayList<EventUpdateStatus>();
      eventUpdateStatusRequestList.add(eventUpdateStatus);
      EventUpdateStatusRequest eventUpdateStatusRequest =
          new EventUpdateStatusRequest(eventUpdateStatusRequestList);
      String json = eventUpdateStatusRequest.toJSON();

      CUrlResponse response = getRestClient().patch(url, accessToken, json);
      if (response.isError()) {
        ConstantContactServiceException constantContactException =
            new ConstantContactServiceException(
                ConstantContactServiceException.RESPONSE_ERR_SERVICE);
        response.getInfo().add(new CUrlRequestError("url", url));
        constantContactException.setErrorInfo(response.getInfo());
        throw constantContactException;
      }
      return response.getStatusCode() == HttpURLConnection.HTTP_NO_CONTENT;
    } catch (ConstantContactServiceException e) {
      throw new ConstantContactServiceException(e);
    } catch (Exception e) {
      throw new ConstantContactServiceException(e);
    }
  }
  /**
   * Add a large number of contacts in a single batch operation.<br>
   * Implements the bulk add Contacts operation by calling the ConstantContact server side.
   *
   * @param accessToken Constant Contact OAuth2 access token.
   * @param request The request
   * @return A response containing the values returned from the server for the requested operation
   *     on success; <br>
   *     An exception is thrown otherwise.
   * @throws ConstantContactServiceException When something went wrong in the Constant Contact flow
   *     or an error is returned from server.
   */
  public ContactsResponse addContacts(String accessToken, AddContactsRequest request)
      throws ConstantContactServiceException {

    ContactsResponse contactsResponse = null;
    try {
      String url = Config.Endpoints.BASE_URL + Config.Endpoints.ACTIVITIES_ADD_CONTACTS;
      String json = request.toJSON();
      CUrlResponse response = getRestClient().post(url, accessToken, json);
      if (response.hasData()) {
        contactsResponse = Component.fromJSON(response.getBody(), ContactsResponse.class);
      }

      if (response.isError()) {
        ConstantContactServiceException constantContactException =
            new ConstantContactServiceException(
                ConstantContactServiceException.RESPONSE_ERR_SERVICE);
        response.getInfo().add(new CUrlRequestError("url", url));
        constantContactException.setErrorInfo(response.getInfo());
        throw constantContactException;
      }
    } catch (ConstantContactServiceException e) {
      throw new ConstantContactServiceException(e);
    } catch (Exception e) {
      throw new ConstantContactServiceException(e);
    }
    return contactsResponse;
  }
  /**
   * Implements the bulk get Summary Report operation by calling the ConstantContact server side.
   *
   * @param accessToken Constant Contact OAuth2 access token.
   * @return A response containing the values returned from the server for the requested operation
   *     on success; <br>
   *     An exception is thrown otherwise.
   * @throws ConstantContactServiceException When something went wrong in the Constant Contact flow
   *     or an error is returned from server.
   */
  public List<SummaryReport> getSummaryReport(String accessToken)
      throws ConstantContactServiceException {
    List<SummaryReport> activitiesResponse = null;
    try {
      String url = Config.Endpoints.BASE_URL + Config.Endpoints.ACTIVITIES;

      CUrlResponse response = getRestClient().get(url, accessToken);
      if (response.hasData()) {
        activitiesResponse = Component.listFromJSON(response.getBody(), SummaryReport.class);
      }
      if (response.isError()) {
        ConstantContactServiceException constantContactException =
            new ConstantContactServiceException(
                ConstantContactServiceException.RESPONSE_ERR_SERVICE);
        response.getInfo().add(new CUrlRequestError("url", url));
        constantContactException.setErrorInfo(response.getInfo());
        throw constantContactException;
      }
    } catch (ConstantContactServiceException e) {
      throw new ConstantContactServiceException(e);
    } catch (Exception e) {
      throw new ConstantContactServiceException(e);
    }
    return activitiesResponse;
  }
  public ContactsResponse removeContactsFromLists(
      String accessToken, MultipartBody multipartRequest) throws ConstantContactServiceException {

    ContactsResponse contactsResponse = null;
    try {
      String url = Config.Endpoints.BASE_URL + Config.Endpoints.ACTIVITIES_REMOVE_FROM_LISTS;
      CUrlResponse response = getRestClient().postMultipart(url, accessToken, multipartRequest);
      if (response.hasData()) {
        contactsResponse = Component.fromJSON(response.getBody(), ContactsResponse.class);
      }
      if (response.isError()) {
        ConstantContactServiceException constantContactException =
            new ConstantContactServiceException(
                ConstantContactServiceException.RESPONSE_ERR_SERVICE);
        response.getInfo().add(new CUrlRequestError("url", url));
        constantContactException.setErrorInfo(response.getInfo());
        throw constantContactException;
      }
    } catch (ConstantContactServiceException e) {
      throw new ConstantContactServiceException(e);
    } catch (Exception e) {
      throw new ConstantContactServiceException(e);
    }
    return contactsResponse;
  }
  /**
   * Implements the bulk get Detailed Status Report operation by calling the ConstantContact server
   * side.
   *
   * @param accessToken Constant Contact OAuth2 access token.
   * @param status The status, as seen in {@link BulkActivityStatus}
   * @param type The type, as seen in {@link BulkActivityType}
   * @param id The id
   * @return A response containing the values returned from the server for the requested operation
   *     on success; <br>
   *     An exception is thrown otherwise.
   * @throws ConstantContactServiceException When something went wrong in the Constant Contact flow
   *     or an error is returned from server.
   */
  public List<DetailedStatusReport> getDetailedStatusReport(
      String accessToken, String status, String type, String id)
      throws ConstantContactServiceException {

    List<DetailedStatusReport> detailedStatusReports = null;

    String url = Config.Endpoints.BASE_URL + Config.Endpoints.ACTIVITIES;
    try {
      if (status != null && status.length() > 0) {
        url = appendParam(url, "status", status);
      }
      if (type != null && type.length() > 0) {
        url = appendParam(url, "type", type);
      }
      if (id != null && id.length() > 0) {
        url = appendParam(url, "id", id);
      }

      CUrlResponse response = getRestClient().get(url, accessToken);
      if (response.hasData()) {
        detailedStatusReports =
            Component.listFromJSON(response.getBody(), DetailedStatusReport.class);
      }
      if (response.isError()) {
        ConstantContactServiceException constantContactException =
            new ConstantContactServiceException(
                ConstantContactServiceException.RESPONSE_ERR_SERVICE);
        response.getInfo().add(new CUrlRequestError("url", url));
        constantContactException.setErrorInfo(response.getInfo());
        throw constantContactException;
      }
    } catch (ConstantContactServiceException e) {
      throw new ConstantContactServiceException(e);
    } catch (Exception e) {
      throw new ConstantContactServiceException(e);
    }
    return detailedStatusReports;
  }