package icsconf

import (
	"encoding/xml"
	"fmt"
	"os"
	"strings"
	"sync"

	"gitlab.com/ics_cinnamon/voiceStatistics/icserror"
)

type IcsConfig struct {
	XMLName    xml.Name   `xml:"ICSVS"`
	Version    string     `xml:"version,attr"`
	InfoConfig InfoConfig `xml:"INFO"`
	LogConfig  LogConfig  `xml:"LOG"`
	Linger     int        `xml:"LINGER"`
	Target     Target     `xml:"TARGET"`
	HomeDir    string
}

type InfoConfig struct {
	Product  string `xml:"PRODUCT"`
	TenentID string `xml:"TENENTID"`
	ServerID int    `xml:"SERVERID"`
	ServerIP string `xml:"SERVERIP"`
}

type Target struct {
	Transport  string `xml:"transport,attr"`
	TargetPort int    `xml:"port,attr"`
}

type LogConfig struct {
	Path         string       `xml:"PATH"`
	Disklimit    int          `xml:"DISKLIMIT"`
	Level        string       `xml:"LEVEL"`
	Output       string       `xml:"OUTPUT"`
	RotateConfig RotateConfig `xml:"ROTATE"`
	DelConfig    DelConfig    `xml:"DELPERIOD"`
	HomeDir      string
}

type DelConfig struct {
	DelDay  int `xml:"day,attr"`
	DelHour int `xml:"hour,attr"`
}

type RotateConfig struct {
	Size  string `xml:"size,attr"`
	Num   string `xml:"num,attr"`
	YesNo string `xml:"yesno,attr"`
}

var gIcsConfig *IcsConfig
var onceConfig sync.Once

func OpenConfig(ConfigFileName string, homeDir string) (*IcsConfig, *icserror.IcsError) {
	var gerr *icserror.IcsError = nil

	onceConfig.Do(func() {
		fi, err := os.Open(ConfigFileName)
		if err != nil {
			icserror.ICSERRCONFOpenFile.SetError(err)
			gerr = icserror.ICSERRCONFOpenFile
			return
		}
		defer fi.Close()

		FI, _ := os.Stat(ConfigFileName)
		FileLength := FI.Size()

		configdata := make([]byte, FileLength)
		cnt, err := fi.Read(configdata)
		if cnt == 0 || err != nil {
			icserror.ICSERRCONFFileNotFound.SetError(err)
			gerr = icserror.ICSERRCONFFileNotFound
			return
		}

		gIcsConfig = &IcsConfig{}
		gIcsConfig.HomeDir = homeDir

		err = xml.Unmarshal([]byte(configdata), gIcsConfig)
		if err != nil {
			icserror.ICSERRCONFUnmarshal.SetError(err)
			gerr = icserror.ICSERRCONFUnmarshal
			gIcsConfig = nil
			return
		}

		if !strings.HasPrefix(gIcsConfig.LogConfig.Path, "/") {
			gIcsConfig.LogConfig.Path = fmt.Sprintf("%s/%s", homeDir, gIcsConfig.LogConfig.Path)
		}
		//default setting
		if gIcsConfig.LogConfig.DelConfig.DelDay == 0 {
			gIcsConfig.LogConfig.DelConfig.DelHour = 90
		}
		if gIcsConfig.LogConfig.DelConfig.DelHour == 0 {
			gIcsConfig.LogConfig.DelConfig.DelHour = 2
		}

		gIcsConfig.LogConfig.HomeDir = homeDir
	})

	if gerr != nil {
		return nil, gerr
	}

	return gIcsConfig, nil
}

