/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#ifndef GEODE_MAPENTRY_H_
#define GEODE_MAPENTRY_H_

#include <atomic>
#include <memory>
#include <utility>

#include <geode/CacheableKey.hpp>
#include <geode/ExceptionTypes.hpp>
#include <geode/Serializable.hpp>
#include <geode/internal/geode_globals.hpp>

#include "CacheImpl.hpp"
#include "CacheableToken.hpp"
#include "ExpiryTaskManager.hpp"
#include "RegionInternal.hpp"
#include "VersionStamp.hpp"

namespace apache {
namespace geode {
namespace client {

class MapEntry;
class MapEntryImpl;
class LRUEntryProperties;
class CacheImpl;

/**
 * @brief This class encapsulates expiration specific properties for
 *   a MapEntry.
 */
class ExpEntryProperties {
 public:
  ~ExpEntryProperties() noexcept = default;

  typedef std::chrono::system_clock::time_point time_point;

  inline explicit ExpEntryProperties(ExpiryTaskManager* expiryTaskManager)
      : m_lastAccessTime(0),
        m_lastModifiedTime(0),
        m_expiryTaskId(-1),
        m_expiryTaskManager(expiryTaskManager) {
    // The reactor always gives +ve id while scheduling.
    // -1 will indicate that an expiry task has not been scheduled
    // for this entry. // TODO confirm
  }

  inline time_point getLastAccessTime() const {
    return time_point(std::chrono::system_clock::duration(m_lastAccessTime));
  }

  inline time_point getLastModifiedTime() const {
    return time_point(std::chrono::system_clock::duration(m_lastModifiedTime));
  }

  //  moved time initialization outside of constructor to avoid
  // the costly gettimeofday call in MapSegment spinlock
  inline void initStartTime() {
    time_point currentTime = std::chrono::system_clock::now();
    m_lastAccessTime = currentTime.time_since_epoch().count();
    m_lastModifiedTime = currentTime.time_since_epoch().count();
  }

  inline void updateLastAccessTime(time_point currTime) {
    m_lastAccessTime = currTime.time_since_epoch().count();
  }

  inline void updateLastModifiedTime(time_point currTime) {
    m_lastModifiedTime = currTime.time_since_epoch().count();
  }

  inline void setExpiryTaskId(ExpiryTaskManager::id_type id) {
    m_expiryTaskId = id;
  }

  inline ExpiryTaskManager::id_type getExpiryTaskId() const {
    return m_expiryTaskId;
  }

  inline void cancelExpiryTaskId(
      const std::shared_ptr<CacheableKey>& key) const {
    auto taskIdStr = std::to_string(m_expiryTaskId);
    LOGDEBUG("Cancelling expiration task for key [%s] with id [%s]",
             Utils::nullSafeToString(key).c_str(), taskIdStr.c_str());
    m_expiryTaskManager->cancelTask(m_expiryTaskId);
  }

 protected:
  // this constructor deliberately skips initializing any fields
  inline explicit ExpEntryProperties(bool)
      : m_lastAccessTime(0), m_lastModifiedTime(0) {}

 private:
  /** last access time in secs, 32bit.. */
  std::atomic<time_point::duration::rep> m_lastAccessTime;
  /** last modified time in secs, 32bit.. */
  std::atomic<time_point::duration::rep> m_lastModifiedTime;
  /** The expiry task id for this particular entry.. **/
  ExpiryTaskManager::id_type m_expiryTaskId;
  ExpiryTaskManager* m_expiryTaskManager;
};

/**
 * @brief Interface class for region mapped entry value.
 */
class MapEntry {
 public:
  virtual ~MapEntry() noexcept = default;

  virtual void getKey(std::shared_ptr<CacheableKey>& result) const = 0;
  virtual void getValue(std::shared_ptr<Cacheable>& result) const = 0;
  virtual void setValue(const std::shared_ptr<Cacheable>& value) = 0;
  virtual std::shared_ptr<MapEntryImpl> getImplPtr() = 0;

  virtual LRUEntryProperties& getLRUProperties() = 0;
  virtual ExpEntryProperties& getExpProperties() = 0;
  virtual VersionStamp& getVersionStamp() = 0;

  /**
   * Adds a tracker to this MapEntry for any updates.
   * Returns the current update sequence number of this entry.
   * Returns by reference any updated MapEntry to be rebound while an
   * unchanged return value implies this MapEntry should be continued with.
   * Note that the contract says that the return value should not be
   * touched if this MapEntry is to be continued with.
   *
   * The design of tracking is thus:
   * Each entry will have two fields, one indicating the current number of
   * operations tracking this entry, and second indicating the sequence
   * number for number of updates since tracking was started. The idea is
   * to start tracking an entry before going for a long remote operation
   * and check whether the update sequence has remained unchanged upon
   * return. If the entry has been updated in the interim period then
   * the current update is not applied. When the number of operations
   * tracking an entry goes down to zero, then the update sequence number
   * is also reset to zero.
   */
  virtual int addTracker(std::shared_ptr<MapEntry>& newEntry) = 0;

