WIP - Suggesting changes (take2)

    This is not yet completed, still working on things. Eventually the plan
    is to provide the following changes

    - restructure repo to be more aligned with https://github.com/golang-standards/project-layout
    - add k8s probes
    - modifications (golang range loops, etc) to follow some golang
    practices

Change-Id: I6922cbc00b5ef17ceab183aba00a7fc59ab46480
diff --git a/internal/pkg/ofagent/changeEvent.go b/internal/pkg/ofagent/changeEvent.go
new file mode 100644
index 0000000..90b0fd6
--- /dev/null
+++ b/internal/pkg/ofagent/changeEvent.go
@@ -0,0 +1,110 @@
+/*
+   Copyright 2020 the original author or authors.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package ofagent
+
+import (
+	"context"
+	"encoding/json"
+	ofp "github.com/donNewtonAlpha/goloxi/of13"
+	"github.com/golang/protobuf/ptypes/empty"
+	"github.com/opencord/ofagent-go/internal/pkg/openflow"
+	"github.com/opencord/voltha-lib-go/v2/pkg/log"
+	"google.golang.org/grpc"
+	"net"
+)
+
+func (ofa *OFAgent) receiveChangeEvents(ctx context.Context) {
+	logger.Debug("receive-change-events-started")
+	opt := grpc.EmptyCallOption{}
+	streamCtx, streamDone := context.WithCancel(context.Background())
+	stream, err := ofa.volthaClient.ReceiveChangeEvents(streamCtx, &empty.Empty{}, opt)
+	if err != nil {
+		logger.Errorw("Unable to establish Receive Change Event Stream",
+			log.Fields{"error": err})
+		ofa.events <- ofaEventVolthaDisconnected
+	}
+	defer streamDone()
+
+	for {
+		select {
+		case <-ctx.Done():
+			return
+		default:
+			if ce, err := stream.Recv(); err != nil {
+				logger.Errorw("error receiving change event",
+					log.Fields{"error": err})
+				ofa.events <- ofaEventVolthaDisconnected
+			} else {
+				ofa.changeEventChannel <- ce
+			}
+		}
+	}
+}
+
+func (ofa *OFAgent) handleChangeEvents(ctx context.Context) {
+	logger.Debugln("handle-change-event-started")
+	for {
+		select {
+		case <-ctx.Done():
+			return
+		case changeEvent := <-ofa.changeEventChannel:
+			deviceID := changeEvent.GetId()
+			portStatus := changeEvent.GetPortStatus()
+			logger.Debugw("received-change-event",
+				log.Fields{
+					"device-id":   deviceID,
+					"port-status": portStatus})
+
+			if portStatus == nil {
+				if logger.V(log.WarnLevel) {
+					js, _ := json.Marshal(changeEvent.GetEvent())
+					logger.Warnw("Received change event that was not port status",
+						log.Fields{"ChangeEvent": js})
+				}
+				break
+			}
+			ofPortStatus := ofp.NewPortStatus()
+			ofPortStatus.SetXid(openflow.GetXid())
+			ofPortStatus.SetVersion(4)
+
+			ofReason := ofp.PortReason(portStatus.GetReason())
+			ofPortStatus.SetReason(ofReason)
+			ofDesc := ofp.NewPortDesc()
+
+			desc := portStatus.GetDesc()
+			ofDesc.SetAdvertised(ofp.PortFeatures(desc.GetAdvertised()))
+			ofDesc.SetConfig(ofp.PortConfig(0))
+			ofDesc.SetCurr(ofp.PortFeatures(desc.GetAdvertised()))
+			ofDesc.SetCurrSpeed(desc.GetCurrSpeed())
+			intArray := desc.GetHwAddr()
+			var octets []byte
+			for _, val := range intArray {
+				octets = append(octets, byte(val))
+			}
+			addr := net.HardwareAddr(octets)
+			ofDesc.SetHwAddr(addr)
+			ofDesc.SetMaxSpeed(desc.GetMaxSpeed())
+			ofDesc.SetName(openflow.PadString(desc.GetName(), 16))
+			ofDesc.SetPeer(ofp.PortFeatures(desc.GetPeer()))
+			ofDesc.SetPortNo(ofp.Port(desc.GetPortNo()))
+			ofDesc.SetState(ofp.PortState(desc.GetState()))
+			ofDesc.SetSupported(ofp.PortFeatures(desc.GetSupported()))
+			ofPortStatus.SetDesc(*ofDesc)
+			ofa.getOFClient(deviceID).SendMessage(ofPortStatus)
+		}
+	}
+}