package zone

import (
	"github.com/cihub/seelog"
	"net"
	"strings"

	"git.loafle.net/overflow/overflow_probe/discovery/discovery/types"
	"git.loafle.net/overflow/overflow_probe/discovery/util/converter"
	"strconv"
	"sync"
)

var checkStr = []string{
	"docker",
	"lo",
	"br-f23a505183ce",
}

type FoundZoneHandler func(z *types.DiscoveryZone)

func Scan(callback FoundZoneHandler) {
	startZone(callback)
}

func ScanAndCheck(zones *[]types.DiscoveryZone) {

}

func Check(zones *[]types.DiscoveryZone) {

}

func startZone(callback FoundZoneHandler) {
	//var zones []*types.DiscoveryZone

	ifaces, _ := net.Interfaces()

	for _, i := range ifaces {

		if checkStrByInterfaces(i.Name) {
			continue
		}

		addrs, err := i.Addrs()

		if err != nil {
			seelog.Critical(err)
			continue
		}

		for _, addr := range addrs {

			if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
				if ipnet.IP.To4() != nil {

					if err != nil {
						seelog.Critical(err)
						continue
					}

					cidrs := strings.Split(addr.String(), "/")
					tempNet, err := strconv.Atoi(cidrs[1])
					if err != nil {
						seelog.Critical(err)
					}
					netMask := uint8(tempNet)
					f, l := GetMinAndMaxIPRange(addr.String())

					first := net.ParseIP(f)
					last := net.ParseIP(l)
					zone := &types.DiscoveryZone{
						M:              new(sync.RWMutex),
						Netmask:        netMask,
						Hosts_:         make(map[string]*types.DiscoveryHost, 255),
						Ip:             converter.IP4toInt(ipnet.IP),
						FirstScanRange: converter.IP4toInt(first),
						LastScanRange:  converter.IP4toInt(last),
						Mac:            converter.MacToInt(i.HardwareAddr),
						Iface:          i.Name,
					}

					if callback != nil {
						callback(zone)
					}

				}
			}

		}
	}
}

// Test
func NewZone() *types.DiscoveryZone {

	var z = &types.DiscoveryZone{}
	startZone(func(zone *types.DiscoveryZone) {
		if zone != nil {
			z = zone
		}
	})
	return z
}

func GetMinAndMaxIPRange(ip string) (min string, max string) {
	_, ipnet, err := net.ParseCIDR(ip)

	if err != nil {
		return
	}

	var ips []string
	cc := strings.Split(ip, "/")

	cip := net.ParseIP(cc[0])
	for addr := cip.Mask(ipnet.Mask); ipnet.Contains(addr); inc(addr) {
		ips = append(ips, addr.String())
	}

	if len(ips) < 3 {
		return
	}

	min = ips[1]
	max = ips[len(ips)-2]

	return

}

func checkStrByInterfaces(inter string) bool {

	for _, str := range checkStr {
		index := strings.Index(inter, str)
		if index >= 0 {
			return true
		}
	}

	return false
}

func inc(ip net.IP) {
	for j := len(ip) - 1; j >= 0; j-- {
		ip[j]++
		if ip[j] > 0 {
			break
		}
	}
}
