/*
 * 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.
 */
package org.apache.geode.modules.session.catalina;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpSession;

import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.InterestResultPolicy;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientRegionFactory;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.apache.geode.cache.client.PoolManager;
import org.apache.geode.cache.client.internal.PoolImpl;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.FunctionService;
import org.apache.geode.cache.execute.ResultCollector;
import org.apache.geode.modules.session.catalina.callback.SessionExpirationCacheListener;
import org.apache.geode.modules.util.BootstrappingFunction;
import org.apache.geode.modules.util.CreateRegionFunction;
import org.apache.geode.modules.util.RegionConfiguration;
import org.apache.geode.modules.util.RegionStatus;
import org.apache.geode.modules.util.SessionCustomExpiry;
import org.apache.geode.modules.util.TouchPartitionedRegionEntriesFunction;
import org.apache.geode.modules.util.TouchReplicatedRegionEntriesFunction;

public class ClientServerSessionCache extends AbstractSessionCache {

  private ClientCache cache;

  protected static final String DEFAULT_REGION_ATTRIBUTES_ID =
      RegionShortcut.PARTITION_REDUNDANT.toString();

  protected static final boolean DEFAULT_ENABLE_LOCAL_CACHE = true;

  public ClientServerSessionCache(SessionManager sessionManager, ClientCache cache) {
    super(sessionManager);
    this.cache = cache;
  }

  @Override
  public void initialize() {
    // Bootstrap the servers
    bootstrapServers();

    // Create or retrieve the region
    try {
      createOrRetrieveRegion();
    } catch (Exception ex) {
      sessionManager.getLogger().fatal("Unable to create or retrieve region", ex);
      throw new IllegalStateException(ex);
    }

    // Set the session region directly as the operating region since there is no difference
    // between the local cache region and the session region.
    this.operatingRegion = this.sessionRegion;

    // Create or retrieve the statistics
    createStatistics();
  }

  @Override
  public String getDefaultRegionAttributesId() {
    return DEFAULT_REGION_ATTRIBUTES_ID;
  }

  @Override
  public boolean getDefaultEnableLocalCache() {
    return DEFAULT_ENABLE_LOCAL_CACHE;
  }

  @Override
  public void touchSessions(Set<String> sessionIds) {
    // Get the region attributes id to determine the region type. This is
    // problematic since the region attributes id doesn't really define the
    // region type. Currently there is no way to know the type of region created
    // on the server. Maybe the CreateRegionFunction should return it.
    String regionAttributesID = getSessionManager().getRegionAttributesId().toLowerCase();

    // Invoke the appropriate function depending on the type of region
    if (regionAttributesID.startsWith("partition")) {
      // Execute the partitioned touch function on the primary server(s)
      Execution execution = FunctionService.onRegion(getSessionRegion()).withFilter(sessionIds);
      try {
        ResultCollector collector = execution.execute(TouchPartitionedRegionEntriesFunction.ID);
        collector.getResult();
      } catch (Exception e) {
        // If an exception occurs in the function, log it.
        getSessionManager().getLogger().warn("Caught unexpected exception:", e);
      }
    } else {
      // Execute the member touch function on all the server(s)
      Execution execution = FunctionService.onServers(getCache())
          .setArguments(new Object[] {this.sessionRegion.getFullPath(), sessionIds});
      try {
        ResultCollector collector = execution.execute(TouchReplicatedRegionEntriesFunction.ID);
        collector.getResult();
      } catch (Exception e) {
        // If an exception occurs in the function, log it.
        getSessionManager().getLogger().warn("Caught unexpected exception:", e);
      }
    }
  }

  @Override
  public boolean isPeerToPeer() {
    return false;
  }

  @Override
  public boolean isClientServer() {
    return true;
  }

  @Override
  public Set<String> keySet() {
    return getSessionRegion().keySetOnServer();
  }

  @Override
  public int size() {
    return getSessionRegion().sizeOnServer();
  }

  @Override
  public boolean isBackingCacheAvailable() {
    if (getSessionManager().isCommitValveFailfastEnabled()) {
      PoolImpl pool = (PoolImpl) PoolManager.find(getOperatingRegionName());
      return pool.isPrimaryUpdaterAlive();
    }
    return true;
  }

