package icsconf

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

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

type IcsConfig struct {
	XMLName          xml.Name         `xml:"ICSVSIM"`
	Version          string           `xml:"version,attr"`
	InfoConfig       InfoConfig       `xml:"INFO"`
	LicenseConfig    LicenseConfig    `xml:"LICENSE"`
	LogConfig        LogConfig        `xml:"LOG"`
	CommandConfig    CommandConfig    `xml:"COMMAND"`
	CallEventConfig  CallEventConfig  `xml:"CALLEVENT"`
	SIPConfig        SIPConfig        `xml:"SIP"`
	AgentConfig      []AgentConfig    `xml:"AGENT"`
	VoiceAgentConfig VoiceAgentConfig `xml:"VOICEAGENT"`
	PbxConfig        PbxConfig        `xml:"PBX"`
	SimLoopCount     int              `xml:"SIMLOOP"`
	Representative   Representative   `xml:"REPRESENTATIVE"`
	CallEndInfo      CallEndInfo   	  `xml:"CALLENDINFO"`
	HomeDir          string
}

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

type LicenseConfig struct {
	Key      string `xml:"KEY"`
	Channels int    `xml:"CHANNELS"`
	Expire   int    `xml:"EXPIRE"`
}

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"`
}

type CommandConfig struct {
	Value     string `xml:"value,attr"`
	Transport string `xml:"transport,attr"`
	Port      int    `xml:"port,attr"`
}

type AgentConfig struct {
	Name           string         `xml:"name,attr"`
	Value          string         `xml:"value,attr"`
	RegisterConfig RegisterConfig `xml:"REGISTER"`
	OptionsConfig  OptionsConfig  `xml:"OPTIONS"`
	MediaConfig    MediaConfig    `xml:"MEDIA"`
}

type RegisterConfig struct {
	RegisterValue     string `xml:"value,attr"`
	RegisterTransport string `xml:"transport,attr"`
	RegisterExpire    int    `xml:"expire,attr"`
	RegisterUserName  string `xml:"username,attr"`
}

type OptionsConfig struct {
	OptionsValue    string `xml:"value,attr"`
	OptionsInterval int    `xml:"interval,attr"`
}

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

type CallEventConfig struct {
	Value      string `xml:"value,attr"`
	Production string `xml:"production,attr"`
	Version    string `xml:"version,attr"`
}

type SIPConfig struct {
	Value     string `xml:"value,attr"`
	Transport string `xml:"transport,attr"`
	Port      int    `xml:"port,attr"`
	SIPProxy  string `xml:"proxy,attr"`
}

type Representative struct {
	Value bool `xml:"value,attr"`
	Name string `xml:"name,attr"`
}

type CallEndInfo struct {
	Value bool   `xml:"value,attr"`
	Loop  int    `xml:"loopCount,attr"`
}

type PbxConfig struct {
	PbxIp   string `xml:"IP"`
	PbxPort int    `xml:"PORT"`
}

type VoiceAgentConfig struct {
	AgentInfo []AgentInfo `xml:"AGENT"`
	MyAddr    MyAddr      `xml:"SERVER"`
}

type AgentInfo struct {
	Name      string `xml:"name,attr"`
	Action    string `xml:"action,attr"`
	Port      int    `xml:"port,attr"`
	VoicePort int    `xml:"voiceport,attr"`
	IP        string `xml:"ip,attr"`
}

type MyAddr struct {
	ServerPort int    `xml:"port,attr"`
	BasePort   int    `xml:"baseport,attr"`
	PortRange  int    `xml:"range,attr"`
	ServerIP   string `xml:",chardata"`
}

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) GetChannelNum() int {
	return c.LicenseConfig.Channels
}

func (c IcsConfig) GetExpire() int {
	return c.LicenseConfig.Expire
}

func (c IcsConfig) GetPbxIp() string {
	return c.PbxConfig.PbxIp
}

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
}

func (c IcsConfig) GetServerIP() string {
	return c.VoiceAgentConfig.MyAddr.ServerIP
}

//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("Licensed Channel number : %d\n", c.LicenseConfig.Channels)
	agentlen := len(c.VoiceAgentConfig.AgentInfo)
	for iter1 := 0; iter1 < agentlen; iter1++ {
		fmt.Printf("Voice Agent [%s] %s:%d|%d action: %s\n",
			c.VoiceAgentConfig.AgentInfo[iter1].Name,
			c.VoiceAgentConfig.AgentInfo[iter1].IP,
			c.VoiceAgentConfig.AgentInfo[iter1].Port,
			c.VoiceAgentConfig.AgentInfo[iter1].VoicePort,
			c.VoiceAgentConfig.AgentInfo[iter1].Action)
	}
	fmt.Printf("PBX Address : %s:%d\n\n", c.PbxConfig.PbxIp, c.PbxConfig.PbxPort)
	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("CallEvent Value: %s\n", c.CallEventConfig.Value)
	fmt.Printf("CallEvent Production: %s\n", c.CallEventConfig.Production)
	fmt.Printf("CallEvent Version: %s\n", c.CallEventConfig.Version)
	fmt.Printf("Log Del Day : %d\n", c.LogConfig.DelConfig.DelDay)
	fmt.Printf("Log Del Hour : %d\n", c.LogConfig.DelConfig.DelHour)
	fmt.Printf("SIP Value: %s\n", c.SIPConfig.Value)
	fmt.Printf("SIP Transport: %s\n", c.SIPConfig.Transport)
	fmt.Printf("SIP Port: %d\n", c.SIPConfig.Port)
	fmt.Printf("SIP Proxy: %s\n\n", c.SIPConfig.SIPProxy)
	/*
		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("Licensed Channel number : %d\n", c.LicenseConfig.Channels)
	/*
		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("PBX Address : %s:%d\n\n", c.PbxConfig.PbxIp, c.PbxConfig.PbxPort)
	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)
	confmsg += fmt.Sprintf("CallEvent Production: %s\n", c.CallEventConfig.Production)
	confmsg += fmt.Sprintf("CallEvent Version: %s\n", c.CallEventConfig.Version)
	confmsg += fmt.Sprintf("SIP Transport: %s\n", c.SIPConfig.Transport)
	confmsg += fmt.Sprintf("SIP Port: %d\n", c.SIPConfig.Port)
	confmsg += fmt.Sprintf("SIP Proxy: %s\n", c.SIPConfig.SIPProxy)
	for iter := 0; iter < len(c.AgentConfig); iter++ {
		confmsg += fmt.Sprintf("=========================\nAgent Name: %s, Use? %s\n", c.AgentConfig[iter].Name, c.AgentConfig[iter].Value)
		confmsg += fmt.Sprintf("Agent Media media: %s\n", c.AgentConfig[iter].MediaConfig.Media)
		confmsg += fmt.Sprintf("Agent Media Port: %d\n", c.AgentConfig[iter].MediaConfig.Port)
		confmsg += fmt.Sprintf("Agent Media Format: %s\n", c.AgentConfig[iter].MediaConfig.Format)
		confmsg += fmt.Sprintf("Register value: %s\n", c.AgentConfig[iter].RegisterConfig.RegisterValue)
		confmsg += fmt.Sprintf("Register Transport: %s\n", c.AgentConfig[iter].RegisterConfig.RegisterTransport)
		confmsg += fmt.Sprintf("Register Expire: %d\n", c.AgentConfig[iter].RegisterConfig.RegisterExpire)
		confmsg += fmt.Sprintf("Register Username: %s\n\n", c.AgentConfig[iter].RegisterConfig.RegisterUserName)
	}

	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
}
