/*
 * 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_PROXYREGION_H_
#define GEODE_PROXYREGION_H_

#include <algorithm>

#include <geode/AttributesMutator.hpp>
#include <geode/AuthenticatedView.hpp>
#include <geode/CacheListener.hpp>
#include <geode/CacheLoader.hpp>
#include <geode/CacheStatistics.hpp>
#include <geode/CacheWriter.hpp>
#include <geode/CacheableBuiltins.hpp>
#include <geode/CacheableKey.hpp>
#include <geode/CacheableString.hpp>
#include <geode/ExceptionTypes.hpp>
#include <geode/Query.hpp>
#include <geode/RegionAttributes.hpp>
#include <geode/RegionAttributesFactory.hpp>
#include <geode/RegionEntry.hpp>
#include <geode/internal/geode_globals.hpp>

#include "RegionInternal.hpp"
#include "UserAttributes.hpp"

namespace apache {
namespace geode {
namespace client {

class FunctionService;

/**
 * @class ProxyRegion ProxyRegion.hpp
 * This class wrapper around real region
 */
class APACHE_GEODE_EXPORT ProxyRegion final : public Region {
 public:
  const std::string& getName() const final { return m_realRegion->getName(); }

  const std::string& getFullPath() const final {
    return m_realRegion->getFullPath();
  }

  std::shared_ptr<Region> getParentRegion() const final {
    return m_realRegion->getParentRegion();
  }

  const RegionAttributes& getAttributes() const final {
    return m_realRegion->getAttributes();
  }

  std::shared_ptr<AttributesMutator> getAttributesMutator() const final {
    throw UnsupportedOperationException("Region.getAttributesMutator()");
  }

  std::shared_ptr<CacheStatistics> getStatistics() const final {
    return m_realRegion->getStatistics();
  }

  void invalidateRegion(const std::shared_ptr<Serializable>&) final {
    throw UnsupportedOperationException("Region.invalidateRegion()");
  }

  void localInvalidateRegion(const std::shared_ptr<Serializable>&) final {
    throw UnsupportedOperationException("Region.localInvalidateRegion()");
  }

  void destroyRegion(
      const std::shared_ptr<Serializable>& aCallbackArgument = nullptr) final {
    GuardUserAttributes gua(m_authenticatedView);
    m_realRegion->destroyRegion(aCallbackArgument);
  }

  void clear(
      const std::shared_ptr<Serializable>& aCallbackArgument = nullptr) final {
    GuardUserAttributes gua(m_authenticatedView);
    m_realRegion->clear(aCallbackArgument);
  }

  void localClear(const std::shared_ptr<Serializable>&) final {
    throw UnsupportedOperationException("localClear()");
  }

  void localDestroyRegion(const std::shared_ptr<Serializable>&) final {
    throw UnsupportedOperationException("Region.localDestroyRegion()");
  }

  std::shared_ptr<Region> getSubregion(const std::string& path) final {
    LOGDEBUG("ProxyRegion getSubregion");
    auto rPtr = std::static_pointer_cast<RegionInternal>(
        m_realRegion->getSubregion(path));

    if (rPtr == nullptr) {
      return std::move(rPtr);
    }

    return std::make_shared<ProxyRegion>(*m_authenticatedView, rPtr);
  }

  std::shared_ptr<Region> createSubregion(const std::string&,
                                          RegionAttributes) final {
    throw UnsupportedOperationException("createSubregion()");
  }

  std::vector<std::shared_ptr<Region>> subregions(const bool recursive) final {
    std::vector<std::shared_ptr<Region>> realVectorRegion =
        m_realRegion->subregions(recursive);
    std::vector<std::shared_ptr<Region>> proxyRegions(realVectorRegion.size());

    std::transform(realVectorRegion.begin(), realVectorRegion.end(),
                   std::back_inserter(proxyRegions),
                   [this](const std::shared_ptr<Region>& realRegion)
                       -> std::shared_ptr<ProxyRegion> {
                     return std::make_shared<ProxyRegion>(
                         *m_authenticatedView,
                         std::static_pointer_cast<RegionInternal>(realRegion));
                   });

    return proxyRegions;
  }

  std::shared_ptr<RegionEntry> getEntry(
      const std::shared_ptr<CacheableKey>& key) final {
    return m_realRegion->getEntry(key);
  }

