package main

import (
	"fmt"
	"log"
	"math/rand"
	"net"
	"strconv"
	"time"

	"github.com/go-ping/ping"
	"github.com/milosgajdos/tenus"
)

type AbstractBridge struct {
	ExistingInterface string
	BridgeIpCIDR      string
	IsActive          bool
	hIerarchyNumber   int64
}

func init() {

	ZoreideBridge.initializeHierarchy()

}

func (b *AbstractBridge) initializeHierarchy() {

	var letterRunes = []rune("123456789")

	num := make([]rune, numberlenght)
	for i := range num {
		num[i] = letterRunes[rand.Intn(len(letterRunes))]
	}

	zz, err := strconv.ParseInt(string(num), 10, 64)
	if err != nil {
		log.Println("Error generating number: ", err.Error())
		b.hIerarchyNumber = 0
		return
	} else {
		b.hIerarchyNumber = zz
		log.Println("Success generating number: ", b.hIerarchyNumber)
	}

}

func (b *AbstractBridge) configureIpAndBridgeUp() {
	// we want the program to recover in case of issues
	defer func() {
		if r := recover(); r != nil {

			fmt.Println("An error happened in <configureIpAndBridgeUp()>, but Zoreide recovered. ")
			fmt.Println("Error was: ", r)
		}
	}()

	// first we check the IP is free. Something weird could have happened in some
	// other server
	brIp, brIpNet, err := net.ParseCIDR(b.BridgeIpCIDR)
	if err != nil {
		log.Println(err.Error())
	}

	if doesIpExists(brIp.String()) {
		log.Println("Cannot take this IP, it exists already: " + brIp.String())
		return
	}

	br, err := tenus.NewLinkFrom(b.ExistingInterface)
	if err != nil {
		log.Println(err.Error())
	}

	if err := br.SetLinkIp(brIp, brIpNet); err != nil {
		log.Println(err.Error())
	}

}

func (b *AbstractBridge) removeIPandBridgeInt() {

	// we want the program to recover in case of issues
	defer func() {
		if r := recover(); r != nil {

			fmt.Println("An error happened in <removeIPandBridgeInt()>, but Zoreide recovered. ")
			fmt.Println("Error was: ", r)
		}
	}()

	br, err := tenus.NewLinkFrom(b.ExistingInterface)
	if err != nil {
		log.Println(err.Error())
	}

	brIp, brIpNet, err := net.ParseCIDR(b.BridgeIpCIDR)
	if err != nil {
		log.Println(err.Error())
	}
	if err := br.UnsetLinkIp(brIp, brIpNet); err != nil {
		log.Println(err.Error())
	}

}

func doesIpExists(bridgeip string) bool {

	pinger, err := ping.NewPinger(bridgeip)
	if err != nil {
		log.Println("Ping error: " + err.Error())
	}
	// just in case it doesn't stops alone
	defer pinger.Stop()
	pinger.Count = 5
	pinger.Interval = time.Duration(10 * time.Millisecond)
	pinger.Timeout = time.Duration(1 * time.Second)
	pinger.Run() // blocks until finished
	stats := pinger.Statistics()

	return stats.PacketsRecv == 5

}
