content: package com.fernandocejas.frodo.internal;
  
  import com.fernandocejas.frodo.core.optional.Optional;
  import com.fernandocejas.frodo.internal.observable.ObservableInfo;
  import com.fernandocejas.frodo.joinpoint.FrodoJoinPoint;
  import java.util.List;
  
  /**
   * Class used to build different messages that will be shown in debug mode
   */
  class MessageBuilder {
  
    private static final String LOG_START = "@";
    private static final String SEPARATOR = " :: ";
    private static final String METHOD_SEPARATOR = "#";
    private static final String VALUE_SEPARATOR = " -> ";
    private static final String TEXT_ENCLOSING_SYMBOL = "'";
    private static final String LOG_ENCLOSING_OPEN = "[";
    private static final String LOG_ENCLOSING_CLOSE = "]";
    private static final String LIBRARY_LABEL = "Frodo => ";
    private static final String CLASS_LABEL = LOG_START + "InClass" + VALUE_SEPARATOR;
    private static final String METHOD_LABEL = LOG_START + "Method" + VALUE_SEPARATOR;
    private static final String TIME_LABEL = LOG_START + "Time" + VALUE_SEPARATOR;
    private static final String TIME_MILLIS = " ms";
    private static final String OBSERVABLE_LABEL = LOG_START + "Observable";
    private static final String EMITTED_ELEMENTS_LABEL = LOG_START + "Emitted" + VALUE_SEPARATOR;
    private static final String LABEL_OBSERVABLE_ON_SUBSCRIBE = "onSubscribe()";
    private static final String LABEL_OBSERVABLE_ON_NEXT = "onNext()";
    private static final String LABEL_OBSERVABLE_ON_ERROR = "onError()";
    private static final String LABEL_OBSERVABLE_ON_COMPLETED = "onCompleted()";
    private static final String LABEL_OBSERVABLE_ON_TERMINATE = "onTerminate()";
    private static final String LABEL_OBSERVABLE_ON_UNSUBSCRIBE = "onUnsubscribe()";
    private static final String LABEL_OBSERVABLE_SUBSCRIBE_ON =
        LOG_START + "SubscribeOn" + VALUE_SEPARATOR;
    private static final String SUBSCRIBER_LABEL = LOG_START + "Subscriber";
    private static final String LABEL_SUBSCRIBER_ON_START = "onStart()";
    private static final String LABEL_SUBSCRIBER_ON_NEXT = "onNext()";
    private static final String LABEL_SUBSCRIBER_ON_ERROR = "onError()";
    private static final String LABEL_SUBSCRIBER_ON_COMPLETED = "onCompleted()";
    private static final String LABEL_SUBSCRIBER_UN_SUBSCRIBE = "unSubscribe()";
    private static final String LABEL_SUBSCRIBER_OBSERVE_ON =
        LOG_START + "ObserveOn" + VALUE_SEPARATOR;
    private static final String REQUESTED_ELEMENTS_LABEL = LOG_START + "Requested" + VALUE_SEPARATOR;
    private static final String RECEIVED_ELEMENTS_LABEL = LOG_START + "Received" + VALUE_SEPARATOR;
    private static final String LABEL_ELEMENT_SINGULAR = " element";
    private static final String LABEL_ELEMENT_PLURAL = " elements";
    private static final String LABEL_MESSAGE_NULL_OBSERVABLES = "You received a null observable";
  
    MessageBuilder() {}
  
    String buildObservableInfoMessage(ObservableInfo observableInfo) {
      final FrodoJoinPoint joinPoint = observableInfo.getJoinPoint();
      final StringBuilder message = buildObservableSB();
      message.append(SEPARATOR);
      message.append(CLASS_LABEL);
      message.append(observableInfo.getClassSimpleName());
      message.append(SEPARATOR);
      message.append(METHOD_LABEL);
      message.append(observableInfo.getMethodName());
      message.append(buildMethodSignatureWithValues(joinPoint));
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    String buildObservableOnSubscribeMessage(ObservableInfo observableInfo) {
      final StringBuilder message = buildObservableSB();
      message.append(METHOD_SEPARATOR);
      message.append(observableInfo.getMethodName());
      message.append(VALUE_SEPARATOR);
      message.append(LABEL_OBSERVABLE_ON_SUBSCRIBE);
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    <T> String buildObservableOnNextWithValueMessage(ObservableInfo observableInfo, T value) {
      final StringBuilder message = buildObservableSB();
      message.append(METHOD_SEPARATOR);
      message.append(observableInfo.getMethodName());
      message.append(VALUE_SEPARATOR);
      message.append(LABEL_OBSERVABLE_ON_NEXT);
      message.append(VALUE_SEPARATOR);
      message.append(String.valueOf(value));
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    String buildObservableOnNextMessage(ObservableInfo observableInfo) {
      final StringBuilder message = buildObservableSB();
      message.append(METHOD_SEPARATOR);
      message.append(observableInfo.getMethodName());
      message.append(VALUE_SEPARATOR);
      message.append(LABEL_OBSERVABLE_ON_NEXT);
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    String buildObservableOnErrorMessage(ObservableInfo observableInfo, String errorMessage) {
      final StringBuilder message = buildObservableSB();
      message.append(METHOD_SEPARATOR);
      message.append(observableInfo.getMethodName());
      message.append(VALUE_SEPARATOR);
      message.append(LABEL_OBSERVABLE_ON_ERROR);
      message.append(VALUE_SEPARATOR);
      message.append(TEXT_ENCLOSING_SYMBOL);
      message.append(errorMessage);
      message.append(TEXT_ENCLOSING_SYMBOL);
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    String buildObservableOnCompletedMessage(ObservableInfo observableInfo) {
      final StringBuilder message = buildObservableSB();
      message.append(METHOD_SEPARATOR);
      message.append(observableInfo.getMethodName());
      message.append(VALUE_SEPARATOR);
      message.append(LABEL_OBSERVABLE_ON_COMPLETED);
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    String buildObservableOnTerminateMessage(ObservableInfo observableInfo) {
      final StringBuilder message = buildObservableSB();
      message.append(METHOD_SEPARATOR);
      message.append(observableInfo.getMethodName());
      message.append(VALUE_SEPARATOR);
      message.append(LABEL_OBSERVABLE_ON_TERMINATE);
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    String buildObservableOnUnsubscribeMessage(ObservableInfo observableInfo) {
      final StringBuilder message = buildObservableSB();
      message.append(METHOD_SEPARATOR);
      message.append(observableInfo.getMethodName());
      message.append(VALUE_SEPARATOR);
      message.append(LABEL_OBSERVABLE_ON_UNSUBSCRIBE);
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    String buildSubscriberOnStartMessage(String subscriberName) {
      final StringBuilder message = buildSubscriberSB();
      message.append(SEPARATOR);
      message.append(subscriberName);
      message.append(VALUE_SEPARATOR);
      message.append(LABEL_SUBSCRIBER_ON_START);
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    String buildSubscriberOnNextMessage(String subscriberName, Object value, String threadName) {
      final StringBuilder message = buildSubscriberSB();
      message.append(SEPARATOR);
      message.append(subscriberName);
      message.append(VALUE_SEPARATOR);
      message.append(LABEL_SUBSCRIBER_ON_NEXT);
      message.append(VALUE_SEPARATOR);
      message.append(value != null ? value.toString() : LABEL_MESSAGE_NULL_OBSERVABLES);
      message.append(SEPARATOR);
      message.append(LABEL_SUBSCRIBER_OBSERVE_ON);
      message.append(threadName);
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    String buildSubscriberOnErrorMessage(String subscriberName, String error) {
      final StringBuilder message = buildSubscriberSB();
      message.append(SEPARATOR);
      message.append(subscriberName);
      message.append(VALUE_SEPARATOR);
      message.append(LABEL_SUBSCRIBER_ON_ERROR);
      message.append(VALUE_SEPARATOR);
      message.append(error);
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    String buildSubscriberOnCompletedMessage(String subscriberName) {
      final StringBuilder message = buildSubscriberSB();
      message.append(SEPARATOR);
      message.append(subscriberName);
      message.append(VALUE_SEPARATOR);
      message.append(LABEL_SUBSCRIBER_ON_COMPLETED);
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    String buildSubscriberItemTimeMessage(String subscriberName, long executionTimeMillis,
        int receivedItems) {
      final StringBuilder message = buildSubscriberSB();
      message.append(SEPARATOR);
      message.append(subscriberName);
      message.append(VALUE_SEPARATOR);
      message.append(RECEIVED_ELEMENTS_LABEL);
      message.append(receivedItems);
      message.append(receivedItems == 1 ? LABEL_ELEMENT_SINGULAR : LABEL_ELEMENT_PLURAL);
      message.append(SEPARATOR);
      message.append(TIME_LABEL);
      message.append(executionTimeMillis);
      message.append(TIME_MILLIS);
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    String buildSubscriberRequestedItemsMessage(String subscriberName, long requestedItems) {
      final StringBuilder message = buildSubscriberSB();
      message.append(SEPARATOR);
      message.append(subscriberName);
      message.append(VALUE_SEPARATOR);
      message.append(REQUESTED_ELEMENTS_LABEL);
      message.append(requestedItems);
      message.append(requestedItems == 1 ? LABEL_ELEMENT_SINGULAR : LABEL_ELEMENT_PLURAL);
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    String buildSubscriberUnsubscribeMessage(String subscriberName) {
      final StringBuilder message = buildSubscriberSB();
      message.append(SEPARATOR);
      message.append(subscriberName);
      message.append(VALUE_SEPARATOR);
      message.append(LABEL_SUBSCRIBER_UN_SUBSCRIBE);
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    String buildObservableItemTimeInfoMessage(ObservableInfo observableInfo) {
      final int totalEmittedItems = observableInfo.getTotalEmittedItems().or(0);
      final long totalExecutionTime = observableInfo.getTotalExecutionTime().or(0L);
      final StringBuilder message = buildObservableSB();
      message.append(METHOD_SEPARATOR);
      message.append(observableInfo.getMethodName());
      message.append(VALUE_SEPARATOR);
      message.append(EMITTED_ELEMENTS_LABEL);
      message.append(totalEmittedItems);
      message.append(totalEmittedItems == 1 ? LABEL_ELEMENT_SINGULAR : LABEL_ELEMENT_PLURAL);
      message.append(SEPARATOR);
      message.append(TIME_LABEL);
      message.append(totalExecutionTime);
      message.append(TIME_MILLIS);
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    String buildObservableThreadInfoMessage(ObservableInfo observableInfo) {
      final Optional<String> subscribeOnThread = observableInfo.getSubscribeOnThread();
      final Optional<String> observeOnThread = observableInfo.getObserveOnThread();
      final StringBuilder message = buildObservableSB();
      message.append(METHOD_SEPARATOR);
      message.append(observableInfo.getMethodName());
      message.append(VALUE_SEPARATOR);
      if (subscribeOnThread.isPresent()) {
        message.append(LABEL_OBSERVABLE_SUBSCRIBE_ON);
        message.append(subscribeOnThread.get());
      }
      if (observeOnThread.isPresent()) {
        message.append(SEPARATOR);
        message.append(LABEL_SUBSCRIBER_OBSERVE_ON);
        message.append(observeOnThread.get());
      }
      message.append(LOG_ENCLOSING_CLOSE);
  
      return message.toString();
    }
  
    private StringBuilder buildSubscriberSB() {
      final int avgStringSize = 75;
      final StringBuilder message = new StringBuilder(avgStringSize + LIBRARY_LABEL.length());
      message.append(LIBRARY_LABEL);
      message.append(LOG_ENCLOSING_OPEN);
      message.append(SUBSCRIBER_LABEL);
      return message;
    }
  
    private StringBuilder buildObservableSB() {
      final int avgStringSize = 75;
      final StringBuilder message = new StringBuilder(avgStringSize + LIBRARY_LABEL.length());
      message.append(LIBRARY_LABEL);
      message.append(LOG_ENCLOSING_OPEN);
      message.append(OBSERVABLE_LABEL);
      return message;
    }
  
    private String buildMethodSignatureWithValues(FrodoJoinPoint joinPoint) {
      final int avg = 30;
      final StringBuilder stringBuilder = new StringBuilder(avg + joinPoint.getMethodName().length());
      stringBuilder.append("(");
      List<String> methodParamNames = joinPoint.getMethodParamNamesList();
      if (methodParamNames != null && !methodParamNames.isEmpty()) {
        for (int i = 0; i < joinPoint.getMethodParamNamesList().size(); i++) {
          stringBuilder.append(methodParamNames.get(i));
          stringBuilder.append("=");
          stringBuilder.append("'");
          stringBuilder.append(String.valueOf(joinPoint.getMethodParamValuesList().get(i)));
          stringBuilder.append("'");
          if ((i != methodParamNames.size() - 1)) {
            stringBuilder.append(", ");
          }
        }
      }
      stringBuilder.append(")");
  
      return stringBuilder.toString();
    }
  }
  