/*
 * 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.
 */
#include "fw_dunit.hpp"
#include "ThinClientHelper.hpp"

using apache::geode::client::NoAvailableLocatorsException;

bool isLocalServer = false;
bool isLocator = false;

const std::string locatorsG =
    CacheHelper::getLocatorHostPort(isLocator, isLocalServer, 3);
#define CLIENT1 s1p1
#define CLIENT2 s1p2
#define LOCATORS s2p1
#define SERVERS s2p2
DUNIT_TASK(LOCATORS, CreateLocator_All)
  {
    if (isLocalServer) {
      CacheHelper::initLocator(1);
      CacheHelper::initLocator(2);
      CacheHelper::initLocator(3);
    }
  }
END_TASK(CreateLocator_All)

DUNIT_TASK(SERVERS, CreateServer1_All)
  {
    // starting servers
    if (isLocalServer) CacheHelper::initServer(1, {}, locatorsG);
    LOG("Server One started");
  }
END_TASK(CreateServer1_All)

DUNIT_TASK(CLIENT1, SetupClient1_All)
  {
    // starting client 1
    initClient(true);
    createPooledRegion(regionNames[0], USE_ACK, locatorsG, "Pool1");
    LOG("SetupClient1 complete.");
  }
END_TASK(SetupClient1_All)

DUNIT_TASK(CLIENT2, SetupClient2_All)
  {
    // starting client 2
    initClient(true);
    createPooledRegion(regionNames[0], USE_ACK, locatorsG, "Pool2");
    LOG("SetupClient2 complete.");
  }
END_TASK(SetupClient2_All)

DUNIT_TASK(CLIENT1, ConnectC1_All)
  {
    createEntry(regionNames[0], keys[0], vals[0]);
    LOG("ConnectC1 complete.");
  }
END_TASK(ConnectC1_All)

DUNIT_TASK(CLIENT2, ConnectC2_All)
  {
    doNetsearch(regionNames[0], keys[0], vals[0]);
    createEntry(regionNames[0], keys[1], vals[1]);
    LOG("ConnectC2 complete.");
  }
END_TASK(ConnectC2_All)

DUNIT_TASK(SERVERS, CreateServer2_All)
  {
    if (isLocalServer) {
      CacheHelper::initServer(2, {}, locatorsG);
      LOG("Server 2 started");
    }
  }
END_TASK(CreateServer2_All)

DUNIT_TASK(LOCATORS, CloseLocators)
  {
    if (isLocator) {
      CacheHelper::closeLocator(1);
      CacheHelper::closeLocator(2);
    }
  }
END_TASK(CloseLocators)

DUNIT_TASK(SERVERS, CloseServer1_All)
  {
    if (isLocalServer) {
      CacheHelper::closeServer(1);
      LOG("SERVER1 stopped");
    }
  }
END_TASK(CloseServer1_All)

DUNIT_TASK(CLIENT1, FailoverC1_All)
  {
    doNetsearch(regionNames[0], keys[1], vals[1]);
    updateEntry(regionNames[0], keys[0], nvals[0]);
    LOG("FailoverC1_All complete.");
  }
END_TASK(FailoverC1_All)

DUNIT_TASK(CLIENT2, FailoverC2_All)
  {
    invalidateEntry(regionNames[0], keys[0]);
    doNetsearch(regionNames[0], keys[0], nvals[0], false);
    updateEntry(regionNames[0], keys[1], nvals[1]);
    LOG("FailoverC2_All complete.");
  }
END_TASK(FailoverC2_All)

DUNIT_TASK(LOCATORS, SwapLocators)
  {
    if (isLocator) {
      CacheHelper::initLocator(2);
      CacheHelper::closeLocator(3);
    }
  }
END_TASK(SwapLocators)

DUNIT_TASK(SERVERS, Re_CreateServer1_All)
  {
    if (isLocalServer) {
      CacheHelper::initServer(1, {}, locatorsG);
      LOG("Server 1 started");
      SLEEP(30000);
    }
  }
END_TASK(Re_CreateServer1_All)

DUNIT_TASK(SERVERS, CloseServer2_All)
  {
    if (isLocalServer) {
      CacheHelper::closeServer(2);
      LOG("SERVER2 stopped");
      SLEEP(30000);
    }
  }
END_TASK(CloseServer2_All)

DUNIT_TASK(CLIENT1, AgainFailoverC1_All)
  {
    SLEEP(30000);
    invalidateEntry(regionNames[0], keys[1]);
    doNetsearch(regionNames[0], keys[1], nvals[1], false);
    updateEntry(regionNames[0], keys[0], vals[0]);
  }
END_TASK(AgainFailoverC1_All)

DUNIT_TASK(LOCATORS, SwapLocators2)
  {
    if (isLocator) {
      CacheHelper::initLocator(3);
      CacheHelper::closeLocator(2);
    }
  }
END_TASK(SwapLocators2)

DUNIT_TASK(CLIENT2, AgainFailoverC2_All)
  {
    invalidateEntry(regionNames[0], keys[0]);
    doNetsearch(regionNames[0], keys[0], vals[0], false);
    updateEntry(regionNames[0], keys[1], vals[1]);
  }
END_TASK(AgainFailoverC2_All)

DUNIT_TASK(LOCATORS, CloseLocators)
  {
    if (isLocator) {
      CacheHelper::closeLocator(3);
    }
  }
END_TASK(CloseLocators)

DUNIT_TASK(SERVERS, Re_Close1_All_All)
  {
    if (isLocalServer) {
      CacheHelper::closeServer(1);
      LOG("Server 1 Stopped");
      SLEEP(30000);
    }
  }
END_TASK(Re_Close1_All_All)

DUNIT_TASK(SERVERS, StartServer2_All)
  {
    if (isLocalServer) {
      CacheHelper::initServer(2);
      LOG("SERVER2 Started");
      SLEEP(30000);
    }
  }
END_TASK(StartServer2_All)

DUNIT_TASK(CLIENT1, AgainAgainFailoverC1_All)
  {
    try {
      invalidateEntry(regionNames[0], keys[0]);
      doNetsearch(regionNames[0], keys[0], vals[0], false);
      updateEntry(regionNames[0], keys[1], vals[1]);
      FAIL(
          "No locator exception should "
          "have been raised");
    } catch (const NoAvailableLocatorsException &) {
      LOG("Caught expected NoAvailableLocatorsException.");
    } catch (...) {
      FAIL(
          "NotConnectedException "
          "with cause "
          "NoAvailableLocatorsExcepti"
          "on should have been "
          "raised");
    }
  }
END_TASK(AgainAgainFailoverC1_All)

DUNIT_TASK(CLIENT1, CloseCache1_All)
  { cleanProc(); }
END_TASK(CloseCache1_All)

DUNIT_TASK(CLIENT2, CloseCache2_All)
  { cleanProc(); }
END_TASK(CloseCache2_All)

DUNIT_TASK(SERVERS, CloseServer2_All_AgaIN)
  {
    if (isLocalServer) {
      CacheHelper::closeServer(2);
      LOG("SERVER2 stopped");
    }
  }
END_TASK(CloseServer2_All_AgaIN)