  @Override
  public GemFireCache getCache() {
    return this.cache;
  }

  private void bootstrapServers() {
    Execution execution = FunctionService.onServers(this.cache);
    ResultCollector collector = execution.execute(new BootstrappingFunction());
    // Get the result. Nothing is being done with it.
    try {
      collector.getResult();
    } catch (Exception e) {
      // If an exception occurs in the function, log it.
      getSessionManager().getLogger().warn("Caught unexpected exception:", e);
    }
  }

  protected void createOrRetrieveRegion() {
    // Retrieve the local session region
    this.sessionRegion = this.cache.getRegion(getSessionManager().getRegionName());

    // If necessary, create the regions on the server and client
    if (this.sessionRegion == null) {
      // Create the PR on the servers
      createSessionRegionOnServers();

      // Create the region on the client
      this.sessionRegion = createLocalSessionRegion();
      if (getSessionManager().getLogger().isDebugEnabled()) {
        getSessionManager().getLogger().debug("Created session region: " + this.sessionRegion);
      }
    } else {
      if (getSessionManager().getLogger().isDebugEnabled()) {
        getSessionManager().getLogger().debug("Retrieved session region: " + this.sessionRegion);
      }

      // Check that we have our expiration listener attached
      if (!regionHasExpirationListenerAttached(sessionRegion)) {
        sessionRegion.getAttributesMutator().addCacheListener(new SessionExpirationCacheListener());
      }

      // This is true for PROXY regions
      if (sessionRegion.getAttributes().getDataPolicy() == DataPolicy.EMPTY) {
        sessionRegion.registerInterest("ALL_KEYS", InterestResultPolicy.KEYS);
      }
    }
  }

  private boolean regionHasExpirationListenerAttached(Region<?, ?> region) {
    return Arrays.stream(region.getAttributes().getCacheListeners())
        .anyMatch(x -> x instanceof SessionExpirationCacheListener);
  }

  private void createSessionRegionOnServers() {
    // Create the RegionConfiguration
    RegionConfiguration configuration = createRegionConfiguration();

    // Send it to the server tier
    Execution execution = FunctionService.onServer(this.cache).setArguments(configuration);
    ResultCollector collector = execution.execute(CreateRegionFunction.ID);

    // Verify the region was successfully created on the servers
    List<RegionStatus> results = (List<RegionStatus>) collector.getResult();
    for (RegionStatus status : results) {
      if (status == RegionStatus.INVALID) {
        StringBuilder builder = new StringBuilder();
        builder
            .append(
                "An exception occurred on the server while attempting to create or validate region named ")
            .append(getSessionManager().getRegionName())
            .append(". See the server log for additional details.");
        throw new IllegalStateException(builder.toString());
      }
    }
  }

  private Region<String, HttpSession> createLocalSessionRegion() {
    ClientRegionFactory<String, HttpSession> factory = null;
    if (getSessionManager().getEnableLocalCache()) {
      // Create the region factory with caching and heap LRU enabled
      factory = this.cache.createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY_HEAP_LRU);

      // Set the expiration time, action and listener if necessary
      int maxInactiveInterval = getSessionManager().getMaxInactiveInterval();
      if (maxInactiveInterval != RegionConfiguration.DEFAULT_MAX_INACTIVE_INTERVAL) {
        factory.setStatisticsEnabled(true);
        factory.setCustomEntryIdleTimeout(new SessionCustomExpiry());
        factory.addCacheListener(new SessionExpirationCacheListener());
      }
    } else {
      // Create the region factory without caching enabled
      factory = this.cache.createClientRegionFactory(ClientRegionShortcut.PROXY);
      factory.addCacheListener(new SessionExpirationCacheListener());
    }

    // Create the region
    Region region = factory.create(getSessionManager().getRegionName());

    /*
     * If we're using an empty client region, we register interest so that expired sessions are
     * destroyed correctly.
     */
    if (!getSessionManager().getEnableLocalCache()) {
      region.registerInterest("ALL_KEYS", InterestResultPolicy.KEYS);
    }

    return region;
  }
}
