/*
 * 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() {
		return nil, fmt.Errorf("unsupported attribute mask %#x, valid: %#x for ME %v (Class ID: %d)",
			mask, bme.GetAllowedAttributeMask(), bme.GetName(), bme.ClassID)
	}
	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
					// TODO: No support at this time

				case byte(SetTable) | AR: // Set Table Request
					attrMap[name] = value
					data = data[len(data):]
				}
			} 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
}
