func (c *configImpl) GetFilePath() string {
	return c.fileName
}
GetFilePath returns the path (file name) of the config json
package config
import (
	"errors"
	"fmt"
	"os"
	"regexp"
	"strings"
	"github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/api"
	"github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/environment"
	"github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/util"
	"github.com/spf13/afero"
)
type Config interface {
	GetConfigForEnvironment(environment environment.Environment, dict map[string]api.DynatraceEntity) ([]byte, error)
	IsSkipDeployment(environment environment.Environment) bool
	GetApi() api.Api
	GetObjectNameForEnvironment(environment environment.Environment, dict map[string]api.DynatraceEntity) (string, error)
	HasDependencyOn(config Config) bool
	GetFilePath() string
	GetFullQualifiedId() string
	GetType() string
	GetMeIdsOfEnvironment(environment environment.Environment) map[string]map[string]string
	GetId() string
	GetProject() string
	GetProperties() map[string]map[string]string
	GetRequiredByConfigIdList() []string
	addToRequiredByConfigIdList(config string)
}
var dependencySuffixes = []string{".id", ".name"}
const skipConfigDeploymentParameter = "skipDeployment"
type configImpl struct {
	id                  string
	project             string
	properties          map[string]map[string]string
	template            util.Template
	api                 api.Api
	objectName          string
	fileName            string
	requiredByConfigIds []string
}
type ConfigFactory interface {
	NewConfig(fs afero.Fs, id string, project string, fileName string, properties map[string]map[string]string, api api.Api) (Config, error)
}
type configFactoryImpl struct{}
func NewConfigFactory() ConfigFactory {
	return &configFactoryImpl{}
}
func NewConfig(fs afero.Fs, id string, project string, fileName string, properties map[string]map[string]string, api api.Api) (Config, error) {
	template, err := util.NewTemplate(fs, fileName)
	if err != nil {
		return nil, fmt.Errorf("loading config %s failed with %s", project+string(os.PathSeparator)+id, err)
	}
	return newConfig(id, project, template, filterProperties(id, properties), api, fileName), nil
}
func NewConfigForDelete(id string, fileName string, properties map[string]map[string]string, api api.Api) Config {
	return newConfig(id, "", nil, filterProperties(id, properties), api, fileName)
}
func newConfig(id string, project string, template util.Template, properties map[string]map[string]string, api api.Api, fileName string) Config {
	return &configImpl{
		id:         id,
		project:    project,
		template:   template,
		properties: properties,
		api:        api,
		fileName:   fileName,
	}
}
func filterProperties(id string, properties map[string]map[string]string) map[string]map[string]string {
	result := make(map[string]map[string]string)
	configNameInID := strings.Split(id, ".")[0]
	for key, value := range properties {
		configNameInKey := strings.Split(key, ".")[0]
		if strings.HasPrefix(key, id) && configNameInID == configNameInKey {
			result[key] = value
		}
	}
	return result
}
func (c *configImpl) IsSkipDeployment(environment environment.Environment) bool {
	environmentKey := c.id + "." + environment.GetId()
	if properties, ok := c.properties[environmentKey]; ok {
		if value, ok := properties[skipConfigDeploymentParameter]; ok {
			return strings.EqualFold(value, "true")
		}
	}
	environmentGroupKey := c.id + "." + environment.GetGroup()
	if properties, ok := c.properties[environmentGroupKey]; ok {
		if value, ok := properties[skipConfigDeploymentParameter]; ok {
			return strings.EqualFold(value, "true")
		}
	}
	if properties, ok := c.properties[c.id]; ok {
		if value, ok := properties[skipConfigDeploymentParameter]; ok {
			return strings.EqualFold(value, "true")
		}
	}
	return false
}
func (c *configImpl) GetConfigForEnvironment(environment environment.Environment, dict map[string]api.DynatraceEntity) ([]byte, error) {
	filtered := copyProperties(c.properties)
	if len(filtered) == 0 {
		json, err := c.template.ExecuteTemplate(map[string]string{})
		if err != nil {
			return nil, err
		}
		err = util.ValidateJson(json, c.GetFilePath())
		if err != nil {
			return nil, err
		}
		return []byte(json), nil
	}
	environmentGroupKey := c.id + "." + environment.GetGroup()
	environmentKey := c.id + "." + environment.GetId()
	for _, environment := range []string{environmentGroupKey, environmentKey} {
		filteredForEnvironment := filterProperties(environment, c.properties)
		if len(filteredForEnvironment) > 0 {
			for key, value := range filteredForEnvironment[environment] {
				_, ok := filtered[c.id]
				if !ok {
					filtered[c.id] = make(map[string]string)
				}
				filtered[c.id][key] = value
			}
		}
	}
	filtered, err := c.replaceDependencies(filtered, dict)
	if err != nil {
		return nil, err
	}
	json, err := c.template.ExecuteTemplate(filtered[c.id])
	if err != nil {
		return nil, err
	}
	json = strings.ReplaceAll(json, "&#34;", "\"")
	err = util.ValidateJson(json, c.GetFilePath())
	if err != nil {
		return nil, err
	}
	return []byte(json), nil
}
func (c *configImpl) GetObjectNameForEnvironment(environment environment.Environment, dict map[string]api.DynatraceEntity) (string, error) {
	environmentKey := c.id + "." + environment.GetId()
	environmentGroupKey := c.id + "." + environment.GetGroup()
	name := c.properties[environmentKey]["name"]
	if name == "" {
		name = c.properties[environmentGroupKey]["name"]
	}
	if name == "" {
		name = c.properties[c.id]["name"]
	}
	if name == "" {
		return "", fmt.Errorf("could not find name property in config %s, please make sure `name` is defined", c.GetFullQualifiedId())
	}
	if isDependency(name) {
		return c.parseDependency(name, dict)
	}
	return name, nil
}
func copyProperties(original map[string]map[string]string) map[string]map[string]string {
	copies := make(map[string]map[string]string)
	for k, v := range original {
		copies[k] = make(map[string]string)
		for key, val := range v {
			copies[k][key] = val
		}
	}
	return copies
}
func (c *configImpl) replaceDependencies(data map[string]map[string]string, dict map[string]api.DynatraceEntity) (map[string]map[string]string, error) {
	var err error
	for k, v := range data {
		for k2, v2 := range v {
			if isDependency(v2) {
				data[k][k2], err = c.parseDependency(v2, dict)
				if err != nil {
					return data, err
				}
			}
		}
	}
	return data, nil
}
func (c *configImpl) parseDependency(dependency string, dict map[string]api.DynatraceEntity) (string, error) {
	if strings.HasPrefix(dependency, string(os.PathSeparator)) {
		dependency = dependency[1:]
	}
	id, access, err := splitDependency(dependency)
	if err != nil {
		return "", err
	}
	dtObject, ok := dict[id]
	if !ok {
		return "", errors.New("Id '" + id + "' was not available. Please make sure the reference exists.")
	}
	switch access {
	case "id":
		return dtObject.Id, nil
	case "name":
		return dtObject.Name, nil
	default:
		return "", fmt.Errorf("accessor %s not found for dependcy id %s", access, id)
	}
}
func isDependency(property string) bool {
	for _, suffix := range dependencySuffixes {
		if strings.HasSuffix(property, suffix) {
			return true
		}
	}
	return false
}
func splitDependency(property string) (id string, access string, err error) {
	split := strings.Split(property, ".")
	if len(split) < 2 {
		return "", "", fmt.Errorf("property %s cannot be split", property)
	}
	firstPart, secondPart := split[0], split[1]
	if len(split) > 2 {
		util.Log.Debug("\t\t\tproperty %s contains more than the single expected `.` separator, using last separator for split", property)
		secondPart = split[len(split)-1]
		firstPart = strings.TrimSuffix(property, "."+secondPart)
	}
	return firstPart, secondPart, nil
}
func (c *configImpl) GetApi() api.Api {
	return c.api
}
func (c *configImpl) GetRequiredByConfigIdList() []string {
	return c.requiredByConfigIds
}
func (c *configImpl) addToRequiredByConfigIdList(config string) {
	c.requiredByConfigIds = append(c.requiredByConfigIds, config)
}
func (c *configImpl) GetType() string {
	return c.api.GetId()
}
func (c *configImpl) GetId() string {
	return c.id
}
func (c *configImpl) GetProject() string {
	return c.project
}
func (c *configImpl) GetProperties() map[string]map[string]string {
	return c.properties
}
func (c *configImpl) HasDependencyOn(config Config) bool {
	for _, v := range c.properties {
		for _, value := range v {
			valueIndex := strings.LastIndex(value, ".")
			if valueIndex != -1 && isDependency(value[valueIndex:]) {
				valueString := value[:valueIndex]
				if strings.HasPrefix(valueString, string(os.PathSeparator)) {
					valueString = valueString[1:]
				}
				if len(strings.Split(valueString, string(os.PathSeparator))) < 3 && c.GetProject() == config.GetProject() {
					if valueString == strings.Join([]string{config.GetType(), config.GetId()}, string(os.PathSeparator)) {
						config.addToRequiredByConfigIdList(c.GetFullQualifiedId())
						return true
					}
				}
				pathPart := []string{config.GetProject(), config.GetType(), config.GetId()}
				configFullPath := strings.Join(pathPart, string(os.PathSeparator))
				if strings.HasSuffix(configFullPath, valueString) {
					config.addToRequiredByConfigIdList(c.GetFullQualifiedId())
					return true
				}
			}
		}
	}
	return false
}