/*
  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 "address.hpp"

#include "logger.hpp"
#include "macros.hpp"
#include "row.hpp"
#include "value.hpp"

using namespace datastax;
using namespace datastax::internal::core;

const Address Address::EMPTY_KEY(String(), 0);
const Address Address::DELETED_KEY(String(), 1);

namespace {

template <class T>
inline void hash_combine(std::size_t& seed, const T& v) {
  SPARSEHASH_HASH<T> hasher;
  seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

} // namespace

Address::Address()
    : family_(UNRESOLVED)
    , port_(0) {}

Address::Address(const Address& other, const String& server_name)
    : hostname_or_address_(other.hostname_or_address_)
    , server_name_(server_name)
    , family_(other.family_)
    , port_(other.port_) {}

Address::Address(const String& hostname, int port, const String& server_name)
    : server_name_(server_name)
    , family_(UNRESOLVED)
    , port_(port) {
  char addr[16];
  if (uv_inet_pton(AF_INET, hostname.c_str(), addr) == 0) {
    hostname_or_address_.assign(addr, addr + 4);
    family_ = IPv4;
  } else if (uv_inet_pton(AF_INET6, hostname.c_str(), addr) == 0) {
    hostname_or_address_.assign(addr, addr + 16);
    family_ = IPv6;
  } else {
    hostname_or_address_ = hostname;
  }
}

Address::Address(const uint8_t* address, uint8_t address_length, int port)
    : family_(UNRESOLVED)
    , port_(port) {
  if (address_length == 4) {
    hostname_or_address_.assign(reinterpret_cast<const char*>(address), address_length);
    family_ = IPv4;
  } else if (address_length == 16) {
    hostname_or_address_.assign(reinterpret_cast<const char*>(address), address_length);
    family_ = IPv6;
  }
}

Address::Address(const struct sockaddr* addr)
    : family_(UNRESOLVED)
    , port_(0) {
  if (addr->sa_family == AF_INET) {
    const struct sockaddr_in* addr_in = reinterpret_cast<const struct sockaddr_in*>(addr);
    hostname_or_address_.assign(reinterpret_cast<const char*>(&addr_in->sin_addr), 4);
    port_ = ntohs(addr_in->sin_port);
    family_ = IPv4;
  } else if (addr->sa_family == AF_INET6) {
    const struct sockaddr_in6* addr_in6 = reinterpret_cast<const struct sockaddr_in6*>(addr);
    hostname_or_address_.assign(reinterpret_cast<const char*>(&addr_in6->sin6_addr), 16);
    port_ = ntohs(addr_in6->sin6_port);
    family_ = IPv6;
  }
}

bool Address::equals(const Address& other, bool with_port) const {
  if (family_ != other.family_) return false;
  if (with_port && port_ != other.port_) return false;
  if (server_name_ != other.server_name_) return false;
  if (hostname_or_address_ != other.hostname_or_address_) return false;
  return true;
}

bool Address::operator<(const Address& other) const {
  if (family_ != other.family_) return family_ < other.family_;
  if (port_ != other.port_) return port_ < other.port_;
  if (server_name_ != other.server_name_) return server_name_ < other.server_name_;
  return hostname_or_address_ < other.hostname_or_address_;
}

String Address::hostname_or_address() const {
  if (family_ == IPv4) {
    char name[INET_ADDRSTRLEN + 1] = { '\0' };
    uv_inet_ntop(AF_INET, hostname_or_address_.data(), name, INET_ADDRSTRLEN);
    return name;
  } else if (family_ == IPv6) {
    char name[INET6_ADDRSTRLEN + 1] = { '\0' };
    uv_inet_ntop(AF_INET6, hostname_or_address_.data(), name, INET6_ADDRSTRLEN);
    return name;
  } else {
    return hostname_or_address_;
  }
}

size_t Address::hash_code() const {
  SPARSEHASH_HASH<Family> hasher;
  size_t code = hasher(family_);
  hash_combine(code, port_);
  hash_combine(code, server_name_);
  hash_combine(code, hostname_or_address_);
  return code;
}

uint8_t Address::to_inet(void* address) const {
  if (family_ == IPv4 || family_ == IPv6) {
    size_t size = hostname_or_address_.size();
    assert((size == 4 || size == 16) && "Invalid size for address");
    hostname_or_address_.copy(reinterpret_cast<char*>(address), size);
    return static_cast<uint8_t>(size);
  }
  return 0;
}

const struct sockaddr* Address::to_sockaddr(SocketStorage* storage) const {
  int rc = 0;
  if (family_ == IPv4) {
    char name[INET_ADDRSTRLEN + 1] = { '\0' };
    rc = uv_inet_ntop(AF_INET, hostname_or_address_.data(), name, INET_ADDRSTRLEN);
    if (rc != 0) return NULL;
    rc = uv_ip4_addr(name, port_, storage->addr_in());
  } else if (family_ == IPv6) {
    char name[INET6_ADDRSTRLEN + 1] = { '\0' };
    rc = uv_inet_ntop(AF_INET6, hostname_or_address_.data(), name, INET6_ADDRSTRLEN);
    if (rc != 0) return NULL;
    rc = uv_ip6_addr(name, port_, storage->addr_in6());
  } else {
    return NULL;
  }
  if (rc != 0) return NULL;
  return storage->addr();
}

String Address::to_string(bool with_port) const {
  OStringStream ss;
  if (family_ == IPv6 && with_port) {
    ss << "[" << hostname_or_address() << "]";
  } else {
    ss << hostname_or_address();
  }
  if (with_port) {
    ss << ":" << port_;
  }
  if (!server_name_.empty()) {
    ss << " (" << server_name_ << ")";
  }
  return ss.str();
}

namespace datastax { namespace internal { namespace core {

String determine_listen_address(const Address& address, const Row* row) {
  const Value* v = row->get_by_name("peer");
  if (v != NULL) {
    Address listen_address;
    if (v->decoder().as_inet(v->size(), address.port(), &listen_address)) {
      return listen_address.to_string();
    } else {
      LOG_WARN("Invalid address format for listen address for host %s",
               address.to_string().c_str());
    }
  }
  return "";
}

}}} // namespace datastax::internal::core