  /** Convenience method allowing key to be a const char* */
  template <class KEYTYPE>
  inline std::shared_ptr<RegionEntry> getEntry(const KEYTYPE& key) {
    return getEntry(CacheableKey::create(key));
  }

  std::shared_ptr<Cacheable> get(
      const std::shared_ptr<CacheableKey>& key,
      const std::shared_ptr<Serializable>& aCallbackArgument = nullptr) final {
    GuardUserAttributes gua(m_authenticatedView);
    return m_realRegion->get(key, aCallbackArgument);
  }

  /** Convenience method allowing key to be a const char* */
  template <class KEYTYPE>
  inline std::shared_ptr<Cacheable> get(
      const KEYTYPE& key,
      const std::shared_ptr<Serializable>& callbackArg = nullptr) {
    return get(CacheableKey::create(key), callbackArg);
  }

  void put(
      const std::shared_ptr<CacheableKey>& key,
      const std::shared_ptr<Cacheable>& value,
      const std::shared_ptr<Serializable>& aCallbackArgument = nullptr) final {
    GuardUserAttributes gua(m_authenticatedView);
    return m_realRegion->put(key, value, aCallbackArgument);
  }

  /** Convenience method allowing both key and value to be a const char* */
  template <class KEYTYPE, class VALUETYPE>
  inline void put(const KEYTYPE& key, const VALUETYPE& value,
                  const std::shared_ptr<Serializable>& arg = nullptr) {
    put(CacheableKey::create(key), Serializable::create(value), arg);
  }

  /** Convenience method allowing key to be a const char* */
  template <class KEYTYPE>
  inline void put(const KEYTYPE& key, const std::shared_ptr<Cacheable>& value,
                  const std::shared_ptr<Serializable>& arg = nullptr) {
    put(CacheableKey::create(key), value, arg);
  }

  /** Convenience method allowing value to be a const char* */
  template <class VALUETYPE>
  inline void put(const std::shared_ptr<CacheableKey>& key,
                  const VALUETYPE& value,
                  const std::shared_ptr<Serializable>& arg = nullptr) {
    put(key, Serializable::create(value), arg);
  }

  void putAll(
      const HashMapOfCacheable& map,
      std::chrono::milliseconds timeout = DEFAULT_RESPONSE_TIMEOUT,
      const std::shared_ptr<Serializable>& aCallbackArgument = nullptr) final {
    GuardUserAttributes gua(m_authenticatedView);
    return m_realRegion->putAll(map, timeout, aCallbackArgument);
  }

  void localPut(const std::shared_ptr<CacheableKey>&,
                const std::shared_ptr<Cacheable>&,
                const std::shared_ptr<Serializable>&) final {
    throw UnsupportedOperationException("Region.localPut()");
  }

  /** Convenience method allowing both key and value to be a const char* */
  template <class KEYTYPE, class VALUETYPE>
  inline void localPut(const KEYTYPE& key, const VALUETYPE& value,
                       const std::shared_ptr<Serializable>& arg = nullptr) {
    localPut(CacheableKey::create(key), Serializable::create(value), arg);
  }

  /** Convenience method allowing key to be a const char* */
  template <class KEYTYPE>
  inline void localPut(const KEYTYPE& key,
                       const std::shared_ptr<Cacheable>& value,
                       const std::shared_ptr<Serializable>& arg = nullptr) {
    localPut(CacheableKey::create(key), value, arg);
  }

  /** Convenience method allowing value to be a const char* */
  template <class VALUETYPE>
  inline void localPut(const std::shared_ptr<CacheableKey>& key,
                       const VALUETYPE& value,
                       const std::shared_ptr<Serializable>& arg = nullptr) {
    localPut(key, Serializable::create(value), arg);
  }

  void create(
      const std::shared_ptr<CacheableKey>& key,
      const std::shared_ptr<Cacheable>& value,
      const std::shared_ptr<Serializable>& aCallbackArgument = nullptr) final {
    GuardUserAttributes gua(m_authenticatedView);
    m_realRegion->create(key, value, aCallbackArgument);
  }

  /** Convenience method allowing both key and value to be a const char* */
  template <class KEYTYPE, class VALUETYPE>
  inline void create(const KEYTYPE& key, const VALUETYPE& value,
                     const std::shared_ptr<Serializable>& arg = nullptr) {
    create(CacheableKey::create(key), Serializable::create(value), arg);
  }

