// Copyright 2016 The Weave 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 "src/access_black_list_manager_impl.h"

#include <base/json/json_reader.h>
#include <base/json/json_writer.h>
#include <base/values.h>

#include "src/commands/schema_constants.h"
#include "src/data_encoding.h"

namespace weave {

namespace {
const char kConfigFileName[] = "black_list";

const char kUser[] = "user";
const char kApp[] = "app";
const char kExpiration[] = "expiration";
}

AccessBlackListManagerImpl::AccessBlackListManagerImpl(
    provider::ConfigStore* store,
    size_t capacity,
    base::Clock* clock)
    : capacity_{capacity}, clock_{clock}, store_{store} {
  Load();
}

void AccessBlackListManagerImpl::Load() {
  if (!store_)
    return;
  if (auto list = base::ListValue::From(
          base::JSONReader::Read(store_->LoadSettings(kConfigFileName)))) {
    for (const auto& e : *list) {
      const base::DictionaryValue* entry{nullptr};
      std::string user;
      std::string app;
      decltype(entries_)::key_type key;
      int expiration;
      if (e->GetAsDictionary(&entry) && entry->GetString(kUser, &user) &&
          Base64Decode(user, &key.first) && entry->GetString(kApp, &app) &&
          Base64Decode(app, &key.second) &&
          entry->GetInteger(kExpiration, &expiration)) {
        base::Time expiration_time = base::Time::FromTimeT(expiration);
        if (expiration_time > clock_->Now())
          entries_[key] = expiration_time;
      }
    }
    if (entries_.size() < list->GetSize()) {
      // Save some storage space by saving without expired entries.
      Save({});
    }
  }
}

void AccessBlackListManagerImpl::Save(const DoneCallback& callback) {
  if (!store_) {
    if (!callback.is_null())
      callback.Run(nullptr);
    return;
  }

  base::ListValue list;
  for (const auto& e : entries_) {
    scoped_ptr<base::DictionaryValue> entry{new base::DictionaryValue};
    entry->SetString(kUser, Base64Encode(e.first.first));
    entry->SetString(kApp, Base64Encode(e.first.second));
    entry->SetInteger(kExpiration, e.second.ToTimeT());
    list.Append(std::move(entry));
  }

  std::string json;
  base::JSONWriter::Write(list, &json);
  store_->SaveSettings(kConfigFileName, json, callback);
}

void AccessBlackListManagerImpl::RemoveExpired() {
  for (auto i = begin(entries_); i != end(entries_);) {
    if (i->second <= clock_->Now())
      i = entries_.erase(i);
    else
      ++i;
  }
}

void AccessBlackListManagerImpl::AddEntryAddedCallback(
    const base::Closure& callback) {
  on_entry_added_callbacks_.push_back(callback);
}

void AccessBlackListManagerImpl::Block(const std::vector<uint8_t>& user_id,
                                       const std::vector<uint8_t>& app_id,
                                       const base::Time& expiration,
                                       const DoneCallback& callback) {
  // Iterating is OK as Save below is more expensive.
  RemoveExpired();
  if (expiration <= clock_->Now()) {
    if (!callback.is_null()) {
      ErrorPtr error;
      Error::AddTo(&error, FROM_HERE, "aleady_expired",
                   "Entry already expired");
      callback.Run(std::move(error));
    }
    return;
  }
  if (entries_.size() >= capacity_) {
    if (!callback.is_null()) {
      ErrorPtr error;
      Error::AddTo(&error, FROM_HERE, "blacklist_is_full",
                   "Unable to store more entries");
      callback.Run(std::move(error));
    }
    return;
  }

  auto& value = entries_[std::make_pair(user_id, app_id)];
  value = std::max(value, expiration);
  for (const auto& cb : on_entry_added_callbacks_)
    cb.Run();

  Save(callback);
}

bool AccessBlackListManagerImpl::IsBlocked(
    const std::vector<uint8_t>& user_id,
    const std::vector<uint8_t>& app_id) const {
  for (const auto& user : {{}, user_id}) {
    for (const auto& app : {{}, app_id}) {
      auto both = entries_.find(std::make_pair(user, app));
      if (both != end(entries_) && both->second > clock_->Now())
        return true;
    }
  }
  return false;
}

std::vector<AccessBlackListManager::Entry>
AccessBlackListManagerImpl::GetEntries() const {
  std::vector<Entry> result;
  for (const auto& e : entries_)
    result.push_back({e.first.first, e.first.second, e.second});
  return result;
}

size_t AccessBlackListManagerImpl::GetSize() const {
  return entries_.size();
}

size_t AccessBlackListManagerImpl::GetCapacity() const {
  return capacity_;
}

}  // namespace weave
