// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "peridot/bin/context_engine/index.h"

#include <algorithm>
#include <sstream>

#include <lib/fidl/cpp/clone.h>
#include <lib/fidl/cpp/optional.h>
#include <src/lib/fxl/logging.h>

namespace modular {

ContextIndex::ContextIndex() = default;
ContextIndex::~ContextIndex() = default;

namespace internal {
// Keys for fields within fuchsia::modular::ContextMetadata.story:
const char kStoryIdKey[] = "si";
const char kStoryFocusedKey[] = "sf";

// Keys for fields within fuchsia::modular::ContextMetadata.mod:
const char kModPathKey[] = "mp";
const char kModUrlKey[] = "mu";
const char kModuleFocusedKey[] = "mf";

// Keys for fields within fuchsia::modular::ContextMetadata.entity:
const char kEntityTopicKey[] = "et";
const char kEntityTypeKey[] = "ey";
// We don't index |ctime|.

// Key for fuchsia::modular::ContextValueType.
const char kContextValueTypeKey[] = "t";

std::set<std::string> EncodeMetadataAndType(fuchsia::modular::ContextValueType node_type,
                                            const fuchsia::modular::ContextMetadata& metadata) {
  fuchsia::modular::ContextMetadata meta_clone;
  fidl::Clone(metadata, &meta_clone);
  return EncodeMetadataAndType(node_type, fidl::MakeOptional(std::move(meta_clone)));
}

std::string EncodeFocus(const std::string& key, fuchsia::modular::FocusedStateState focused_state) {
  std::ostringstream str;
  str << key;
  if (focused_state == fuchsia::modular::FocusedStateState::FOCUSED) {
    str << "1";
  } else {
    str << "0";
  }
  return str.str();
}

std::set<std::string> EncodeMetadataAndType(fuchsia::modular::ContextValueType node_type,
                                            const fuchsia::modular::ContextMetadataPtr& metadata) {
  std::set<std::string> ret;

  if (metadata) {
    if (metadata->story) {
      if (metadata->story->id) {
        std::ostringstream str;
        str << kStoryIdKey << metadata->story->id;
        ret.insert(str.str());
      }
      if (metadata->story->focused) {
        ret.insert(EncodeFocus(kStoryFocusedKey, metadata->story->focused->state));
      }
    }

    if (metadata->mod) {
      if (metadata->mod->url) {
        std::ostringstream str;
        str << kModUrlKey << metadata->mod->url;
        ret.insert(str.str());
      }
      if (metadata->mod->path) {
        std::ostringstream str;
        str << kModPathKey;
        for (const auto& part : *metadata->mod->path) {
          str << '\0' << part;
        }
        ret.insert(str.str());
      }
      if (metadata->mod->focused) {
        ret.insert(EncodeFocus(kModuleFocusedKey, metadata->mod->focused->state));
      }
    }

    if (metadata->entity) {
      if (metadata->entity->topic) {
        std::ostringstream str;
        str << kEntityTopicKey << metadata->entity->topic;
        ret.insert(str.str());
      }
      if (metadata->entity->type) {
        for (const auto& type : *metadata->entity->type) {
          std::ostringstream str;
          str << kEntityTypeKey << type;
          ret.insert(str.str());
        }
      }
    }
  }

  std::ostringstream str;
  str << kContextValueTypeKey << fidl::ToUnderlying(node_type);
  ret.insert(str.str());

  return ret;
}

}  // namespace internal

void ContextIndex::Add(Id id, fuchsia::modular::ContextValueType type,
                       const fuchsia::modular::ContextMetadata& metadata) {
  auto keys = internal::EncodeMetadataAndType(type, metadata);
  for (const auto& key : keys) {
    index_[key].insert(id);
  }
}

void ContextIndex::Remove(Id id, fuchsia::modular::ContextValueType type,
                          const fuchsia::modular::ContextMetadata& metadata) {
  auto keys = internal::EncodeMetadataAndType(type, metadata);
  for (const auto& key : keys) {
    index_[key].erase(id);
  }
}

void ContextIndex::Query(fuchsia::modular::ContextValueType type,
                         const fuchsia::modular::ContextMetadataPtr& metadata,
                         std::set<ContextIndex::Id>* out) {
  FXL_DCHECK(out != nullptr);

  auto keys = internal::EncodeMetadataAndType(type, metadata);
  std::set<ContextIndex::Id> ret;
  if (keys.empty())
    return;
  const auto& first = index_[*keys.begin()];
  ret.insert(first.begin(), first.end());
  keys.erase(keys.begin());

  for (const auto& key : keys) {
    std::set<ContextIndex::Id> intersection;
    const auto& posting_list = index_[key];
    std::set_intersection(ret.begin(), ret.end(), posting_list.begin(), posting_list.end(),
                          std::inserter(intersection, intersection.begin()));
    ret.swap(intersection);
  }

  out->insert(ret.begin(), ret.end());
}

}  // namespace modular