  /** Convenience method allowing key to be a const char* */
  template <class KEYTYPE>
  inline void create(const KEYTYPE& key,
                     const std::shared_ptr<Cacheable>& value,
                     const std::shared_ptr<Serializable>& arg = nullptr) {
    create(CacheableKey::create(key), value, arg);
  }

  /** Convenience method allowing value to be a const char* */
  template <class VALUETYPE>
  inline void create(const std::shared_ptr<CacheableKey>& key,
                     const VALUETYPE& value,
                     const std::shared_ptr<Serializable>& arg = nullptr) {
    create(key, Serializable::create(value), arg);
  }

  void localCreate(const std::shared_ptr<CacheableKey>&,
                   const std::shared_ptr<Cacheable>&,
                   const std::shared_ptr<Serializable>&) final {
    throw UnsupportedOperationException("Region.localCreate()");
  }

  /** Convenience method allowing both key and value to be a const char* */
  template <class KEYTYPE, class VALUETYPE>
  inline void localCreate(const KEYTYPE& key, const VALUETYPE& value,
                          const std::shared_ptr<Serializable>& arg = nullptr) {
    localCreate(CacheableKey::create(key), Serializable::create(value), arg);
  }

  /** Convenience method allowing key to be a const char* */
  template <class KEYTYPE>
  inline void localCreate(const KEYTYPE& key,
                          const std::shared_ptr<Cacheable>& value,
                          const std::shared_ptr<Serializable>& arg = nullptr) {
    localCreate(CacheableKey::create(key), value, arg);
  }

  /** Convenience method allowing value to be a const char* */
  template <class VALUETYPE>
  inline void localCreate(const std::shared_ptr<CacheableKey>& key,
                          const VALUETYPE& value,
                          const std::shared_ptr<Serializable>& arg = nullptr) {
    localCreate(key, Serializable::create(value), arg);
  }

  void invalidate(
      const std::shared_ptr<CacheableKey>& key,
      const std::shared_ptr<Serializable>& aCallbackArgument = nullptr) final {
    GuardUserAttributes gua(m_authenticatedView);
    m_realRegion->invalidate(key, aCallbackArgument);
  }

  /** Convenience method allowing key to be a const char* */
  template <class KEYTYPE>
  inline void invalidate(const KEYTYPE& key,
                         const std::shared_ptr<Serializable>& arg = nullptr) {
    invalidate(CacheableKey::create(key), arg);
  }

  void localInvalidate(const std::shared_ptr<CacheableKey>&,
                       const std::shared_ptr<Serializable>&) final {
    throw UnsupportedOperationException("Region.localInvalidate()");
  }

  /** Convenience method allowing key to be a const char* */
  template <class KEYTYPE>
  inline void localInvalidate(
      const KEYTYPE& key, const std::shared_ptr<Serializable>& arg = nullptr) {
    localInvalidate(CacheableKey::create(key), arg);
  }

  void destroy(
      const std::shared_ptr<CacheableKey>& key,
      const std::shared_ptr<Serializable>& aCallbackArgument = nullptr) final {
    GuardUserAttributes gua(m_authenticatedView);
    m_realRegion->destroy(key, aCallbackArgument);
  }

  /** Convenience method allowing key to be a const char* */
  template <class KEYTYPE>
  inline void destroy(const KEYTYPE& key,
                      const std::shared_ptr<Serializable>& arg = nullptr) {
    destroy(CacheableKey::create(key), arg);
  }

  void localDestroy(const std::shared_ptr<CacheableKey>&,
                    const std::shared_ptr<Serializable>&) final {
    throw UnsupportedOperationException("Region.localDestroy()");
  }

  /** Convenience method allowing key to be a const char* */
  template <class KEYTYPE>
  inline void localDestroy(const KEYTYPE& key,
                           const std::shared_ptr<Serializable>& arg = nullptr) {
    localDestroy(CacheableKey::create(key), arg);
  }

  bool remove(
      const std::shared_ptr<CacheableKey>& key,
      const std::shared_ptr<Cacheable>& value,
      const std::shared_ptr<Serializable>& aCallbackArgument = nullptr) final {
    GuardUserAttributes gua(m_authenticatedView);
    return m_realRegion->remove(key, value, aCallbackArgument);
  }

