/*
 * 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_THINCLIENTREDUNDANCYMANAGER_H_
#define GEODE_THINCLIENTREDUNDANCYMANAGER_H_

#include <atomic>
#include <chrono>
#include <list>
#include <memory>
#include <mutex>
#include <set>
#include <string>

#include "ErrType.hpp"
#include "EventIdMap.hpp"
#include "ExpiryTaskManager.hpp"
#include "ServerLocation.hpp"
#include "Task.hpp"
#include "TcrMessage.hpp"
#include "util/concurrent/binary_semaphore.hpp"
#include "util/synchronized_map.hpp"

namespace apache {
namespace geode {
namespace client {

class TcrConnectionManager;
class TcrHADistributionManager;
class ThinClientRegion;
class ThinClientPoolHADM;
class TcrEndpoint;

class ThinClientRedundancyManager {
 public:
  bool m_globalProcessedMarker;

  GfErrType maintainRedundancyLevel(bool init = false,
                                    const TcrMessage* request = nullptr,
                                    TcrMessageReply* reply = nullptr,
                                    ThinClientRegion* region = nullptr);
  void initialize(int redundancyLevel);
  void close();
  void sendNotificationCloseMsgs();

  explicit ThinClientRedundancyManager(TcrConnectionManager* theConnManager,
                                       int redundencyLevel = 0,
                                       ThinClientPoolHADM* poolHADM = nullptr,
                                       bool sentReadyForEvents = false,
                                       bool globalProcessedMarker = false);
  GfErrType sendSyncRequestRegisterInterest(TcrMessage& request,
                                            TcrMessageReply& reply,
                                            bool attemptFailover,
                                            TcrEndpoint* endpoint,
                                            ThinClientBaseDM* theHADM,
                                            ThinClientRegion* region = nullptr);

  GfErrType sendSyncRequestCq(TcrMessage& request, TcrMessageReply& reply,
                              ThinClientBaseDM* theHADM);
  void readyForEvents();
  void startPeriodicAck();
  bool checkDupAndAdd(std::shared_ptr<EventId> eventid);
  void netDown();
  void acquireRedundancyLock() { m_redundantEndpointsLock.lock(); }
  void releaseRedundancyLock() { m_redundantEndpointsLock.unlock(); }
  bool allEndPointDiscon() { return m_allEndpointsDisconnected; }
  void removeCallbackConnection(TcrEndpoint*);

  std::recursive_mutex& getRedundancyLock() { return m_redundantEndpointsLock; }

  GfErrType sendRequestToPrimary(TcrMessage& request, TcrMessageReply& reply);
  bool isSentReadyForEvents() const { return m_sentReadyForEvents; }

 private:
  using clock = std::chrono::steady_clock;
  using time_point = clock::time_point;

  // for selectServers
  volatile bool m_allEndpointsDisconnected;
  std::size_t m_server;
  bool m_sentReadyForEvents;
  int m_redundancyLevel;
  bool m_loggedRedundancyWarning;
  ThinClientPoolHADM* m_poolHADM;
  std::vector<TcrEndpoint*> m_redundantEndpoints;
  std::vector<TcrEndpoint*> m_nonredundantEndpoints;
  std::recursive_mutex m_redundantEndpointsLock;
  TcrConnectionManager* m_theTcrConnManager;
  std::shared_ptr<CacheableStringArray> m_locators;
  std::shared_ptr<CacheableStringArray> m_servers;

  void removeEndpointsInOrder(std::vector<TcrEndpoint*>& destVector,
                              const std::vector<TcrEndpoint*>& srcVector);
  void addEndpointsInOrder(std::vector<TcrEndpoint*>& destVector,
                           const std::vector<TcrEndpoint*>& srcVector);
  GfErrType makePrimary(TcrEndpoint* ep, const TcrMessage* request,
                        TcrMessageReply* reply);
  GfErrType makeSecondary(TcrEndpoint* ep, const TcrMessage* request,
                          TcrMessageReply* reply);
  bool sendMakePrimaryMesg(TcrEndpoint* ep, const TcrMessage* request,
                           ThinClientRegion* region);
  bool readyForEvents(TcrEndpoint* primaryCandidate);
  void moveEndpointToLast(std::vector<TcrEndpoint*>& epVector,
                          TcrEndpoint* targetEp);

  synchronized_map<
      std::unordered_map<std::string, std::shared_ptr<TcrEndpoint>>,
      std::recursive_mutex>&
  updateAndSelectEndpoints();

  void getAllEndpoints(std::vector<TcrEndpoint*>& endpoints);
  // For 38196 Fix: Reorder End points.
  void insertEPInQueueSizeOrder(TcrEndpoint* ep,
                                std::vector<TcrEndpoint*>& endpoints);

  GfErrType createQueueEP(TcrEndpoint* ep, const TcrMessage* request,
                          TcrMessageReply* reply, bool isPrimary);
  GfErrType createPoolQueueEP(TcrEndpoint* ep, const TcrMessage* request,
                              TcrMessageReply* reply, bool isPrimary);

  inline bool isDurable();

  std::unique_ptr<Task<ThinClientRedundancyManager>> m_periodicAckTask;
  binary_semaphore periodic_ack_semaphore_;
  ExpiryTask::id_t process_event_id_map_task_id_{ExpiryTask::invalid()};

  void periodicAck(std::atomic<bool>& isRunning);
  void doPeriodicAck();
  time_point m_nextAck;                     // next ack time
  std::chrono::milliseconds next_ack_inc_;  // next ack time increment
  volatile bool m_HAenabled;
  EventIdMap m_eventidmap;

  std::list<ServerLocation> selectServers(int howMany,
                                          std::set<ServerLocation> exclEndPts);

  friend class TcrConnectionManager;
  static const char* NC_PerodicACK;
};
}  // namespace client
}  // namespace geode
}  // namespace apache

#endif  // GEODE_THINCLIENTREDUNDANCYMANAGER_H_
