// Copyright 2011 Google Inc. All Rights Reserved.
//
// 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.enterprise.adaptor;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;

import org.json.simple.JSONObject;
import org.json.simple.JSONValue;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * JSON-RPC handler for communication with the dashboard.
 */
class RpcHandler implements HttpHandler {
  /** Key used to store the XSRF-prevention token in the session. */
  private static final String XSRF_TOKEN_ATTR_NAME = "rpc-xsrf-token";
  /** Cookie name used to provide the XSRF token to client. */
  public static final String XSRF_TOKEN_HEADER_NAME = "X-Adaptor-XSRF-Token";

  private static final Logger log
      = Logger.getLogger(RpcHandler.class.getName());

  private final Charset charset = Charset.forName("UTF-8");
  private final Map<String, RpcMethod> methods
      = new HashMap<String, RpcMethod>();
  private final SessionManager<HttpExchange> sessionManager;

  public RpcHandler(SessionManager<HttpExchange> sessionManager) {
    this.sessionManager = sessionManager;
  }

  /**
   * Register new RPC method.
   *
   * @throws IllegalStateException if method by that name already registered
   */
  public void registerRpcMethod(String name, RpcMethod method) {
    if (methods.containsKey(name)) {
      throw new IllegalStateException(
          "Method by that name already registered");
    }
    methods.put(name, method);
  }

  /**
   * Unregister a previously registered RPC method.
   *
   * @throws IllegalStateException if method by that name not previously
   *     registered
   */
  public void unregisterRpcMethod(String name) {
    if (!methods.containsKey(name)) {
      throw new IllegalStateException("No method by that name registered");
    }
    methods.remove(name);
  }

  @Override
  public void handle(HttpExchange ex) throws IOException {
    if (!"POST".equals(ex.getRequestMethod())) {
      HttpExchanges.cannedRespond(ex, HttpURLConnection.HTTP_BAD_METHOD,
          Translation.HTTP_BAD_METHOD);
      return;
    }
    if (!ex.getRequestURI().getPath().equals(ex.getHttpContext().getPath())) {
      HttpExchanges.cannedRespond(ex, HttpURLConnection.HTTP_NOT_FOUND,
          Translation.HTTP_NOT_FOUND);
      return;
    }
    // Make sure the session has a XSRF token.
    Session session = sessionManager.getSession(ex);
    String xsrfToken = (String) session.getAttribute(XSRF_TOKEN_ATTR_NAME);
    if (xsrfToken == null) {
      xsrfToken = sessionManager.generateRandomIdentifier();
      session.setAttribute(XSRF_TOKEN_ATTR_NAME, xsrfToken);
    }
    // Make sure the client provided the correct XSRF token.
    String providedXsrfToken
        = ex.getRequestHeaders().getFirst(XSRF_TOKEN_HEADER_NAME);
    if (!xsrfToken.equals(providedXsrfToken)) {
      ex.getResponseHeaders().set(XSRF_TOKEN_HEADER_NAME, xsrfToken);
      HttpExchanges.cannedRespond(ex, HttpURLConnection.HTTP_CONFLICT,
          Translation.HTTP_CONFLICT_INVALID_HEADER, XSRF_TOKEN_HEADER_NAME);
      return;
    }
    Object requestObj;
    {
      String request = IOHelper.readInputStreamToString(
          ex.getRequestBody(), charset);
      requestObj = JSONValue.parse(request);
    }
    if (requestObj == null) {
      HttpExchanges.cannedRespond(ex, HttpURLConnection.HTTP_BAD_REQUEST,
          Translation.HTTP_BAD_REQUEST_INVALID_JSON);
      return;
    }
    String method;
    List params;
    Object id;
    try {
      Map request = (Map) requestObj;
      method = (String) request.get("method");
      params = (List) request.get("params");
      id = request.get("id");
    } catch (ClassCastException e) {
      @SuppressWarnings("unchecked")
      Map<String, Object> response = new JSONObject();
      response.put("id", null);
      response.put("result", null);
      response.put("error", "Invalid request format: " + e.getMessage());
      HttpExchanges.respond(ex, HttpURLConnection.HTTP_OK, "application/json",
          JSONValue.toJSONString(response).getBytes(charset));
      return;
    }

    // You must set one and only one of result and error.
    Object result = null;
    Object error = null;
    try {
      RpcMethod methodObj = methods.get(method);
      if (methodObj != null) {
        result = methodObj.run(params);
        if (result == null) {
          error = "Null response from method";
        }
      } else {
        error = "Unknown method";
      }
    } catch (Exception e) {
      error = e.getMessage();
      if (error == null) {
        error = "Unknown exception";
        log.log(Level.WARNING, "Exception during RPC", e);
      } else {
        log.log(Level.FINE, "Exception during RPC", e);
      }
    }
    @SuppressWarnings("unchecked")
    Map<String, Object> response = new JSONObject();
    response.put("id", id);
    response.put("result", result);
    response.put("error", error);
    HttpExchanges.enableCompressionIfSupported(ex);
    HttpExchanges.respond(ex, HttpURLConnection.HTTP_OK, "application/json",
        response.toString().getBytes(charset));
  }

  public interface RpcMethod {
    /**
     * Execute expected task for the class. Should not return {@code null}, as
     * that can't be disambiguated from a misformed response. If an exception
     * is thrown, the message will be sent in the response as the error.
     *
     * @throws Exception when something goes wrong
     */
    public Object run(List request) throws Exception;
  }
}