  /** Convenience method allowing both key and value to be a const char* */
  template <class KEYTYPE, class VALUETYPE>
  inline bool remove(const KEYTYPE& key, const VALUETYPE& value,
                     const std::shared_ptr<Serializable>& arg = nullptr) {
    return remove(CacheableKey::create(key), Serializable::create(value), arg);
  }

  /** Convenience method allowing key to be a const char* */
  template <class KEYTYPE>
  inline bool remove(const KEYTYPE& key,
                     const std::shared_ptr<Cacheable>& value,
                     const std::shared_ptr<Serializable>& arg = nullptr) {
    return remove(CacheableKey::create(key), value, arg);
  }

  /** Convenience method allowing value to be a const char* */
  template <class VALUETYPE>
  inline bool remove(const std::shared_ptr<CacheableKey>& key,
                     const VALUETYPE& value,
                     const std::shared_ptr<Serializable>& arg = nullptr) {
    return remove(key, Serializable::create(value), arg);
  }

  bool removeEx(
      const std::shared_ptr<CacheableKey>& key,
      const std::shared_ptr<Serializable>& aCallbackArgument = nullptr) final {
    GuardUserAttributes gua(m_authenticatedView);
    return m_realRegion->removeEx(key, aCallbackArgument);
  }

  /** Convenience method allowing key to be a const char* */
  template <class KEYTYPE>
  inline bool removeEx(const KEYTYPE& key,
                       const std::shared_ptr<Serializable>& arg = nullptr) {
    return removeEx(CacheableKey::create(key), arg);
  }

  bool localRemove(const std::shared_ptr<CacheableKey>&,
                   const std::shared_ptr<Cacheable>&,
                   const std::shared_ptr<Serializable>&) final {
    throw UnsupportedOperationException("Region.localRemove()");
  }

  /** Convenience method allowing both key and value to be a const char* */
  template <class KEYTYPE, class VALUETYPE>
  inline bool localRemove(const KEYTYPE& key, const VALUETYPE& value,
                          const std::shared_ptr<Serializable>& arg = nullptr) {
    return localRemove(CacheableKey::create(key), Serializable::create(value),
                       arg);
  }

  /** Convenience method allowing key to be a const char* */
  template <class KEYTYPE>
  inline bool localRemove(const KEYTYPE& key,
                          const std::shared_ptr<Cacheable>& value,
                          const std::shared_ptr<Serializable>& arg = nullptr) {
    return localRemove(CacheableKey::create(key), value, arg);
  }

  /** Convenience method allowing value to be a const char* */
  template <class VALUETYPE>
  inline bool localRemove(const std::shared_ptr<CacheableKey>& key,
                          const VALUETYPE& value,
                          const std::shared_ptr<Serializable>& arg = nullptr) {
    return localRemove(key, Serializable::create(value), arg);
  }

  bool localRemoveEx(const std::shared_ptr<CacheableKey>&,
                     const std::shared_ptr<Serializable>&) final {
    throw UnsupportedOperationException("Region.localRemoveEx()");
  }

  /** Convenience method allowing key to be a const char* */
  template <class KEYTYPE>
  inline bool localRemoveEx(
      const KEYTYPE& key, const std::shared_ptr<Serializable>& arg = nullptr) {
    return localRemoveEx(CacheableKey::create(key), arg);
  }

  /**
   * Return all the keys in the local process for this region. This includes
   * keys for which the entry is invalid.
   */
  std::vector<std::shared_ptr<CacheableKey>> keys() final {
    throw UnsupportedOperationException("Region.keys()");
  }

  std::vector<std::shared_ptr<CacheableKey>> serverKeys() final {
    GuardUserAttributes gua(m_authenticatedView);
    return m_realRegion->serverKeys();
  }

  std::vector<std::shared_ptr<Cacheable>> values() final {
    throw UnsupportedOperationException("Region.values()");
  }

  std::vector<std::shared_ptr<RegionEntry>> entries(bool) final {
    throw UnsupportedOperationException("Region.entries()");
  }

  RegionService& getRegionService() const final { return *m_authenticatedView; }

  bool isDestroyed() const final { return m_realRegion->isDestroyed(); }

  bool containsValueForKey(const std::shared_ptr<CacheableKey>&) const final {
    throw UnsupportedOperationException("Region.containsValueForKey()");
  }

