// Copyright (C) 2008 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.server;

import com.google.gerrit.client.data.GerritConfig;
import com.google.gerrit.client.data.SshHostKey;
import com.google.gerrit.client.data.SystemInfoService;
import com.google.gerrit.client.reviewdb.ContributorAgreement;
import com.google.gerrit.client.reviewdb.ReviewDb;
import com.google.gerrit.client.rpc.Common;
import com.google.gerrit.server.ssh.GerritSshDaemon;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwtorm.client.OrmException;

import com.jcraft.jsch.HostKey;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;

import org.apache.sshd.common.util.Buffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.security.PublicKey;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

public class SystemInfoServiceImpl implements SystemInfoService {
  private static final Logger log =
      LoggerFactory.getLogger(SystemInfoServiceImpl.class);
  private static final JSch JSCH = new JSch();

  public static GerritConfig getGerritConfig() {
    final GerritConfig cfg = Common.getGerritConfig();
    synchronized (cfg) {
      if (cfg.getSshdAddress() == null) {
        final InetSocketAddress addr = GerritSshDaemon.getAddress();
        if (addr != null) {
          final InetAddress ip = addr.getAddress();
          String host;
          if (ip != null && ip.isAnyLocalAddress()) {
            host = "";
          } else if (isIPv6(ip)) {
            host = "[" + addr.getHostName() + "]";
          } else {
            host = addr.getHostName();
          }
          if (addr.getPort() != 22) {
            host += ":" + addr.getPort();
          }
          cfg.setSshdAddress(host);
        }
      }
    }
    return cfg;
  }

  private static boolean isIPv6(final InetAddress ip) {
    return ip instanceof Inet6Address
        && ip.getHostName().equals(ip.getHostAddress());
  }

  public void loadGerritConfig(final AsyncCallback<GerritConfig> callback) {
    callback.onSuccess(getGerritConfig());
  }

  public void contributorAgreements(
      final AsyncCallback<List<ContributorAgreement>> callback) {
    try {
      final ReviewDb db = Common.getSchemaFactory().open();
      try {
        callback.onSuccess(db.contributorAgreements().active().toList());
      } finally {
        db.close();
      }
    } catch (OrmException e) {
      callback.onFailure(e);
    }
  }

  public void daemonHostKeys(final AsyncCallback<List<SshHostKey>> callback) {
    final String hostIdent = hostIdent();
    final List<PublicKey> keys = sortKeys();
    final ArrayList<SshHostKey> r = new ArrayList<SshHostKey>(keys.size());
    for (final PublicKey pub : keys) {
      try {
        final HostKey hk = toHostKey(hostIdent, pub);
        r.add(new SshHostKey(hk.getHost(), hk.getType() + " " + hk.getKey(), hk
            .getFingerPrint(JSCH)));
      } catch (JSchException e) {
        log.error("Invalid host key", e);
        continue;
      }
    }
    callback.onSuccess(r);
  }

  private static List<PublicKey> sortKeys() {
    final List<PublicKey> r = new ArrayList<PublicKey>(2);
    r.addAll(GerritSshDaemon.getHostKeys());
    Collections.sort(r, new Comparator<PublicKey>() {
      @Override
      public int compare(final PublicKey a, final PublicKey b) {
        if (a == b) {
          return 0;
        }
        if (a instanceof RSAPublicKey) {
          return -1;
        }
        if (a instanceof DSAPublicKey) {
          return 1;
        }
        return 0;
      }
    });
    return r;
  }

  private HostKey toHostKey(final String hostIdent, final PublicKey pub)
      throws JSchException {
    final Buffer buf = new Buffer();
    buf.putPublicKey(pub);
    final byte[] keyBin = buf.getCompactData();
    return new HostKey(hostIdent, keyBin);
  }

  private String hostIdent() {
    final HttpServletRequest req =
        GerritJsonServlet.getCurrentCall().getHttpServletRequest();

    InetSocketAddress addr = GerritSshDaemon.getAddress();
    InetAddress ip = addr.getAddress();
    if (ip.isAnyLocalAddress()) {
      try {
        ip = InetAddress.getByName(req.getServerName());
      } catch (UnknownHostException e) {
        throw new RuntimeException(e);
      }
      addr = new InetSocketAddress(ip, addr.getPort());
    }

    if (addr.getPort() == 22 && !isIPv6(ip)) {
      return addr.getHostName();
    }
    return "[" + addr.getHostName() + "]:" + addr.getPort();
  }
}
