// Copyright (c) 2022 Tigera, Inc. All rights reserved.
//
// 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 multiversion

import (
	"github.com/projectcalico/calico/felix/bpf/maps"
	v2 "github.com/projectcalico/calico/felix/bpf/mock/multiversion/v2"
	v3 "github.com/projectcalico/calico/felix/bpf/mock/multiversion/v3"
	v4 "github.com/projectcalico/calico/felix/bpf/mock/multiversion/v4"
	v5 "github.com/projectcalico/calico/felix/bpf/mock/multiversion/v5"
)

func GetMapParams(version int) maps.MapParameters {
	switch version {
	case 2:
		return v2.MockMapParams
	case 3:
		return v3.MockMapParams
	case 4:
		return v4.MockMapParams
	case 5:
		return v5.MockMapParams
	default:
		return v5.MockMapParams
	}
}

func GetKeyValueTypeFromVersion(version int, k, v []byte) (maps.Upgradable, maps.Upgradable) {
	switch version {
	case 2:
		var key v2.Key
		var val v2.Value
		copy(key[:], k)
		copy(val[:], v)
		return key, val
	case 3:
		var key v3.Key
		var val v3.Value
		copy(key[:], k)
		copy(val[:], v)
		return key, val
	case 4:
		var key v4.Key
		var val v4.Value
		copy(key[:], k)
		copy(val[:], v)
		return key, val
	case 5:
		var key v5.Key
		var val v5.Value
		copy(key[:], k)
		copy(val[:], v)
		return key, val
	default:
		var key v5.Key
		var val v5.Value
		copy(key[:], k)
		copy(val[:], v)
		return key, val
	}
}

func MapV2(maxEntries int) maps.Map {
	mockParams := v2.MockMapParams
	if maxEntries > 0 {
		mockParams.MaxEntries = maxEntries
	}
	b := maps.NewPinnedMap(mockParams)
	b.(*maps.PinnedMap).UpgradeFn = maps.Upgrade
	b.(*maps.PinnedMap).GetMapParams = GetMapParams
	b.(*maps.PinnedMap).KVasUpgradable = GetKeyValueTypeFromVersion
	return b
}

func MapV3(maxEntries int) maps.Map {
	mockParams := v3.MockMapParams
	if maxEntries > 0 {
		mockParams.MaxEntries = maxEntries
	}
	b := maps.NewPinnedMap(mockParams)
	b.(*maps.PinnedMap).UpgradeFn = maps.Upgrade
	b.(*maps.PinnedMap).GetMapParams = GetMapParams
	b.(*maps.PinnedMap).KVasUpgradable = GetKeyValueTypeFromVersion
	return b
}

func MapV4(maxEntries int) maps.Map {
	mockParams := v4.MockMapParams
	if maxEntries > 0 {
		mockParams.MaxEntries = maxEntries
	}
	b := maps.NewPinnedMap(mockParams)
	b.(*maps.PinnedMap).UpgradeFn = maps.Upgrade
	b.(*maps.PinnedMap).GetMapParams = GetMapParams
	b.(*maps.PinnedMap).KVasUpgradable = GetKeyValueTypeFromVersion
	return b
}

func MapV5(maxEntries int) maps.Map {
	mockParams := v5.MockMapParams
	if maxEntries > 0 {
		mockParams.MaxEntries = maxEntries
	}
	b := maps.NewPinnedMap(mockParams)
	b.(*maps.PinnedMap).UpgradeFn = maps.Upgrade
	b.(*maps.PinnedMap).GetMapParams = GetMapParams
	b.(*maps.PinnedMap).KVasUpgradable = GetKeyValueTypeFromVersion
	return b
}
