package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"

	"code.fbi.h-da.de/danet/gosdn/api/go/gosdn/networkelement"

	"code.fbi.h-da.de/danet/gosdn/application-framework/event"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

// Application is an example for a sdn application.
type Application struct {
	eventServiceNetworkElements event.ServiceInterface
	stopChannel                 chan os.Signal
	grpcClientConn              *grpc.ClientConn
}

// Run runs the application.
func (a *Application) Run(controllerAddress string) {
	statusMap = make(map[string]map[string]*InterfaceStatus)

	signal.Notify(a.stopChannel, os.Interrupt, syscall.SIGTERM)

	a.eventServiceNetworkElements.SubscribeToEventType([]event.TypeToCallbackTuple{
		{Type: event.Update, Callback: a.NetworkElementCallback},
	})
	a.eventServiceNetworkElements.SetupEventReciever(a.stopChannel)

	conn, err := grpc.Dial(controllerAddress, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		panic(err)
	}

	a.grpcClientConn = conn

	var forever chan struct{}

	go func() {
		for {
			select {
			case <-a.stopChannel:
				close(forever)
				_ = a.grpcClientConn.Close()

				return
			}
		}
	}()

	if err := StartHTTPServer(); err != nil {
		panic(err)
	}

	<-forever
}

// NetworkElementCallback is the callback function for network element changes.
func (a *Application) NetworkElementCallback(event *event.Event) {
	networkElementServer := networkelement.NewNetworkElementServiceClient(a.grpcClientConn)

	changedInterfaces, err := checkIfOperationStateHasChanged(networkElementServer, event.EntityID)
	if err != nil {
		fmt.Printf("Error %+v\n ", err)
	}

	if changedInterfaces != nil {
		for _, changedInterface := range changedInterfaces {
			fmt.Printf("Change on %s: status of interface %s has changed to %s\n", changedInterface.NetworkElementName, changedInterface.Name, changedInterface.Status)
		}
	}
}
