// Copyright 2019 Hewlett Packard Enterprise Development LP

// 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 shared

import (
	"errors"
	"sync"

	kdv1 "github.com/bluek8s/kubedirector/pkg/apis/kubedirector/v1beta1"
)

var (
	globalConfig     *kdv1.KubeDirectorConfig
	globalConfigLock sync.RWMutex
)

// GetRequiredSecretPrefix returns a string that must prefix-match a
// secret name in order to allow that secret to be mounted by us. May be
// emptystring if no match required.
func GetRequiredSecretPrefix() string {

	globalConfigLock.RLock()
	defer globalConfigLock.RUnlock()
	if globalConfig != nil && globalConfig.Spec.RequiredSecretPrefix != nil {
		return *globalConfig.Spec.RequiredSecretPrefix
	}
	return ""
}

// GetNativeSystemdSupport extracts the flag definition from the
// globalConfig CR data if present, otherwise returns false
func GetNativeSystemdSupport() bool {

	globalConfigLock.RLock()
	defer globalConfigLock.RUnlock()
	if globalConfig != nil && globalConfig.Spec.NativeSystemdSupport != nil {
		return *globalConfig.Spec.NativeSystemdSupport
	}
	return false
}

// GetDefaultNamingScheme extracts the flag definition from the
// globalConfig CR data if present, otherwise returns false
func GetDefaultNamingScheme() string {

	globalConfigLock.RLock()
	defer globalConfigLock.RUnlock()
	if globalConfig != nil && globalConfig.Spec.DefaultNamingScheme != nil {
		return *globalConfig.Spec.DefaultNamingScheme
	}
	return DefaultNamingScheme
}

// GetDefaultStorageClass extracts the default storage class from the
// globalConfig CR data if present, otherwise returns an empty string
func GetDefaultStorageClass() string {

	globalConfigLock.RLock()
	defer globalConfigLock.RUnlock()
	if globalConfig != nil && globalConfig.Spec.StorageClass != nil {
		return *globalConfig.Spec.StorageClass
	}
	return ""
}

// GetDefaultServiceType extracts the default service type from the
// globalConfig CR data if present, otherwise returns the default
// value (NodePort).
func GetDefaultServiceType() string {

	globalConfigLock.RLock()
	defer globalConfigLock.RUnlock()
	if globalConfig != nil && globalConfig.Spec.ServiceType != nil {
		return *globalConfig.Spec.ServiceType
	}
	return DefaultServiceType
}

// GetSvcClusterDomainBase extracts the default svc cluster domain
// from the globalConfig CR data if present, otherwise returns the default
// value (NodePort).
func GetSvcClusterDomainBase() string {

	globalConfigLock.RLock()
	defer globalConfigLock.RUnlock()
	if globalConfig != nil && globalConfig.Spec.ClusterSvcDomainBase != nil {
		return *globalConfig.Spec.ClusterSvcDomainBase
	}
	return DefaultSvcDomainBase
}

// GetMasterEncryptionKey extracts the master encryption key
// from the globalConfig CR data if present, otherwise return
// an error.
// Note: If config exists the key should be generated by webhook or reconcile
func GetMasterEncryptionKey() (string, error) {

	globalConfigLock.RLock()
	defer globalConfigLock.RUnlock()
	if globalConfig != nil && globalConfig.Spec.MasterEncryptionKey != nil {
		return *globalConfig.Spec.MasterEncryptionKey, nil
	}
	return "", errors.New("masterEncryptionKey must be set in global KD config")
}

// GetPodLabels returns the pod labels specified in the config, or nil if no
// config.
func GetPodLabels() map[string]string {

	globalConfigLock.RLock()
	defer globalConfigLock.RUnlock()
	if globalConfig != nil {
		return globalConfig.Spec.PodLabels
	}
	return nil
}

// GetPodAnnotations returns the pod annotations specified in the config, or
// nil if no config.
func GetPodAnnotations() map[string]string {

	globalConfigLock.RLock()
	defer globalConfigLock.RUnlock()
	if globalConfig != nil {
		return globalConfig.Spec.PodAnnotations
	}
	return nil
}

// GetServiceLabels returns the service labels specified in the config, or nil
// if no config.
func GetServiceLabels() map[string]string {

	globalConfigLock.RLock()
	defer globalConfigLock.RUnlock()
	if globalConfig != nil {
		return globalConfig.Spec.ServiceLabels
	}
	return nil
}

// GetServiceAnnotations returns the service annotations specified in the
// config, or nil if no config.
func GetServiceAnnotations() map[string]string {

	globalConfigLock.RLock()
	defer globalConfigLock.RUnlock()
	if globalConfig != nil {
		return globalConfig.Spec.ServiceAnnotations
	}
	return nil
}

// GetBackupClusterStatus extracts the flag definition from the
// globalConfig CR data if present, otherwise returns false.
func GetBackupClusterStatus() bool {

	globalConfigLock.RLock()
	defer globalConfigLock.RUnlock()
	if globalConfig != nil && globalConfig.Spec.BackupClusterStatus != nil {
		return *globalConfig.Spec.BackupClusterStatus
	}
	return false
}

// GetAllowRestoreWithoutConnections extracts the flag definition from the
// globalConfig CR data if present, otherwise returns false.
func GetAllowRestoreWithoutConnections() bool {

	globalConfigLock.RLock()
	defer globalConfigLock.RUnlock()
	if globalConfig != nil && globalConfig.Spec.AllowRestoreWithoutConnections != nil {
		return *globalConfig.Spec.AllowRestoreWithoutConnections
	}
	return false
}

// GetForceSharedMemorySizeSupport extracts the boolean-or-nil value from the
// globalConfig CR data if present, otherwise returns nil.
func GetForceSharedMemorySizeSupport() *bool {

	globalConfigLock.RLock()
	defer globalConfigLock.RUnlock()
	if globalConfig != nil {
		return globalConfig.Spec.ForceSharedMemorySizeSupport
	}
	return nil
}

// RemoveGlobalConfig removes the current globalConfig
func RemoveGlobalConfig() {

	globalConfigLock.Lock()
	defer globalConfigLock.Unlock()
	globalConfig = nil
}

// AddGlobalConfig adds the globalConfig CR data
func AddGlobalConfig(config *kdv1.KubeDirectorConfig) {

	globalConfigLock.Lock()
	defer globalConfigLock.Unlock()
	globalConfig = config
}
