package config

import (
	"flag"
	"io"
	"os"
	"sync"

	"code.justin.tv/release/libforerunner/pkg/interchange"
)

// Config is the manager of the config state. It stores the default values,
// parsed flags and env. In addition it handles merging the configs and
// actually loading the config struct.
type Config struct {
	flagVars        map[string]*flagValue
	setDefaultsOnce *sync.Once
	currentConfig   interchange.EntrySet
	fields          []string
}

func NewConfig() (*Config, error) {
	return &Config{
		flagVars:        map[string]*flagValue{},
		setDefaultsOnce: &sync.Once{},
		currentConfig:   make(interchange.EntrySet),
	}, nil
}

func (c *Config) SetDefaults(v interface{}) error {
	var err error

	c.setDefaultsOnce.Do(func() {
		err = c.parseStruct(v)
		flag.Parse()
	})

	return err
}

func (c *Config) GetConfig(v interface{}, entries interchange.EntrySet) error {
	if err := c.setStruct(v, entries); err != nil {
		return err
	}

	return nil
}

func (c *Config) Write(f io.Writer) error {
	return c.write(f)
}

func (c *Config) Print() error {
	return c.write(os.Stdout)
}
