package xyaml

// Map defines a map type that uses strings as key value.
// The map implements the Unmarshaller interface to convert
// the unmarshalled map keys type from interface{} to string.
type Map map[string]interface{}

func (m *Map) UnmarshalYAML(unmarshal func(interface{}) error) error {
	var raw map[interface{}]interface{}

	if err := unmarshal(&raw); err != nil {
		return err
	}

	*m = convertMapKeys(raw)

	return nil
}

func convertSlice(raw []interface{}) []interface{} {
	if len(raw) == 0 {
		return raw
	}

	if _, ok := raw[0].(map[interface{}]interface{}); !ok {
		return raw
	}

	values := make([]interface{}, len(raw))
	for i, v := range raw {
		values[i] = convertMapKeys(v.(map[interface{}]interface{}))
	}

	return values
}

func convertMapKeys(raw map[interface{}]interface{}) map[string]interface{} {
	m := make(map[string]interface{})

	for k, v := range raw {
		if value, _ := v.(map[interface{}]interface{}); value != nil {
			// Convert map keys to string
			v = convertMapKeys(value)
		} else if values, _ := v.([]interface{}); values != nil {
			// Make sure that maps inside slices also use strings as key
			v = convertSlice(values)
		}

		m[k.(string)] = v
	}

	return m
}
