package config_manager

import (
	"encoding/json"
	"git.loafle.net/overflow/overflow_probe/agent_api/config_manager"
	log "github.com/cihub/seelog"
	yaml "gopkg.in/yaml.v2"
	"io/ioutil"
	"os"
	"strings"
	"sync"
)

type configManager struct {
	config_manager.ConfigManager // interface implements
	configs                      map[string]*config_manager.Config
	globalConfig                 config_manager.GlobalConfig
}

var _configManager *configManager

func GetInstance() *configManager {
	var once sync.Once
	once.Do(func() {
		_configManager = &configManager{
			configs: make(map[string]*config_manager.Config, 0),
		}
	})

	return _configManager

}

func (c *configManager) stop() {}

func (c *configManager) getConfigPath() string {
	return c.globalConfig.Paths.RootFolder + c.globalConfig.Paths.ConfigFolder
}

func (c *configManager) getContainerPath() string {
	return c.getConfigPath() + "container/"
}

func (c *configManager) getConfigFilePath(config *config_manager.Config) string {
	return c.getContainerPath() + appendSeperator(config.Crawler.Container) + appendSeperator(config.Crawler.Name) + config.Id
}

func appendSeperator(str string) string {
	if strings.LastIndex(str, "/") != len(str)-1 {
		return str + "/"
	}
	return str
}

func (c *configManager) loadGlobalConfig(path string) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
	}
	err = yaml.Unmarshal(data, &c.globalConfig)
	if err != nil {
	}
}

func (c *configManager) loadCrawlerConfigAll() error {

	root := c.getConfigPath()
	files, err := ioutil.ReadDir(root)
	if err != nil {
		log.Error(err)
	}
	for _, file := range files {
		if file.IsDir() == true {
			c.loadCrawlerConfig(root, file.Name())
		}
	}
	return nil
}

func (c *configManager) loadCrawlerConfig(root string, dir string) {

	separator := ""
	if strings.LastIndex(root, "/") != len(root)-1 {
		separator = "/"
	}
	currentDir := root + separator + dir
	files, err := ioutil.ReadDir(currentDir)
	if err != nil {
		log.Error(err)
	}

	for _, file := range files {

		// 디렉터리라면 재귀 / 파일이라면 설정 로드
		if file.IsDir() == true {
			c.loadCrawlerConfig(currentDir, file.Name())
		} else {
			b, err := ioutil.ReadFile(currentDir + separator + file.Name())
			if err != nil {
				log.Error(err)
			}
			var m = config_manager.Config{}
			json.Unmarshal(b, &m)
			c.configs[file.Name()] = &m
		}
	}

}

func (c *configManager) addConfig(tmp string) {
	//for data := range c.addCh {

	path := tmp
	b, err := ioutil.ReadFile(path)
	if err != nil {
		// error process
		log.Error(err)
	}

	// 임시파일을 로드 ,  Config로 변환
	var m = config_manager.Config{}
	err = json.Unmarshal(b, &m)
	if err != nil {
		// error process
		log.Error(err)
	}

	// agent 폴더 / config / crawler / .. / .. / .. / 에 해당하는 파일이 있는지 확인, 있다면 삭제
	// Config 파일로 저장
	savePath := c.getConfigFilePath(&m)
	ioutil.WriteFile(savePath, b, 0644)

	// tempfile remove
	err = os.Remove(path)
	if err != nil {
		// error process
		log.Error(err)
	}

	// Config 맵에 저장
	c.configs[m.Id] = &m

	// notify id
	//err = observer.Notify(messages.SCF_SENSOR_ADD_DONE, m.Id)
	//if err != nil {
	//	continue
	//}
	//}
}

func (c *configManager) removeConfig(id string) {
	//for data := range c.removeCh {
	removeid := id

	// check exists
	config, ok := c.configs[removeid]
	if !ok {
		return
	}

	// 해당 파일 삭제
	path := c.getConfigFilePath(config)
	err := os.Remove(path)
	if err != nil {
		// error check
		log.Error(err)
	}

	// 해당 id 삭제
	delete(c.configs, removeid)

	// notify id
	//err = observer.Notify("TASK_DONE", removeid)
	//if err != nil {
	//	continue
	//}
	//}
}

// implements methods
func (c *configManager) GetGlobalConfig() *config_manager.GlobalConfig {
	return &c.globalConfig
}
func (c *configManager) GetSensorById(id string) *config_manager.Config {
	return c.configs[id]
}
func (c *configManager) GetSensors() map[string]*config_manager.Config {
	return c.configs
}
