[VOL-1349] EPON ONU adapter (package B)

Change-Id: I609ba349c429bc7e87c74b66bb1121841f9caef6
diff --git a/internal/pkg/onuadaptercore/onu_device_db.go b/internal/pkg/onuadaptercore/onu_device_db.go
new file mode 100644
index 0000000..ca954d6
--- /dev/null
+++ b/internal/pkg/onuadaptercore/onu_device_db.go
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * 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 adaptercoreonu provides the utility for onu devices, flows and statistics
+package adaptercoreonu
+
+import (
+	"context"
+	"fmt"
+	"reflect"
+	"sort"
+
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/opencord/voltha-lib-go/v3/pkg/log"
+)
+
+type meDbMap map[me.ClassID]map[uint16]me.AttributeValueMap
+
+//onuDeviceDB structure holds information about known ME's
+type onuDeviceDB struct {
+	ctx             context.Context
+	pOnuDeviceEntry *OnuDeviceEntry
+	meDb            meDbMap
+}
+
+//newOnuDeviceDB returns a new instance for a specific ONU_Device_Entry
+func newOnuDeviceDB(ctx context.Context, aPOnuDeviceEntry *OnuDeviceEntry) *onuDeviceDB {
+	logger.Debugw("Init OnuDeviceDB for:", log.Fields{"device-id": aPOnuDeviceEntry.deviceID})
+	var onuDeviceDB onuDeviceDB
+	onuDeviceDB.ctx = ctx
+	onuDeviceDB.pOnuDeviceEntry = aPOnuDeviceEntry
+	onuDeviceDB.meDb = make(meDbMap)
+
+	return &onuDeviceDB
+}
+
+func (onuDeviceDB *onuDeviceDB) PutMe(meClassID me.ClassID, meEntityID uint16, meAttributes me.AttributeValueMap) {
+
+	if me.OnuDataClassID == meClassID {
+		return
+	}
+
+	meInstMap, ok := onuDeviceDB.meDb[meClassID]
+	if !ok {
+		logger.Debugw("meClassID not found - add to db :", log.Fields{"device-id": onuDeviceDB.pOnuDeviceEntry.deviceID})
+		meInstMap = make(map[uint16]me.AttributeValueMap)
+		onuDeviceDB.meDb[meClassID] = meInstMap
+		onuDeviceDB.meDb[meClassID][meEntityID] = meAttributes
+	} else {
+		meAttribs, ok := meInstMap[meEntityID]
+		if !ok {
+			/* verbose logging, avoid in >= debug level
+			logger.Debugw("meEntityId not found - add to db :", log.Fields{"device-id": onuDeviceDB.pOnuDeviceEntry.deviceID})
+			*/
+			meInstMap[meEntityID] = meAttributes
+		} else {
+			/* verbose logging, avoid in >= debug level
+			logger.Debugw("ME-Instance exists already: merge attribute data :", log.Fields{"device-id": onuDeviceDB.pOnuDeviceEntry.deviceID, "meAttribs": meAttribs})
+			*/
+			for k, v := range meAttributes {
+				meAttribs[k] = v
+			}
+			meInstMap[meEntityID] = meAttribs
+			/* verbose logging, avoid in >= debug level
+			logger.Debugw("ME-Instance updated :", log.Fields{"device-id": onuDeviceDB.pOnuDeviceEntry.deviceID, "meAttribs": meAttribs})
+			*/
+		}
+	}
+}
+
+func (onuDeviceDB *onuDeviceDB) GetMe(meClassID me.ClassID, meEntityID uint16) me.AttributeValueMap {
+
+	if meAttributes, present := onuDeviceDB.meDb[meClassID][meEntityID]; present {
+		/* verbose logging, avoid in >= debug level
+		logger.Debugw("ME found:", log.Fields{"meClassID": meClassID, "meEntityID": meEntityID, "meAttributes": meAttributes,
+			"device-id": onuDeviceDB.pOnuDeviceEntry.deviceID})
+		*/
+		return meAttributes
+	}
+	return nil
+}
+
+func (onuDeviceDB *onuDeviceDB) getUint32Attrib(meAttribute interface{}) (uint32, error) {
+
+	switch reflect.TypeOf(meAttribute).Kind() {
+	case reflect.Float64:
+		//JSON numbers by default are unmarshaled into values of float64 type if type information is not present
+		return uint32(meAttribute.(float64)), nil
+	case reflect.Uint32:
+		return uint32(meAttribute.(uint32)), nil
+	default:
+		return uint32(0), fmt.Errorf(fmt.Sprintf("wrong interface-type received-%s", onuDeviceDB.pOnuDeviceEntry.deviceID))
+	}
+}
+
+func (onuDeviceDB *onuDeviceDB) getSortedInstKeys(meClassID me.ClassID) []uint16 {
+
+	var meInstKeys []uint16
+
+	meInstMap := onuDeviceDB.meDb[meClassID]
+
+	for k := range meInstMap {
+		meInstKeys = append(meInstKeys, k)
+	}
+	logger.Debugw("meInstKeys - input order :", log.Fields{"meInstKeys": meInstKeys}) //TODO: delete the line after test phase!
+	sort.Slice(meInstKeys, func(i, j int) bool { return meInstKeys[i] < meInstKeys[j] })
+	logger.Debugw("meInstKeys - output order :", log.Fields{"meInstKeys": meInstKeys}) //TODO: delete the line after test phase!
+	return meInstKeys
+}
+
+func (onuDeviceDB *onuDeviceDB) logMeDb() {
+	logger.Debugw("ME instances stored for :", log.Fields{"device-id": onuDeviceDB.pOnuDeviceEntry.deviceID})
+	for meClassID, meInstMap := range onuDeviceDB.meDb {
+		for meEntityID, meAttribs := range meInstMap {
+			logger.Debugw("ME instance: ", log.Fields{"meClassID": meClassID, "meEntityID": meEntityID, "meAttribs": meAttribs, "device-id": onuDeviceDB.pOnuDeviceEntry.deviceID})
+		}
+	}
+}