func ReloadConfig(ConfigFileName string, homeDir string) (*IcsConfig, *icserror.IcsError) {
	fi, err := os.Open(ConfigFileName)
	if err != nil {
		icserror.ICSERRCONFOpenFile.SetError(err)
		return nil, icserror.ICSERRCONFOpenFile
	}
	defer fi.Close()

	FI, _ := os.Stat(ConfigFileName)
	FileLength := FI.Size()

	configdata := make([]byte, FileLength)
	cnt, err := fi.Read(configdata)
	if cnt == 0 || err != nil {
		icserror.ICSERRCONFFileNotFound.SetError(err)
		return nil, icserror.ICSERRCONFFileNotFound
	}

	gIcsConfig = &IcsConfig{}
	gIcsConfig.HomeDir = homeDir

	err = xml.Unmarshal([]byte(configdata), gIcsConfig)
	if err != nil {
		icserror.ICSERRCONFUnmarshal.SetError(err)
		return nil, icserror.ICSERRCONFUnmarshal
	}

	if !strings.HasPrefix(gIcsConfig.LogConfig.Path, "/") {
		gIcsConfig.LogConfig.Path = fmt.Sprintf("%s/%s", homeDir, gIcsConfig.LogConfig.Path)
	}
	//default setting
	if gIcsConfig.LogConfig.DelConfig.DelDay == 0 {
		gIcsConfig.LogConfig.DelConfig.DelHour = 90
	}
	if gIcsConfig.LogConfig.DelConfig.DelHour == 0 {
		gIcsConfig.LogConfig.DelConfig.DelHour = 2
	}

	gIcsConfig.LogConfig.HomeDir = homeDir

	return gIcsConfig, nil
}

func (c IcsConfig) GetHomeDir() string {
	return c.HomeDir
}

func (c IcsConfig) GetChannelID() string {
	return c.InfoConfig.TenentID
}

func (c IcsConfig) GetServerID() int {
	return c.InfoConfig.ServerID
}

//from LogConfig struct
func (c LogConfig) GetHomeDir() string {
	return c.HomeDir
}

func (c *IcsConfig) SetHomeDir(homeDir string) {
	c.HomeDir = homeDir
}

func GetIcsConfig() *IcsConfig {
	return gIcsConfig
}

func (c IcsConfig) ShowConfig() string {
	fmt.Printf("Log Level : %s\n", c.LogConfig.Level)
	fmt.Printf("Log Path : %s\n", c.LogConfig.Path)
	fmt.Printf("Log Disk Space Size : %dMB\n", c.LogConfig.Disklimit)
	fmt.Printf("Log Del Day : %d\n", c.LogConfig.DelConfig.DelDay)
	fmt.Printf("Log Del Hour : %d\n", c.LogConfig.DelConfig.DelHour)
	fmt.Printf("Log Output : %s\n", c.LogConfig.Output)
	fmt.Printf("Log Rotate : %s\n", c.LogConfig.RotateConfig.YesNo)
	fmt.Printf("Log Rotate File Size : %sMB\n", c.LogConfig.RotateConfig.Size)
	fmt.Printf("Log Rotate File Number : %s\n\n", c.LogConfig.RotateConfig.Num)
	fmt.Printf("Log Del Day : %d\n", c.LogConfig.DelConfig.DelDay)
	fmt.Printf("Log Del Hour : %d\n", c.LogConfig.DelConfig.DelHour)
	/*
		for iter := 0; iter < len(c.AgentConfig); iter++ {
			fmt.Printf("==========================\n")
			fmt.Printf("Agent Name: %s, Use? %s\n", c.AgentConfig[iter].Name, c.AgentConfig[iter].Value)
			fmt.Printf("Agent Media media: %s\n", c.AgentConfig[iter].MediaConfig.Media)
			fmt.Printf("Agent Media Port: %d\n", c.AgentConfig[iter].MediaConfig.Port)
			fmt.Printf("Agent Media Format: %s\n", c.AgentConfig[iter].MediaConfig.Format)
			fmt.Printf("Register value: %s\n", c.AgentConfig[iter].RegisterConfig.RegisterValue)
			fmt.Printf("Register Transport: %s\n", c.AgentConfig[iter].RegisterConfig.RegisterTransport)
			fmt.Printf("Register Expire: %d\n", c.AgentConfig[iter].RegisterConfig.RegisterExpire)
			fmt.Printf("Register Username: %s\n", c.AgentConfig[iter].RegisterConfig.RegisterUserName)
			fmt.Printf("Options Use? %s\n", c.AgentConfig[iter].OptionsConfig.OptionsValue)
			fmt.Printf("Options Interval: %d\n\n", c.AgentConfig[iter].OptionsConfig.OptionsInterval)
		}
	*/

	/*
		confmsg += fmt.Sprintf("iComsys Voice Agent Address : %s[%d:%d]\n",
			c.VoiceAgentConfig.AgentAddr.VoiceAgentIP, c.VoiceAgentConfig.AgentAddr.CallSignalPort, c.VoiceAgentConfig.AgentAddr.VoicePort)
	*/
	confmsg := fmt.Sprintf("Log Level : %s\n", c.LogConfig.Level)
	confmsg += fmt.Sprintf("Log Path : %s\n", c.LogConfig.Path)
	confmsg += fmt.Sprintf("Log Disk Space Size : %dMB\n", c.LogConfig.Disklimit)
	confmsg += fmt.Sprintf("Log Del Day : %d\n", c.LogConfig.DelConfig.DelDay)
	confmsg += fmt.Sprintf("Log Del Hour : %d\n", c.LogConfig.DelConfig.DelHour)
	confmsg += fmt.Sprintf("Log Output : %s\n", c.LogConfig.Output)
	confmsg += fmt.Sprintf("Log Rotate : %s\n", c.LogConfig.RotateConfig.YesNo)
	confmsg += fmt.Sprintf("Log Rotate File Size : %sMB\n", c.LogConfig.RotateConfig.Size)
	confmsg += fmt.Sprintf("Log Rotate File Number : %s\n\n", c.LogConfig.RotateConfig.Num)

	return confmsg
}

