/*
Copyright 2015 The Kubernetes Authors.

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 unstructured

import (
	"bytes"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

var _ runtime.Unstructured = &UnstructuredList{}
var _ metav1.ListInterface = &UnstructuredList{}

// UnstructuredList allows lists that do not have Golang structs
// registered to be manipulated generically. This can be used to deal
// with the API lists from a plug-in.
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:deepcopy-gen=true
type UnstructuredList struct {
	Object map[string]interface{}

	// Items is a list of unstructured objects.
	Items []Unstructured `json:"items"`
}

func (u *UnstructuredList) GetObjectKind() schema.ObjectKind { return u }

func (u *UnstructuredList) IsList() bool { return true }

func (u *UnstructuredList) EachListItem(fn func(runtime.Object) error) error {
	for i := range u.Items {
		if err := fn(&u.Items[i]); err != nil {
			return err
		}
	}
	return nil
}

// NewEmptyInstance returns a new instance of the concrete type containing only kind/apiVersion and no other data.
// This should be called instead of reflect.New() for unstructured types because the go type alone does not preserve kind/apiVersion info.
func (u *UnstructuredList) NewEmptyInstance() runtime.Unstructured {
	out := new(UnstructuredList)
	if u != nil {
		out.SetGroupVersionKind(u.GroupVersionKind())
	}
	return out
}

// UnstructuredContent returns a map contain an overlay of the Items field onto
// the Object field. Items always overwrites overlay.
func (u *UnstructuredList) UnstructuredContent() map[string]interface{} {
	out := make(map[string]interface{}, len(u.Object)+1)

	// shallow copy every property
	for k, v := range u.Object {
		out[k] = v
	}

	items := make([]interface{}, len(u.Items))
	for i, item := range u.Items {
		items[i] = item.UnstructuredContent()
	}
	out["items"] = items
	return out
}

// SetUnstructuredContent obeys the conventions of List and keeps Items and the items
// array in sync. If items is not an array of objects in the incoming map, then any
// mismatched item will be removed.
func (obj *UnstructuredList) SetUnstructuredContent(content map[string]interface{}) {
	obj.Object = content
	if content == nil {
		obj.Items = nil
		return
	}
	items, ok := obj.Object["items"].([]interface{})
	if !ok || items == nil {
		items = []interface{}{}
	}
	unstructuredItems := make([]Unstructured, 0, len(items))
	newItems := make([]interface{}, 0, len(items))
	for _, item := range items {
		o, ok := item.(map[string]interface{})
		if !ok {
			continue
		}
		unstructuredItems = append(unstructuredItems, Unstructured{Object: o})
		newItems = append(newItems, o)
	}
	obj.Items = unstructuredItems
	obj.Object["items"] = newItems
}

func (u *UnstructuredList) DeepCopy() *UnstructuredList {
	if u == nil {
		return nil
	}
	out := new(UnstructuredList)
	*out = *u
	out.Object = runtime.DeepCopyJSON(u.Object)
	out.Items = make([]Unstructured, len(u.Items))
	for i := range u.Items {
		u.Items[i].DeepCopyInto(&out.Items[i])
	}
	return out
}

// MarshalJSON ensures that the unstructured list object produces proper
// JSON when passed to Go's standard JSON library.
func (u *UnstructuredList) MarshalJSON() ([]byte, error) {
	var buf bytes.Buffer
	err := UnstructuredJSONScheme.Encode(u, &buf)
	return buf.Bytes(), err
}

// UnmarshalJSON ensures that the unstructured list object properly
// decodes JSON when passed to Go's standard JSON library.
func (u *UnstructuredList) UnmarshalJSON(b []byte) error {
	_, _, err := UnstructuredJSONScheme.Decode(b, nil, u)
	return err
}

func (u *UnstructuredList) GetAPIVersion() string {
	return getNestedString(u.Object, "apiVersion")
}

func (u *UnstructuredList) SetAPIVersion(version string) {
	u.setNestedField(version, "apiVersion")
}

func (u *UnstructuredList) GetKind() string {
	return getNestedString(u.Object, "kind")
}

func (u *UnstructuredList) SetKind(kind string) {
	u.setNestedField(kind, "kind")
}

func (u *UnstructuredList) GetResourceVersion() string {
	return getNestedString(u.Object, "metadata", "resourceVersion")
}

func (u *UnstructuredList) SetResourceVersion(version string) {
	u.setNestedField(version, "metadata", "resourceVersion")
}

func (u *UnstructuredList) GetSelfLink() string {
	return getNestedString(u.Object, "metadata", "selfLink")
}

func (u *UnstructuredList) SetSelfLink(selfLink string) {
	u.setNestedField(selfLink, "metadata", "selfLink")
}

func (u *UnstructuredList) GetContinue() string {
	return getNestedString(u.Object, "metadata", "continue")
}

func (u *UnstructuredList) SetContinue(c string) {
	u.setNestedField(c, "metadata", "continue")
}

func (u *UnstructuredList) GetRemainingItemCount() *int64 {
	return getNestedInt64Pointer(u.Object, "metadata", "remainingItemCount")
}

func (u *UnstructuredList) SetRemainingItemCount(c *int64) {
	if c == nil {
		RemoveNestedField(u.Object, "metadata", "remainingItemCount")
	} else {
		u.setNestedField(*c, "metadata", "remainingItemCount")
	}
}

func (u *UnstructuredList) SetGroupVersionKind(gvk schema.GroupVersionKind) {
	u.SetAPIVersion(gvk.GroupVersion().String())
	u.SetKind(gvk.Kind)
}

func (u *UnstructuredList) GroupVersionKind() schema.GroupVersionKind {
	gv, err := schema.ParseGroupVersion(u.GetAPIVersion())
	if err != nil {
		return schema.GroupVersionKind{}
	}
	gvk := gv.WithKind(u.GetKind())
	return gvk
}

func (u *UnstructuredList) setNestedField(value interface{}, fields ...string) {
	if u.Object == nil {
		u.Object = make(map[string]interface{})
	}
	SetNestedField(u.Object, value, fields...)
}
