/*
 * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
 * 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.
 */
/*
 * NOTE: This file was generated, manual edits will be overwritten!
 *
 * Generated by 'goCodeGenerator.py':
 *              https://github.com/cboling/OMCI-parser/README.md
 */

package generated

import (
	"errors"
	"fmt"
	"github.com/deckarep/golang-set"
	"github.com/google/gopacket"
	"math/bits"
)

// ManagedEntityDefinition defines a Manage Entity
type ManagedEntityDefinition struct {
	Name                 string
	ClassID              ClassID
	MessageTypes         mapset.Set // Mandatory
	AllowedAttributeMask uint16
	AttributeDefinitions AttributeDefinitionMap
	Access               ClassAccess
	Support              ClassSupport
	Alarms               AlarmMap // AlarmBit -> AlarmName
}

func (bme *ManagedEntityDefinition) String() string {
	return fmt.Sprintf("Definition: %s: CID: %v, Attributes: %v",
		bme.Name, bme.ClassID, bme.AttributeDefinitions)
}

// GetName retrieves the name of a managed entity from a ME Definition
func (bme ManagedEntityDefinition) GetName() string {
	return bme.Name
}

// GetClassID retrieves the 16-bit class ID of a managed entity from a ME Definition
func (bme ManagedEntityDefinition) GetClassID() ClassID {
	return bme.ClassID
}

// SetClassID assigns the 16-bit class ID of a managed entity from a ME Definition
func (bme *ManagedEntityDefinition) SetClassID(classID ClassID) {
	bme.ClassID = classID
}

// GetMessageTypes retrieves the OMCI Message Types supporte3d by a managed entity from a ME Definition
func (bme ManagedEntityDefinition) GetMessageTypes() mapset.Set {
	return bme.MessageTypes
}

// GetAllowedAttributeMask retrieves the allowed/valid 16-bit attribute mask of a managed entity
// from a ME Definition
func (bme ManagedEntityDefinition) GetAllowedAttributeMask() uint16 {
	return bme.AllowedAttributeMask
}

// GetAttributeDefinitions retrieves the attribute definitions of a managed entity from a ME Definition
func (bme ManagedEntityDefinition) GetAttributeDefinitions() AttributeDefinitionMap {
	return bme.AttributeDefinitions
}

// GetClassSupport returns ONUs support of this class
func (bme ManagedEntityDefinition) GetClassSupport() ClassSupport {
	return bme.Support
}

// GetAlarmMap returns the Alarm bit number to name map
func (bme ManagedEntityDefinition) GetAlarmMap() AlarmMap {
	return bme.Alarms
}

func (bme ManagedEntityDefinition) DecodeAttributes(mask uint16, data []byte, p gopacket.PacketBuilder, msgType byte) (AttributeValueMap, error) {
	if (mask | bme.GetAllowedAttributeMask()) != bme.GetAllowedAttributeMask() {
		// TODO: Provide custom error code so a response 'result' can properly be coded
		return nil, errors.New("unsupported attribute mask")
	}
	keyList := GetAttributeDefinitionMapKeys(bme.AttributeDefinitions)

	attrMap := make(AttributeValueMap, bits.OnesCount16(mask))
	for _, index := range keyList {
		if index == 0 {
			continue // Skip Entity ID
		}
		attrDef := bme.AttributeDefinitions[index]
		name := attrDef.GetName()

		if mask&attrDef.Mask != 0 {
			value, err := attrDef.Decode(data, p, msgType)
			if err != nil {
				return nil, err
			}
			if attrDef.IsTableAttribute() {
				switch msgType {
				default:
					return nil, fmt.Errorf("unsupported Message Type '%v' for table serialization", msgType)

				case byte(Get) | AK: // Get Response
					attrMap[name] = value
					data = data[4:]

				case byte(GetNext) | AK: // Get Next Response
					// Value is a partial octet buffer we need to collect and at
					// the end (last segment) pull it up into more appropriate table
					// rows
					valueBuffer, ok := value.([]byte)
					if !ok {
						panic("unexpected type already returned as get-next-response attribute data")
					}
					if existing, found := attrMap[name]; found {
						prev, ok := existing.([]byte)
						if !ok {
							panic("unexpected type already in attribute value map")
						}
						attrMap[name] = append(prev, valueBuffer...)
					} else {
						attrMap[name] = valueBuffer
					}
					if size := attrDef.GetSize(); size != 0 && size > len(valueBuffer) {
						panic("unexpected size difference")
					}
					data = data[len(valueBuffer):]

				case byte(Set) | AR: // Set Request
					fmt.Println("TODO")

				case byte(SetTable) | AR: // Set Table Request
					// TODO: Only baseline supported at this time
					return nil, errors.New("attribute encode for set-table-request not yet supported")
				}
			} else {
				attrMap[name] = value
				data = data[attrDef.GetSize():]
			}
		}
	}
	return attrMap, nil
}

func (bme ManagedEntityDefinition) SerializeAttributes(attr AttributeValueMap, mask uint16,
	b gopacket.SerializeBuffer, msgType byte, bytesAvailable int, packData bool) (error, uint16) {

	if (mask | bme.GetAllowedAttributeMask()) != bme.GetAllowedAttributeMask() {
		// TODO: Provide custom error code so a response 'result' can properly be coded
		return errors.New("unsupported attribute mask"), 0
	}
	// TODO: Need to limit number of bytes appended to not exceed packet size
	// Is there space/metadata info in 'b' parameter to allow this?
	keyList := GetAttributeDefinitionMapKeys(bme.AttributeDefinitions)
	var failedMask uint16

	for _, index := range keyList {
		if index == 0 {
			continue // Skip Entity ID
		}
		attrDef := bme.AttributeDefinitions[index]

		if mask&attrDef.Mask != 0 {
			value, ok := attr[attrDef.GetName()]
			if !ok {
				msg := fmt.Sprintf("attribute not found: '%v'", attrDef.GetName())
				return errors.New(msg), failedMask
			}
			size, err := attrDef.SerializeTo(value, b, msgType, bytesAvailable)
			if err != nil {
				failedMask |= attrDef.Mask
				if packData {
					continue
				}
				return err, failedMask
			}
			bytesAvailable -= size
		}
	}
	return nil, failedMask
}
