// Copyright (C) 2009 The Android Open Source Project
//
// Licensed 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 com.google.gerrit.httpd;

import static java.util.concurrent.TimeUnit.HOURS;

import com.google.gerrit.httpd.WebSessionManager.Key;
import com.google.gerrit.httpd.WebSessionManager.Val;
import com.google.gerrit.reviewdb.Account;
import com.google.gerrit.reviewdb.AccountExternalId;
import com.google.gerrit.server.AccessPath;
import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AuthResult;
import com.google.gerrit.server.cache.Cache;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.cache.EvictionPolicy;
import com.google.gerrit.server.config.AuthConfig;
import com.google.inject.Inject;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
import com.google.inject.servlet.RequestScoped;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@RequestScoped
public final class WebSession {
  private static final String ACCOUNT_COOKIE = "GerritAccount";

  static Module module() {
    return new CacheModule() {
      @Override
      protected void configure() {
        final String cacheName = WebSessionManager.CACHE_NAME;
        final TypeLiteral<Cache<Key, Val>> type =
            new TypeLiteral<Cache<Key, Val>>() {};
        disk(type, cacheName) //
            .memoryLimit(1024) // reasonable default for many sites
            .maxAge(12, HOURS) // expire sessions if they are inactive
            .evictionPolicy(EvictionPolicy.LRU) // keep most recently used
        ;
        bind(WebSessionManager.class);
        bind(WebSession.class).in(RequestScoped.class);
      }
    };
  }

  private final HttpServletRequest request;
  private final HttpServletResponse response;
  private final WebSessionManager manager;
  private final AuthConfig authConfig;
  private final AnonymousUser anonymous;
  private final IdentifiedUser.RequestFactory identified;
  private AccessPath accessPath = AccessPath.WEB_UI;
  private Cookie outCookie;

  private Key key;
  private Val val;

  @Inject
  WebSession(final HttpServletRequest request,
      final HttpServletResponse response, final WebSessionManager manager,
      final AuthConfig authConfig, final AnonymousUser anonymous,
      final IdentifiedUser.RequestFactory identified) {
    this.request = request;
    this.response = response;
    this.manager = manager;
    this.authConfig = authConfig;
    this.anonymous = anonymous;
    this.identified = identified;

    final String cookie = readCookie();
    if (cookie != null) {
      key = new Key(cookie);
      val = manager.get(key);
    } else {
      key = null;
      val = null;
    }

    if (isSignedIn() && val.needsCookieRefresh()) {
      // Cookie is more than half old. Send the cookie again to the
      // client with an updated expiration date. We don't dare to
      // change the key token here because there may be other RPCs
      // queued up in the browser whose xsrfKey would not get updated
      // with the new token, causing them to fail.
      //
      val = manager.createVal(key, val);
      saveCookie();
    }
  }

  private String readCookie() {
    final Cookie[] all = request.getCookies();
    if (all != null) {
      for (final Cookie c : all) {
        if (ACCOUNT_COOKIE.equals(c.getName())) {
          final String v = c.getValue();
          return v != null && !"".equals(v) ? v : null;
        }
      }
    }
    return null;
  }

  public boolean isSignedIn() {
    return val != null;
  }

  String getToken() {
    return isSignedIn() ? key.getToken() : null;
  }

  public boolean isTokenValid(final String inputToken) {
    return isSignedIn() && key.getToken().equals(inputToken);
  }

  public AccountExternalId.Key getLastLoginExternalId() {
    return val != null ? val.getExternalId() : null;
  }

  CurrentUser getCurrentUser() {
    if (isSignedIn()) {
      return identified.create(accessPath, val.getAccountId());
    }
    return anonymous;
  }

  public void login(final AuthResult res, final boolean rememberMe) {
    final Account.Id id = res.getAccountId();
    final AccountExternalId.Key identity = res.getExternalId();

    logout();

    key = manager.createKey(id);
    val = manager.createVal(key, id, rememberMe, identity);
    saveCookie();
  }

  /** Change the access path from the default of {@link AccessPath#WEB_UI}. */
  void setAccessPath(AccessPath path) {
    accessPath = path;
  }

  /** Set the user account for this current request only. */
  void setUserAccountId(Account.Id id) {
    key = new Key("id:" + id);
    val = new Val(id, 0, false, null);
  }

  public void logout() {
    if (val != null) {
      manager.destroy(key);
      key = null;
      val = null;
      saveCookie();
    }
  }

  private void saveCookie() {
    final String token;
    final int ageSeconds;

    if (key == null) {
      token = "";
      ageSeconds = 0 /* erase at client */;
    } else {
      token = key.getToken();
      ageSeconds = manager.getCookieAge(val);
    }

    if (outCookie == null) {
      String path = authConfig.getCookiePath();
      if (path == null || path.isEmpty()) {
        path = request.getContextPath();
        if (path.isEmpty()) {
          path = "/";
        }
      }
      outCookie = new Cookie(ACCOUNT_COOKIE, token);
      outCookie.setPath(path);
      outCookie.setMaxAge(ageSeconds);
      outCookie.setSecure(authConfig.getCookieSecure());
      response.addCookie(outCookie);
    } else {
      outCookie.setValue(token);
      outCookie.setMaxAge(ageSeconds);
    }
  }
}