//////////////////////////////////////////
/////////////// simulator ////////////////
//////////////////////////////////////////

type SimConfig struct {
	XMLName           xml.Name          `xml:"SIMVC"`
	Version           string            `xml:"version,attr"`
	IsCaller          string            `xml:"ISCALLER"`
	Repeat            int               `xml:"REPEAT"`
	Channels          int               `xml:"CHANNELS"`
	TargetPhoneConfig TargetPhoneConfig `xml:"TARGET"`
	SimPhoneConfig    SimPhoneConfig    `xml:"SIM"`
	InOut             string            `xml:"INOUT"`
	LogConfig         LogConfig         `xml:"LOG"`
	RegiCount         int               `xml:"REGICOUNT"`
	MediaConfig       []SimMediaConfig  `xml:"MEDIA"`
	HomeDir           string
}

type TargetPhoneConfig struct {
	TargetIP string `xml:"ip,attr"`
	TSIPPort int    `xml:"sipport,attr"`
	TRTPPort int    `xml:"rtpport,attr"`
}

type SimPhoneConfig struct {
	MYIP    string `xml:"myip,attr"`
	SIPPort int    `xml:"sipport,attr"`
	RTPPort int    `xml:"rtpport,attr"`
}

type SimMediaConfig struct {
	Media  string `xml:"m,attr"`
	Port   int    `xml:"port,attr"`
	Format string `xml:"format,attr"`
}

type SimScenarioConfig struct {
	XMLName       xml.Name `xml:"SIMSCEN"`
	Version       string   `xml:"version,attr"`
	ScenarioCount int      `xml:"SCENARIOCOUNT"`
	SipOrder      SipOrder `xml:"ORDER"`
}

type SipOrder struct {
	Order    []string `xml:"METHOD"`
	StopTime int      `xml:"STOPTIME"`
}

func OpenSimConfig(ConfigFileName string, homeDir string) (*SimConfig, *icserror.IcsError) {
	fi, err := os.Open(ConfigFileName)
	if err != nil {
		icserror.ICSERRCONFOpenFile.SetError(err)
		return nil, icserror.ICSERRCONFOpenFile
	}
	defer fi.Close()

	FI, _ := os.Stat(ConfigFileName)
	FileLength := FI.Size()

	configdata := make([]byte, FileLength)
	cnt, err := fi.Read(configdata)
	if cnt == 0 || err != nil {
		icserror.ICSERRCONFFileNotFound.SetError(err)
		return nil, icserror.ICSERRCONFFileNotFound
	}

	conf := SimConfig{}
	conf.HomeDir = homeDir

	err = xml.Unmarshal([]byte(configdata), &conf)
	if err != nil {
		icserror.ICSERRCONFUnmarshal.SetError(err)
		return nil, icserror.ICSERRCONFUnmarshal
	}

	/*
		fmt.Printf("Configuration> xml name: %s, version: %s\n", conf.XMLName.Local, conf.Version)
		fmt.Println(conf.LicenseConfig)
		fmt.Println(conf.LogConfig)
		fmt.Println(conf.LogConfig.RotateConfig)
		fmt.Println(conf.CaptureConfig)
	*/

	conf.LogConfig.HomeDir = homeDir

	gSimConfig = &conf

	return &conf, nil
}

