public ContainerTranslationStatistics getDocStatistics(Long documentId, LocaleId localeId) {
    ContainerTranslationStatistics result = documentDAO.getStatistics(documentId, localeId);

    TranslationStatistics wordStatistics = result.getStats(localeId.getId(), StatUnit.WORD);
    wordStatistics.setRemainingHours(StatisticsUtil.getRemainingHours(wordStatistics));

    TranslationStatistics msgStatistics = result.getStats(localeId.getId(), StatUnit.MESSAGE);
    msgStatistics.setRemainingHours(StatisticsUtil.getRemainingHours(wordStatistics));

    return result;
  }
  private void processWebHookDocumentMilestoneEvent(
      DocumentStatisticUpdatedEvent event,
      Collection<ContentState> contentStates,
      String message,
      int percentMilestone) {

    HProjectIteration version = projectIterationDAO.findById(event.getProjectIterationId());
    HProject project = version.getProject();

    if (!project.getWebHooks().isEmpty()) {
      WordStatistic stats =
          translationStateCacheImpl.getDocumentStatistics(
              event.getDocumentId(), event.getLocaleId());

      WordStatistic oldStats = StatisticsUtil.copyWordStatistic(stats);
      if (oldStats != null) {
        oldStats.decrement(event.getNewState(), event.getWordCount());
        oldStats.increment(event.getPreviousState(), event.getWordCount());

        boolean shouldPublish =
            hasContentStateReachedMilestone(oldStats, stats, contentStates, percentMilestone);

        if (shouldPublish) {
          HDocument document = documentDAO.getById(event.getDocumentId());

          String editorUrl =
              urlUtil.fullEditorDocumentUrl(
                  project.getSlug(),
                  version.getSlug(),
                  event.getLocaleId(),
                  LocaleId.EN_US,
                  document.getDocId());

          DocumentMilestoneEvent milestoneEvent =
              new DocumentMilestoneEvent(
                  project.getSlug(),
                  version.getSlug(),
                  document.getDocId(),
                  event.getLocaleId(),
                  message,
                  editorUrl);
          for (WebHook webHook : project.getWebHooks()) {
            publishDocumentMilestoneEvent(webHook, milestoneEvent);
          }
        }
      }
    }
  }
  // TODO Need to refactor this method to get Message statistic by default.
  // This is to be consistance with UI which uses message stats, and for
  // calculating remaining hours.
  @Override
  public ContainerTranslationStatistics getStatistics(
      String projectSlug,
      String iterationSlug,
      boolean includeDetails,
      boolean includeWordStats,
      String[] locales) {
    LocaleId[] localeIds;

    // if no locales are specified, search in all locales
    if (locales.length == 0) {
      List<HLocale> iterationLocales =
          localeServiceImpl.getSupportedLangugeByProjectIteration(projectSlug, iterationSlug);
      localeIds = new LocaleId[iterationLocales.size()];
      for (int i = 0, iterationLocalesSize = iterationLocales.size();
          i < iterationLocalesSize;
          i++) {
        HLocale loc = iterationLocales.get(i);
        localeIds[i] = loc.getLocaleId();
      }
    } else {
      localeIds = new LocaleId[locales.length];
      for (int i = 0; i < locales.length; i++) {
        localeIds[i] = new LocaleId(locales[i]);
      }
    }

    HProjectIteration iteration = projectIterationDAO.getBySlug(projectSlug, iterationSlug);

    if (iteration == null) {
      throw new NoSuchEntityException(projectSlug + "/" + iterationSlug);
    }

    Map<String, TransUnitCount> transUnitIterationStats =
        projectIterationDAO.getAllStatisticsForContainer(iteration.getId());
    Map<String, TransUnitWords> wordIterationStats =
        projectIterationDAO.getAllWordStatsStatistics(iteration.getId());

    ContainerTranslationStatistics iterationStats = new ContainerTranslationStatistics();
    iterationStats.setId(iterationSlug);
    iterationStats.addRef(
        new Link(
            URI.create(zPathService.generatePathForProjectIteration(iteration)),
            "statSource",
            "PROJ_ITER"));
    long iterationTotalMssgs =
        projectIterationDAO.getTotalMessageCountForIteration(iteration.getId());
    long iterationTotalWords = projectIterationDAO.getTotalWordCountForIteration(iteration.getId());

    for (LocaleId locId : localeIds) {
      // trans unit level stats
      TransUnitCount count = transUnitIterationStats.get(locId.getId());
      // Stats might not return anything if nothing is translated
      if (count == null) {
        count = new TransUnitCount(0, 0, (int) iterationTotalMssgs);
      }

      HTextFlowTarget target =
          localeServiceImpl.getLastTranslated(projectSlug, iterationSlug, locId);

      String lastModifiedBy = "";
      Date lastModifiedDate = null;

      if (target != null) {
        lastModifiedDate = target.getLastChanged();
        if (target.getLastModifiedBy() != null) {
          lastModifiedBy = target.getLastModifiedBy().getAccount().getUsername();
        }
      }

      TransUnitWords wordCount = wordIterationStats.get(locId.getId());
      if (wordCount == null) {
        wordCount = new TransUnitWords(0, 0, (int) iterationTotalWords);
      }

      TranslationStatistics transUnitStats =
          getMessageStats(count, locId, lastModifiedDate, lastModifiedBy);
      transUnitStats.setRemainingHours(StatisticsUtil.getRemainingHours(wordCount));
      iterationStats.addStats(transUnitStats);

      // word level stats
      if (includeWordStats) {
        TranslationStatistics wordsStats =
            getWordsStats(wordCount, locId, lastModifiedDate, lastModifiedBy);
        wordsStats.setRemainingHours(StatisticsUtil.getRemainingHours(wordCount));
        iterationStats.addStats(wordsStats);
      }
    }

    // TODO Do in a single query
    if (includeDetails) {
      for (String docId : iteration.getDocuments().keySet()) {
        iterationStats.addDetailedStats(
            this.getStatistics(projectSlug, iterationSlug, docId, includeWordStats, locales));
      }
    }

    return iterationStats;
  }