  /**
   * Convenience method allowing key to be a const char*
   * This operations checks for the value in the local cache .
   * It is not propagated to the Geode cache server
   * to which it is connected.
   */
  template <class KEYTYPE>
  inline bool containsValueForKey(const KEYTYPE& key) const {
    return containsValueForKey(CacheableKey::create(key));
  }

  bool containsKey(const std::shared_ptr<CacheableKey>&) const final {
    throw UnsupportedOperationException("Region.containsKey()");
  }

  bool containsKeyOnServer(
      const std::shared_ptr<CacheableKey>& keyPtr) const final {
    GuardUserAttributes gua(m_authenticatedView);
    return m_realRegion->containsKeyOnServer(keyPtr);
  }

  std::vector<std::shared_ptr<CacheableKey>> getInterestList() const final {
    throw UnsupportedOperationException("Region.getInterestList()");
  }

  std::vector<std::shared_ptr<CacheableString>> getInterestListRegex()
      const final {
    throw UnsupportedOperationException("Region.getInterestListRegex()");
  }

  /**
   * Convenience method allowing key to be a const char*
   * This operations checks for the key in the local cache .
   * It is not propagated to the Geode cache server
   * to which it is connected.
   */
  template <class KEYTYPE>
  inline bool containsKey(const KEYTYPE& key) const {
    return containsKey(CacheableKey::create(key));
  }

  void registerKeys(const std::vector<std::shared_ptr<CacheableKey>>&, bool,
                    bool, bool) final {
    throw UnsupportedOperationException("Region.registerKeys()");
  }

  void unregisterKeys(const std::vector<std::shared_ptr<CacheableKey>>&) final {
    throw UnsupportedOperationException("Region.unregisterKeys()");
  }

  void registerAllKeys(bool, bool, bool) final {
    throw UnsupportedOperationException("Region.registerAllKeys()");
  }

  void unregisterAllKeys() final {
    throw UnsupportedOperationException("Region.unregisterAllKeys()");
  }

  void registerRegex(const std::string&, bool, bool, bool) final {
    throw UnsupportedOperationException("Region.registerRegex()");
  }

  void unregisterRegex(const std::string&) final {
    throw UnsupportedOperationException("Region.unregisterRegex()");
  }

  HashMapOfCacheable getAll(
      const std::vector<std::shared_ptr<CacheableKey>>& keys,
      const std::shared_ptr<Serializable>& aCallbackArgument = nullptr) final {
    GuardUserAttributes gua(m_authenticatedView);
    return m_realRegion->getAll_internal(keys, aCallbackArgument, false);
  }

  std::shared_ptr<SelectResults> query(
      const std::string& predicate, std::chrono::milliseconds timeout =
                                        DEFAULT_QUERY_RESPONSE_TIMEOUT) final {
    GuardUserAttributes gua(m_authenticatedView);
    return m_realRegion->query(predicate, timeout);
  }

  bool existsValue(const std::string& predicate,
                   std::chrono::milliseconds timeout =
                       DEFAULT_QUERY_RESPONSE_TIMEOUT) final {
    GuardUserAttributes gua(m_authenticatedView);
    return m_realRegion->existsValue(predicate, timeout);
  }

  std::shared_ptr<Serializable> selectValue(
      const std::string& predicate, std::chrono::milliseconds timeout =
                                        DEFAULT_QUERY_RESPONSE_TIMEOUT) final {
    GuardUserAttributes gua(m_authenticatedView);
    return m_realRegion->selectValue(predicate, timeout);
  }

  void removeAll(
      const std::vector<std::shared_ptr<CacheableKey>>& keys,
      const std::shared_ptr<Serializable>& aCallbackArgument = nullptr) final {
    GuardUserAttributes gua(m_authenticatedView);
    m_realRegion->removeAll(keys, aCallbackArgument);
  }

  uint32_t size() final { return m_realRegion->size(); }

  const std::shared_ptr<Pool>& getPool() const final {
    return m_realRegion->getPool();
  }

  ProxyRegion(AuthenticatedView& authenticatedView,
              const std::shared_ptr<RegionInternal>& realRegion)
      : Region(authenticatedView.m_cacheImpl) {
    m_authenticatedView = &authenticatedView;
    m_realRegion = realRegion;
  }

  ~ProxyRegion() final = default;

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

 private:
  AuthenticatedView* m_authenticatedView;
  std::shared_ptr<RegionInternal> m_realRegion;
  friend class FunctionService;
};

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

#endif  // GEODE_PROXYREGION_H_