func OpenSimScenarioConfig(ConfigFileName string, homeDir string) (*SimScenarioConfig, *icserror.IcsError) {
	fi, err := os.Open(ConfigFileName)
	if err != nil {
		icserror.ICSERRCONFOpenFile.SetError(err)
		return nil, icserror.ICSERRCONFOpenFile
	}
	defer fi.Close()

	FI, _ := os.Stat(ConfigFileName)
	FileLength := FI.Size()

	configdata := make([]byte, FileLength)
	cnt, err := fi.Read(configdata)
	if cnt == 0 || err != nil {
		icserror.ICSERRCONFFileNotFound.SetError(err)
		return nil, icserror.ICSERRCONFFileNotFound
	}

	SimScenarioConf := SimScenarioConfig{}

	err = xml.Unmarshal([]byte(configdata), &SimScenarioConf)
	if err != nil {
		icserror.ICSERRCONFUnmarshal.SetError(err)
		return nil, icserror.ICSERRCONFUnmarshal
	}

	fmt.Println()

	gSimScenarioConfig = &SimScenarioConf
	return &SimScenarioConf, nil
}

func (c SimConfig) GetSimChannels() int {
	return c.Channels
}

func (c SimConfig) GetSimTargetIP() string {
	return c.TargetPhoneConfig.TargetIP
}

func (c SimConfig) GetSimTargetPort() int {
	return c.TargetPhoneConfig.TSIPPort
}

func (c SimConfig) ShowConfig() string {
	fmt.Printf("Home Path : %s\n", c.HomeDir)
	fmt.Printf("INOUT : %s\n", c.InOut)
	fmt.Printf("Channel number : %d\n", c.Channels)
	fmt.Printf("Repeat number : %d\n", c.Repeat)
	fmt.Printf("iComsys SIM Phone Address : %s\n", c.SimPhoneConfig.MYIP)
	fmt.Printf("iComsys Target Phone Address : %s\n", c.GetSimTargetIP())
	fmt.Printf("Log Level : %s\n", c.LogConfig.Level)
	fmt.Printf("Log Path : %s\n", c.LogConfig.Path)
	fmt.Printf("Log Disk Space Limitation : %dMB\n", c.LogConfig.Disklimit)
	fmt.Printf("Log Output : %s\n", c.LogConfig.Output)
	fmt.Printf("Log Rotate : %s\n", c.LogConfig.RotateConfig.YesNo)
	fmt.Printf("Log Rotate File Size : %s\n", c.LogConfig.RotateConfig.Size)
	fmt.Printf("Log Rotate File Number : %s\n", c.LogConfig.RotateConfig.Num)
	fmt.Printf("SIP Port: %d\n", c.SimPhoneConfig.SIPPort)
	fmt.Printf("RTP Port: %d\n", c.SimPhoneConfig.RTPPort)

	confmsg := ""
	confmsg += fmt.Sprintf("Home Path : %s\n", c.HomeDir)
	confmsg += fmt.Sprintf("Caller : %s\n", c.IsCaller)
	confmsg += fmt.Sprintf("Channel number : %d\n", c.Channels)
	confmsg += fmt.Sprintf("iComsys SIM Phone Address : %s\n", c.SimPhoneConfig.MYIP)
	confmsg += fmt.Sprintf("iComsys Target Phone Address : %s\n", c.GetSimTargetIP())
	confmsg += fmt.Sprintf("Log Level : %s\n", c.LogConfig.Level)
	confmsg += fmt.Sprintf("Log Path : %s\n", c.LogConfig.Path)
	confmsg += fmt.Sprintf("Log Disk Space Limitation : %dMB\n", c.LogConfig.Disklimit)
	confmsg += fmt.Sprintf("Log Output : %s\n", c.LogConfig.Output)
	confmsg += fmt.Sprintf("Log Rotate : %s\n\n", c.LogConfig.RotateConfig.YesNo)
	confmsg += fmt.Sprintf("Log Rotate File Size : %s\n", c.LogConfig.RotateConfig.Size)
	confmsg += fmt.Sprintf("Log Rotate File Number : %s\n", c.LogConfig.RotateConfig.Num)
	confmsg += fmt.Sprintf("SIP Port: %d\n", c.SimPhoneConfig.SIPPort)
	confmsg += fmt.Sprintf("RTP Port: %d\n\n", c.SimPhoneConfig.RTPPort)

	return confmsg
}

var gSimConfig *SimConfig
var gSimScenarioConfig *SimScenarioConfig

func GetSimConfig() *SimConfig {
	return gSimConfig
}

func GetSimScenarioConfig() *SimScenarioConfig {
	return gSimScenarioConfig
}
