package discovery

import (
	"git.loafle.net/overflow/overflow_probe/discovery/core/scan/service"
	"git.loafle.net/overflow/overflow_probe/discovery/discovery/types"
	"github.com/cihub/seelog"
	"github.com/google/gopacket"
	"sync"
)

type discoverZoneCallback func(host *types.DiscoveryZone)
type discoverHostCallback func(host *types.DiscoveryHost)
type discoverTCPPortCallback func(port *types.DiscoveryPort)
type discoverUDPPortCallback func(zone *types.DiscoveryZone, ipString, portString string, udpLayer gopacket.Layer)

func Discover(fin chan<- bool) {

	dhs := make([]types.DiscoveryHistory, 0)
	var wg sync.WaitGroup
	wg.Add(1)
	DiscoverZone(&wg, true, &dhs)
	wg.Wait()
	sendBridge(dhs)
	fin <- true
}

func DiscoverZone(wg *sync.WaitGroup, hasHostScan bool, dhs *[]types.DiscoveryHistory) {

	discoveryZone(func(zone *types.DiscoveryZone) {
		*dhs = append(*dhs, types.NewDiscoveryHistory(zone))
		if hasHostScan == true {
			wg.Add(1)
			go DiscoveryHost(zone, wg, true)
		}
	})
	wg.Done()
}

func DiscoveryHost(zone *types.DiscoveryZone, wg *sync.WaitGroup, hasPortScan bool) {
	discoveryHost(zone, func(host *types.DiscoveryHost) {
		seelog.Debug("find host : " + host.Ip_)
		if hasPortScan == true {
			wg.Add(1)
			go DiscoverPort(host, wg, hasPortScan)
		}
	})
	wg.Done()
}

func DiscoverPort(host *types.DiscoveryHost, wg *sync.WaitGroup, hasServiceScan bool) {
	discoverPort(host,
		func(port *types.DiscoveryPort) {
			if hasServiceScan == true {
				wg.Add(1)
				go DiscoverService(port, wg)
			}
		},
		func(zone *types.DiscoveryZone, ipString, portString string, udpLayer gopacket.Layer) {
			wg.Add(1)
			go DiscoverUDPService(zone, wg, ipString, portString, udpLayer)
		})
	wg.Done()
}

func DiscoverService(port *types.DiscoveryPort, wg *sync.WaitGroup) {
	discoverService(port)
	wg.Done()
}

func DiscoverUDPService(zone *types.DiscoveryZone, wg *sync.WaitGroup, ipString, portString string, udpLayer gopacket.Layer) {
	service.MatchUDPPacket(zone, ipString, portString, udpLayer)
	wg.Done()
}