  /**
   * Removes a tracker for this MapEntry and returns a pair:
   *  1) the first element of the pair is a boolean that indicates whether
   *     or not the entry should be replaced with the underlying MapEntryImpl
   *     object in the map
   *  2) the second element is the updated number of trackers for this entry
   */
  virtual std::pair<bool, int> removeTracker() = 0;

  /**
   * Increment the number of updates to this entry.
   * Returns the current update sequence number of this entry.
   * Returns by reference any updated MapEntry to be rebound while an
   * unchanged return value implies this MapEntry should be continued with.
   * Note that the contract says that the return value should not be
   * touched if this MapEntry is to be continued with.
   */
  virtual int incrementUpdateCount(std::shared_ptr<MapEntry>& newEntry) = 0;

  /**
   * Get the current tracking number of this entry. A return value of zero
   * indicates that the entry is not being tracked.
   */
  virtual int getTrackingNumber() const = 0;

  /**
   * Get the current number of updates since tracking was started for
   * this entry.
   */
  virtual int getUpdateCount() const = 0;

  /**
   * Any cleanup required (e.g. removing from LRUList) for the entry.
   */
  virtual void cleanup(const CacheEventFlags eventFlags) = 0;

 protected:
  inline MapEntry() = default;

  inline explicit MapEntry(bool) {}
};

/**
 * @brief Hold region mapped entry value. subclass will hold lru flags.
 * Another holds expiration timestamps.
 */
class MapEntryImpl : public MapEntry,
                     public std::enable_shared_from_this<MapEntryImpl> {
 public:
  ~MapEntryImpl() noexcept override = default;
  MapEntryImpl(const MapEntryImpl&) = delete;
  MapEntryImpl& operator=(const MapEntryImpl&) = delete;

  inline void getKeyI(std::shared_ptr<CacheableKey>& result) const {
    result = m_key;
  }

  inline void getValueI(std::shared_ptr<Cacheable>& result) const {
    // If value is destroyed, then this returns nullptr
    if (CacheableToken::isDestroyed(m_value)) {
      result = nullptr;
    } else {
      result = m_value;
    }
  }

  inline void setValueI(const std::shared_ptr<Cacheable>& value) {
    m_value = value;
  }

  void getKey(std::shared_ptr<CacheableKey>& result) const override {
    getKeyI(result);
  }

  void getValue(std::shared_ptr<Cacheable>& result) const override {
    getValueI(result);
  }

  void setValue(const std::shared_ptr<Cacheable>& value) override {
    setValueI(value);
  }

  std::shared_ptr<MapEntryImpl> getImplPtr() override {
    return shared_from_this();
  }

  LRUEntryProperties& getLRUProperties() override {
    throw FatalInternalException(
        "MapEntry::getLRUProperties called for "
        "non-LRU MapEntry");
  }

  ExpEntryProperties& getExpProperties() override {
    throw FatalInternalException(
        "MapEntry::getExpProperties called for "
        "non-expiration MapEntry");
  }

  VersionStamp& getVersionStamp() override {
    throw FatalInternalException(
        "MapEntry::getVersionStamp called for "
        "non-versioned MapEntry");
  }

  void cleanup(const CacheEventFlags) override {}

 protected:
  inline explicit MapEntryImpl(bool) : MapEntry(true) {}

  inline explicit MapEntryImpl(const std::shared_ptr<CacheableKey>& key)
      : MapEntry(), m_key(key) {}

  std::shared_ptr<Cacheable> m_value;
  std::shared_ptr<CacheableKey> m_key;
};

class VersionedMapEntryImpl : public MapEntryImpl, public VersionStamp {
 public:
  ~VersionedMapEntryImpl() noexcept override = default;

  VersionedMapEntryImpl(const VersionedMapEntryImpl&) = delete;
  VersionedMapEntryImpl& operator=(const VersionedMapEntryImpl&) = delete;

  VersionStamp& getVersionStamp() override { return *this; }

 protected:
  inline explicit VersionedMapEntryImpl(bool) : MapEntryImpl(true) {}

  inline explicit VersionedMapEntryImpl(
      const std::shared_ptr<CacheableKey>& key)
      : MapEntryImpl(key) {}
};

class EntryFactory {
 public:
  explicit EntryFactory(const bool concurrencyChecksEnabled)
      : m_concurrencyChecksEnabled(concurrencyChecksEnabled) {}

  virtual ~EntryFactory() noexcept = default;

  virtual void newMapEntry(ExpiryTaskManager* expiryTaskManager,
                           const std::shared_ptr<CacheableKey>& key,
                           std::shared_ptr<MapEntryImpl>& result) const;

 protected:
  bool m_concurrencyChecksEnabled;
};

}  // namespace client
}  // namespace geode
}  // namespace apache

#endif  // GEODE_MAPENTRY_H_
