/*
 * Copyright 2018-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 model

import (
	desc "github.com/golang/protobuf/descriptor"
	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/protoc-gen-go/descriptor"
	"github.com/opencord/voltha-lib-go/v2/pkg/log"
	"github.com/opencord/voltha-protos/v2/go/common"
	"reflect"
	"strconv"
	"sync"
)

type childTypesSingleton struct {
	mutex sync.RWMutex
	Cache map[interface{}]map[string]*ChildType
}

var instanceChildTypes *childTypesSingleton
var onceChildTypes sync.Once

func getChildTypes() *childTypesSingleton {
	onceChildTypes.Do(func() {
		instanceChildTypes = &childTypesSingleton{}
	})
	return instanceChildTypes
}

func (s *childTypesSingleton) GetCache() map[interface{}]map[string]*ChildType {
	s.mutex.RLock()
	defer s.mutex.RUnlock()
	return s.Cache
}

func (s *childTypesSingleton) SetCache(cache map[interface{}]map[string]*ChildType) {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	s.Cache = cache
}

func (s *childTypesSingleton) GetCacheEntry(key interface{}) (map[string]*ChildType, bool) {
	s.mutex.RLock()
	defer s.mutex.RUnlock()
	childTypeMap, exists := s.Cache[key]
	return childTypeMap, exists
}

func (s *childTypesSingleton) SetCacheEntry(key interface{}, value map[string]*ChildType) {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	s.Cache[key] = value
}

func (s *childTypesSingleton) ResetCache() {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	s.Cache = make(map[interface{}]map[string]*ChildType)
}

// ChildType structure contains construct details of an object
type ChildType struct {
	ClassModule string
	ClassType   reflect.Type
	IsContainer bool
	Key         string
	KeyFromStr  func(s string) interface{}
}

// ChildrenFields retrieves list of child objects associated to a given interface
func ChildrenFields(cls interface{}) map[string]*ChildType {
	if cls == nil {
		return nil
	}
	var names map[string]*ChildType
	var namesExist bool

	if getChildTypes().Cache == nil {
		getChildTypes().Cache = make(map[interface{}]map[string]*ChildType)
	}

	msgType := reflect.TypeOf(cls)
	inst := getChildTypes()

	if names, namesExist = inst.Cache[msgType.String()]; !namesExist {
		names = make(map[string]*ChildType)

		_, md := desc.ForMessage(cls.(desc.Message))

		// TODO: Do we need to validate MD for nil, panic or exception?
		for _, field := range md.Field {
			if options := field.GetOptions(); options != nil {
				if proto.HasExtension(options, common.E_ChildNode) {
					isContainer := *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED
					meta, _ := proto.GetExtension(options, common.E_ChildNode)

					var keyFromStr func(string) interface{}
					var ct ChildType

					parentType := FindOwnerType(reflect.ValueOf(cls), field.GetName(), 0, false)
					if meta.(*common.ChildNode).GetKey() != "" {
						keyType := FindKeyOwner(reflect.New(parentType).Elem().Interface(), meta.(*common.ChildNode).GetKey(), 0)

						switch keyType.(reflect.Type).Name() {
						case "string":
							keyFromStr = func(s string) interface{} {
								return s
							}
						case "int32":
							keyFromStr = func(s string) interface{} {
								i, _ := strconv.Atoi(s)
								return int32(i)
							}
						case "int64":
							keyFromStr = func(s string) interface{} {
								i, _ := strconv.Atoi(s)
								return int64(i)
							}
						case "uint32":
							keyFromStr = func(s string) interface{} {
								i, _ := strconv.Atoi(s)
								return uint32(i)
							}
						case "uint64":
							keyFromStr = func(s string) interface{} {
								i, _ := strconv.Atoi(s)
								return uint64(i)
							}
						default:
							log.Errorf("Key type not implemented - type: %s\n", keyType.(reflect.Type))
						}
					}

					ct = ChildType{
						ClassModule: parentType.String(),
						ClassType:   parentType,
						IsContainer: isContainer,
						Key:         meta.(*common.ChildNode).GetKey(),
						KeyFromStr:  keyFromStr,
					}

					names[field.GetName()] = &ct
				}
			}
		}

		getChildTypes().Cache[msgType.String()] = names
	} else {
		entry, _ := inst.GetCacheEntry(msgType.String())
		log.Debugf("Cache entry for %s: %+v", msgType.String(), entry)
	}

	return names
}
