package types

// Reference: https://www.ietf.org/rfc/rfc4120.txt
// Section: 5.2.5

import (
	"bytes"
	"fmt"
	"net"

	"github.com/jcmturner/gofork/encoding/asn1"
	"gopkg.in/jcmturner/gokrb5.v7/iana/addrtype"
)

/*
HostAddress and HostAddresses

HostAddress     ::= SEQUENCE  {
	addr-type       [0] Int32,
	address         [1] OCTET STRING
}

-- NOTE: HostAddresses is always used as an OPTIONAL field and
-- should not be empty.
HostAddresses   -- NOTE: subtly different from rfc1510,
		-- but has a value mapping and encodes the same
	::= SEQUENCE OF HostAddress

The host address encodings consist of two fields:

addr-type
	This field specifies the type of address that follows.  Pre-
	defined values for this field are specified in Section 7.5.3.

address
	This field encodes a single address of type addr-type.
*/

// HostAddresses implements RFC 4120 type: https://tools.ietf.org/html/rfc4120#section-5.2.5
type HostAddresses []HostAddress

// HostAddress implements RFC 4120 type: https://tools.ietf.org/html/rfc4120#section-5.2.5
type HostAddress struct {
	AddrType int32  `asn1:"explicit,tag:0"`
	Address  []byte `asn1:"explicit,tag:1"`
}

// GetHostAddress returns a HostAddress struct from a string in the format <hostname>:<port>
func GetHostAddress(s string) (HostAddress, error) {
	var h HostAddress
	cAddr, _, err := net.SplitHostPort(s)
	if err != nil {
		return h, fmt.Errorf("invalid format of client address: %v", err)
	}
	ip := net.ParseIP(cAddr)
	var ht int32
	if ip.To4() != nil {
		ht = addrtype.IPv4
		ip = ip.To4()
	} else if ip.To16() != nil {
		ht = addrtype.IPv6
		ip = ip.To16()
	} else {
		return h, fmt.Errorf("could not determine client's address types: %v", err)
	}
	h = HostAddress{
		AddrType: ht,
		Address:  ip,
	}
	return h, nil
}

// GetAddress returns a string representation of the HostAddress.
func (h *HostAddress) GetAddress() (string, error) {
	var b []byte
	_, err := asn1.Unmarshal(h.Address, &b)
	return string(b), err
}

// LocalHostAddresses returns a HostAddresses struct for the local machines interface IP addresses.
func LocalHostAddresses() (ha HostAddresses, err error) {
	ifs, err := net.Interfaces()
	if err != nil {
		return
	}
	for _, iface := range ifs {
		if iface.Flags&net.FlagLoopback != 0 || iface.Flags&net.FlagUp == 0 {
			// Interface is either loopback of not up
			continue
		}
		addrs, err := iface.Addrs()
		if err != nil {
			continue
		}
		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}
			var a HostAddress
			if ip.To16() == nil {
				//neither IPv4 or IPv6
				continue
			}
			if ip.To4() != nil {
				//Is IPv4
				a.AddrType = addrtype.IPv4
				a.Address = ip.To4()
			} else {
				a.AddrType = addrtype.IPv6
				a.Address = ip.To16()
			}
			ha = append(ha, a)
		}
	}
	return ha, nil
}

// HostAddressesFromNetIPs returns a HostAddresses type from a slice of net.IP
func HostAddressesFromNetIPs(ips []net.IP) (ha HostAddresses) {
	for _, ip := range ips {
		ha = append(ha, HostAddressFromNetIP(ip))
	}
	return ha
}

// HostAddressFromNetIP returns a HostAddress type from a net.IP
func HostAddressFromNetIP(ip net.IP) HostAddress {
	if ip.To4() != nil {
		//Is IPv4
		return HostAddress{
			AddrType: addrtype.IPv4,
			Address:  ip.To4(),
		}
	}
	return HostAddress{
		AddrType: addrtype.IPv6,
		Address:  ip.To16(),
	}
}

// HostAddressesEqual tests if two HostAddress slices are equal.
func HostAddressesEqual(h, a []HostAddress) bool {
	if len(h) != len(a) {
		return false
	}
	for _, e := range a {
		var found bool
		for _, i := range h {
			if e.Equal(i) {
				found = true
				break
			}
		}
		if !found {
			return false
		}
	}
	return true
}

// HostAddressesContains tests if a HostAddress is contained in a HostAddress slice.
func HostAddressesContains(h []HostAddress, a HostAddress) bool {
	for _, e := range h {
		if e.Equal(a) {
			return true
		}
	}
	return false
}

// Equal tests if the HostAddress is equal to another HostAddress provided.
func (h *HostAddress) Equal(a HostAddress) bool {
	if h.AddrType != a.AddrType {
		return false
	}
	return bytes.Equal(h.Address, a.Address)
}

// Contains tests if a HostAddress is contained within the HostAddresses struct.
func (h *HostAddresses) Contains(a HostAddress) bool {
	for _, e := range *h {
		if e.Equal(a) {
			return true
		}
	}
	return false
}

// Equal tests if a HostAddress slice is equal to the HostAddresses struct.
func (h *HostAddresses) Equal(a []HostAddress) bool {
	if len(*h) != len(a) {
		return false
	}
	for _, e := range a {
		if !h.Contains(e) {
			return false
		}
	}
	return true
}
