/*
   * Gets the Author Tag for a specific topic
   */
  public RESTTagV1 getAuthorForTopic(final int topicId, final Integer rev) {
    if (rev == null) {
      final List<RESTTagV1> tags = this.getTagsByTopicId(topicId);

      if (tags != null) {
        for (RESTTagV1 tag : tags) {
          if (ComponentTagV1.containedInCategory(tag, CSConstants.WRITER_CATEGORY_ID)) return tag;
        }
      }
    } else {
      final RESTTopicV1 topic = this.getTopicById(topicId, rev);
      if (topic != null) {
        for (RESTTopicV1 topicRevision : topic.getRevisions().getItems()) {
          if (topicRevision.getRevision().equals(rev)) {
            List<RESTTagV1> writerTags =
                ComponentBaseTopicV1.returnTagsInCategoriesByID(
                    topicRevision, CollectionUtilities.toArrayList(CSConstants.WRITER_CATEGORY_ID));
            if (writerTags.size() == 1) return writerTags.get(0);
            break;
          }
        }
      }
    }
    return null;
  }
 /*
  * Gets a list of Revision's from the CSProcessor database for a specific
  * content spec
  */
 public Integer getLatestCSRevById(final Integer csId) {
   final RESTTopicV1 cs = getTopicById(csId, null, false);
   if (cs != null) {
     return cs.getRevision();
   }
   return null;
 }
 /*
  * Gets a List of TopicSourceUrl tuples for a specified its TopicID
  * relationship through TopicToTopicSourceUrl.
  */
 public List<RESTTopicSourceUrlV1> getSourceUrlsByTopicId(final int topicId) {
   final RESTTopicV1 topic;
   if (entityCache.containsKeyValue(RESTTopicV1.class, topicId)) {
     topic = entityCache.get(RESTTopicV1.class, topicId);
   } else {
     topic = getTopicById(topicId, null);
   }
   return topic == null ? null : topic.getSourceUrls_OTM().getItems();
 }
  /*
   * Gets a translated topic based on a topic id and locale
   */
  public RESTTranslatedTopicV1 getTranslatedTopicByTopicId(
      final Integer id, final Integer rev, final String locale) {
    if (locale == null) return null;
    final RESTTopicV1 topic = getTopicById(id, rev, true);
    if (topic == null) return null;

    for (final RESTTranslatedTopicV1 translatedTopic : topic.getTranslatedTopics_OTM().getItems()) {
      if (translatedTopic.getLocale().equals(locale)) return translatedTopic;
    }

    return null;
  }
  /*
   * Gets a ContentSpec tuple for a specified id.
   */
  public RESTTranslatedTopicV1 getTranslatedContentSpecById(
      final int id, final Integer rev, final String locale) {
    if (locale == null) return null;
    final RESTTopicV1 cs = getTopicById(id, rev, true);
    if (cs == null) return null;

    final List<RESTTagV1> topicTypes =
        ComponentBaseTopicV1.returnTagsInCategoriesByID(
            cs, CollectionUtilities.toArrayList(CSConstants.TYPE_CATEGORY_ID));
    if (cs.getTranslatedTopics_OTM() != null && cs.getTranslatedTopics_OTM().getItems() != null) {
      for (final RESTTagV1 type : topicTypes) {
        if (type.getId().equals(CSConstants.CONTENT_SPEC_TAG_ID)) {
          for (final RESTTranslatedTopicV1 topic : cs.getTranslatedTopics_OTM().getItems()) {
            if (topic.getLocale().equals(locale)) return topic;
          }
        }
      }
    }
    return null;
  }
  /*
   * Get the Pre Processed Content Specification for a ID and Revision
   */
  public RESTTopicV1 getPreContentSpecById(final Integer id, final Integer revision) {
    final RESTTopicV1 cs = getContentSpecById(id, revision);
    final List<Object[]> specRevisions = getContentSpecRevisionsById(id);

    if (specRevisions == null) return null;

    // Create a sorted set of revision ids that are less the the current
    // revision
    final SortedSet<Integer> sortedSpecRevisions = new TreeSet<Integer>();
    for (final Object[] specRev : specRevisions) {
      if ((Integer) specRev[0] <= cs.getRevision()) {
        sortedSpecRevisions.add((Integer) specRev[0]);
      }
    }

    if (sortedSpecRevisions.size() == 0) return null;

    // Find the Pre Content Spec from the revisions
    RESTTopicV1 preContentSpec = null;
    Integer specRev = sortedSpecRevisions.last();
    while (specRev != null) {
      final RESTTopicV1 contentSpecRev = getContentSpecById(id, specRev);
      if (ComponentBaseRESTEntityWithPropertiesV1
                  .<RESTTopicV1, RESTTopicCollectionV1>returnProperty(
                      contentSpecRev, CSConstants.CSP_TYPE_PROPERTY_TAG_ID)
              != null
          && ComponentBaseRESTEntityWithPropertiesV1.returnProperty(
                  contentSpecRev, CSConstants.CSP_TYPE_PROPERTY_TAG_ID)
              .getValue()
              .equals(CSConstants.CSP_PRE_PROCESSED_STRING)) {
        preContentSpec = contentSpecRev;
        break;
      }
      specRev =
          sortedSpecRevisions.headSet(specRev).isEmpty()
              ? null
              : sortedSpecRevisions.headSet(specRev).last();
    }
    return preContentSpec;
  }
  /*
   * Gets a list of Revision's from the CSProcessor database for a specific
   * content spec
   */
  public List<Object[]> getContentSpecRevisionsById(final Integer csId) {
    final List<Object[]> results = new ArrayList<Object[]>();
    try {
      final List<String> additionalKeys =
          CollectionUtilities.toArrayList("revision", "topic" + csId);
      final BaseRestCollectionV1<RESTTopicV1, RESTTopicCollectionV1> topicRevisions;
      if (collectionsCache.containsKey(RESTTopicV1.class, additionalKeys)) {
        topicRevisions =
            collectionsCache.get(RESTTopicV1.class, RESTTopicCollectionV1.class, additionalKeys);
      } else {
        /* We need to expand the Revisions collection */
        final ExpandDataTrunk expand = new ExpandDataTrunk();
        final ExpandDataTrunk expandTags = new ExpandDataTrunk(new ExpandDataDetails("tags"));
        final ExpandDataTrunk expandRevs = new ExpandDataTrunk(new ExpandDataDetails("revisions"));
        expandTags.setBranches(
            CollectionUtilities.toArrayList(
                new ExpandDataTrunk(new ExpandDataDetails("categories"))));
        expandRevs.setBranches(
            CollectionUtilities.toArrayList(
                expandTags,
                new ExpandDataTrunk(new ExpandDataDetails("sourceUrls")),
                new ExpandDataTrunk(new ExpandDataDetails("properties")),
                new ExpandDataTrunk(new ExpandDataDetails("outgoingRelationships")),
                new ExpandDataTrunk(new ExpandDataDetails("incomingRelationships"))));
        expand.setBranches(CollectionUtilities.toArrayList(expandTags, expandRevs));

        final String expandString = mapper.writeValueAsString(expand);
        // final String expandEncodedString = URLEncoder.encode(expandString, "UTF-8");

        final RESTTopicV1 topic = client.getJSONTopic(csId, expandString);
        // Check that the topic is a content spec
        if (!ComponentBaseTopicV1.hasTag(topic, CSConstants.CONTENT_SPEC_TAG_ID)) return null;

        // Add the content spec revisions to the cache
        collectionsCache.add(RESTTopicV1.class, topic.getRevisions(), additionalKeys, true);
        topicRevisions = topic.getRevisions();
      }

      // Create the unique array from the revisions
      if (topicRevisions != null && topicRevisions.getItems() != null) {
        for (RESTTopicV1 topicRev : topicRevisions.getItems()) {
          Object[] revision = new Object[2];
          revision[0] = topicRev.getRevision();
          revision[1] = topicRev.getLastModified();
          results.add(revision);
        }
      }
      return results;
    } catch (Exception e) {
      log.error(ExceptionUtilities.getStackTrace(e));
    }
    return null;
  }
  /*
   * Gets a list of Revision's from the TopicIndex database for a specific
   * topic
   */
  public List<Object[]> getTopicRevisionsById(final Integer topicId) {
    final List<Object[]> results = new ArrayList<Object[]>();
    try {
      final List<String> additionalKeys =
          CollectionUtilities.toArrayList("revisions", "topic" + topicId);
      final BaseRestCollectionV1<RESTTopicV1, RESTTopicCollectionV1> topicRevisions;
      if (collectionsCache.containsKey(RESTTopicV1.class, additionalKeys)) {
        topicRevisions =
            collectionsCache.get(RESTTopicV1.class, RESTTopicCollectionV1.class, additionalKeys);
      } else {
        /* We need to expand the Revisions collection */
        final ExpandDataTrunk expand = new ExpandDataTrunk();
        final ExpandDataTrunk expandTags = new ExpandDataTrunk(new ExpandDataDetails("tags"));
        final ExpandDataTrunk expandRevs = new ExpandDataTrunk(new ExpandDataDetails("revisions"));
        expandTags.setBranches(
            CollectionUtilities.toArrayList(
                new ExpandDataTrunk(new ExpandDataDetails("categories"))));
        expandRevs.setBranches(
            CollectionUtilities.toArrayList(
                expandTags,
                new ExpandDataTrunk(new ExpandDataDetails("sourceUrls")),
                new ExpandDataTrunk(new ExpandDataDetails("properties")),
                new ExpandDataTrunk(new ExpandDataDetails("outgoingRelationships")),
                new ExpandDataTrunk(new ExpandDataDetails("incomingRelationships"))));
        expand.setBranches(CollectionUtilities.toArrayList(expandRevs));

        final String expandString = mapper.writeValueAsString(expand);
        // final String expandEncodedString = URLEncoder.encode(expandString, "UTF-8");

        final RESTTopicV1 topic = client.getJSONTopic(topicId, expandString);
        collectionsCache.add(RESTTopicV1.class, topic.getRevisions(), additionalKeys, true);
        topicRevisions = topic.getRevisions();
      }

      // Create the custom revisions list
      if (topicRevisions != null && topicRevisions.getItems() != null) {
        for (final RESTTopicV1 topicRev : topicRevisions.getItems()) {
          Object[] revision = new Object[2];
          revision[0] = topicRev.getRevision();
          revision[1] = topicRev.getLastModified();
          results.add(revision);
        }
      }
      return results;
    } catch (Exception e) {
      log.debug(e.getMessage());
      e.printStackTrace();
    }
    return null;
  }