package icssessionmanager

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"strings"
	"sync"
	"time"
	// "strconv"

	"gitlab.com/ics_cinnamon/voicegateway/icscbtimer"
	"gitlab.com/ics_cinnamon/voicegateway/icsconf"
	"gitlab.com/ics_cinnamon/voicegateway/icserror"
	"gitlab.com/ics_cinnamon/voicegateway/icsevent"
	"gitlab.com/ics_cinnamon/voicegateway/icslog"
	"gitlab.com/ics_cinnamon/voicegateway/icsnet"
	"gitlab.com/ics_cinnamon/voicegateway/icspacketparser"
	"gitlab.com/ics_cinnamon/voicegateway/icssvc"
	"gitlab.com/ics_cinnamon/voicegateway/recorddata"
	"gitlab.com/ics_cinnamon/voicegateway/sipasm"
)

type SessionManager struct {
	evtSystem []*icsevent.EventSystem
	sessions  []*IcsSession

	event *icsevent.EventH

	//sip listener
	SIPNeter icsnet.IcsNeter

	//bot-command net
	CommNet *icsnet.IcsTCPNet
}

var bigSession []*IcsSession

//var bigSession []*IcsSession
var onceSession sync.Once
var channelNum int

func getSessionInstance(SIPNeter *icsnet.IcsNeter) []*IcsSession {
	//l := icslog.GetIcsLog()

	onceSession.Do(func() {
		bigSession = make([]*IcsSession, channelNum)

		svc := icssvc.GetServiceStatus()
		conf := svc.GetIcsConfig()
		agentNum := len(conf.AgentConfig)

		for iter := 0; iter < channelNum; iter++ {
			bigSession[iter] = new(IcsSession)
			bigSession[iter].m = &sync.Mutex{}
			bigSession[iter].ID = iter
			//bigSession[iter].goroutineID = goid()
			bigSession[iter].isStart = false
			//bigSession[iter].lastTimestamp = time.Now()

			bigSession[iter].Cseq = 0
			bigSession[iter].registerStatus = STATUS_REGISTER_NOT_READY
			bigSession[iter].agentStatus = STATUS_AGENT_NOT_READY
			bigSession[iter].AgentName = conf.AgentConfig[iter].Name
			bigSession[iter].simLoopCount = 1
			bigSession[iter].AgentName2 = fmt.Sprintf("agent%s", conf.AgentConfig[iter].Name)

			if iter < agentNum {
				if strings.Contains(strings.ToUpper(conf.AgentConfig[iter].Value), "TRUE") {
					/*
						//set rtp send callback
						bigSession[iter].RTPPort = conf.AgentConfig[iter].MediaConfig.Port
						bigSession[iter].RTPSenderCallBackTimer =
							icscbtimer.NewCBTimer(
								time.Millisecond*20,
								bigSession[iter].SendRTPCB)

						//set session's agentInfo conf
						agentInfo := bigSession[iter].FindAgentInfo(bigSession[iter].AgentName)
						if agentInfo != nil {
							bigSession[iter].SetAgentInfo(agentInfo)
						}
					*/
				} else {
					bigSession[iter].RTPPort = -1
				}

				//set register callback timer
				if strings.Contains(strings.ToUpper(conf.AgentConfig[iter].RegisterConfig.RegisterValue), "TRUE") {
					//bigSession[iter].RegisterCallBackTimer = icscbtimer.NewCBTimer(time.Millisecond*100, bigSession[iter].RequestRegisterCB)
					regiExpire := conf.AgentConfig[iter].RegisterConfig.RegisterExpire
					bigSession[iter].RegisterCallBackTimer =
						icscbtimer.NewCBTimer(
							time.Millisecond*1000*time.Duration(regiExpire),
							bigSession[iter].RequestRegisterCB)
				} else {
					bigSession[iter].registerStatus = STATUS_REGISTER_REGISTERED
					bigSession[iter].agentStatus = STATUS_AGENT_READY
					bigSession[iter].MethodAutomata = 32767
				}

				//set options callback timer
				if strings.Contains(strings.ToUpper(conf.AgentConfig[iter].OptionsConfig.OptionsValue), "TRUE") {
					interval := conf.AgentConfig[iter].OptionsConfig.OptionsInterval
					bigSession[iter].OPTIONSCallBackTimer =
						icscbtimer.NewCBTimer(
							time.Millisecond*1000*time.Duration(interval),
							bigSession[iter].RequestOptionsCB)
				}

				/*
					//set invite callback timer
					bigSession[iter].INVITECallBackTimer =
						icscbtimer.NewCBTimer(
							time.Millisecond*1000*time.Duration(1),
							bigSession[iter].RequestInviteCB)

					if err := bigSession[iter].Init(); err != nil {
						l.Printf(icslog.LOG_LEVEL_FATAL, -1, "Session Init error. Voice Agent EXIT!! - %s", err.GetMessage())
						os.Exit(0)
					}
				*/
			}

			bigSession[iter].eventSystem = icsevent.GetMyEventSystem(iter)
			//bigSession[iter].Init(iter)

			//set sip connection to each sessions
			bigSession[iter].sipNeter = SIPNeter
		}
	})

	return bigSession
}

//TODO: make this function to singleton
func NewSessionManager() *SessionManager {
	l := icslog.GetIcsLog()
	conf := icsconf.GetIcsConfig()

	svc := icssvc.NewService()
	channelNum = svc.GetIcsConfig().GetChannelNum()
	//icsevent.SetConfig(svc.GetIcsConfig())

	sm := new(SessionManager)
	icsevent.SetChannelNum(channelNum)
	sm.evtSystem = icsevent.GetEvtSystemInstance()

	//start sip listen
	sipPort := conf.SIPConfig.Port
	transport := conf.SIPConfig.Transport
	sipProxy := conf.SIPConfig.SIPProxy

	remoteaddr := icsnet.NewNetAddrWithIPAddr(sipProxy)
	localAddrStr := fmt.Sprintf("0.0.0.0:%d", sipPort)
	localAddr := icsnet.NewNetAddrWithIPAddr(localAddrStr)

	switch strings.ToUpper(transport) {
	case "UDP":
		sm.SIPNeter = icsnet.NewUDP(&localAddr, &remoteaddr)
	case "TCP":
		sm.SIPNeter = icsnet.NewTCP(&localAddr, &remoteaddr)
	default:
		l.Print(icslog.LOG_LEVEL_FATAL, -1, "No compatible transport. Check the configuration")
		return nil
	}

	/*
		cerr := sm.SIPNeter.Connect()
		if cerr != nil {
			l.Print(icslog.LOG_LEVEL_FATAL, -1, cerr.GetMessage())
			return nil
		}
	*/

	lerr := sm.SIPNeter.Listen()
	if lerr != nil {
		l.Printf(icslog.LOG_LEVEL_FATAL, -1, "Listening failed: %s", lerr.GetError())
		return nil
	}
	l.Printf(icslog.LOG_LEVEL_INFO, -1, "Listening SIP %s port[%d]", transport, sipPort)

	/*
		//start bot-command listen
		commandValue := strings.ToUpper(conf.CommandConfig.Value)
		commandPort := conf.CommandConfig.Port
		commandTransport := conf.CommandConfig.Transport
		if strings.Compare("TRUE", commandValue) == 0 {
			commandLocalAddrStr := fmt.Sprintf("0.0.0.0:%d", commandPort)
			commandLocalAddr := icsnet.NewNetAddrWithIPAddr(commandLocalAddrStr)
			switch strings.ToUpper(commandTransport) {
			case "UDP":
				sm.CommNeter = icsnet.NewUDP(&commandLocalAddr, nil)
			case "TCP":
				sm.CommNeter = icsnet.NewTCP(&commandLocalAddr, nil)
			default:
				l.Print(icslog.LOG_LEVEL_FATAL, -1, "Bot-Command listening error. No compatible transport. Check the configuration")
				return nil
			}

				lerr = sm.CommNeter.Listen()
				if lerr != nil {
					l.Printf(icslog.LOG_LEVEL_FATAL, -1, "%s", lerr.GetError())
					return nil
				}
				l.Printf(icslog.LOG_LEVEL_INFO, -1, "Listening Bot-Command %s port[%d]", commandTransport, commandPort)
		}
	*/

	sm.sessions = getSessionInstance(&sm.SIPNeter)

	//EventH. Create Event Array
	sm.event = icsevent.NewEventH()

	return sm
}

func (sm *SessionManager) Load() {
	sm.event.Init()

	//for iter, session := range sm.sessions {
	for _, session := range sm.sessions {
		//l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "333 %d", iter)
		go session.Run()
	}
}

func (sm *SessionManager) Close() {
	for iter := 0; iter < channelNum; iter++ {
		sm.sessions[iter].RemoveSession()
	}

	sm.SIPNeter.Close()
}

func (sm *SessionManager) Run() (icserr *icserror.IcsError) {
	l := icslog.GetIcsLog()
	conf := icsconf.GetIcsConfig()
	svc := icssvc.GetServiceStatus()

	for !svc.GetExit() || !svc.GetStop() {
		data, addr, len, rerr := sm.SIPNeter.ReadSIP()
		if rerr != nil {
			return rerr
		}
		//fmt.Println("RECVED>>>", addr, len, string(data))
		l.Printf(icslog.LOG_LEVEL_INFO, -1, "Recved Data[%d] [%s]->[%s]>\n%s",
			len,
			addr.String(),
			sm.SIPNeter.LocalAddr().String(),
			string(data[:len]))

		sip := icspacketparser.NewSIP()
		sip.SipParser(data)
		if icspacketparser.ICS_SIP_METHOD_NOT_FOUND == sip.Method { //not found sip. maybe abnormal use
			l.Printf(icslog.LOG_LEVEL_INFO, -1, "icspacketparser.ICS_SIP_METHOD_NOT_FOUND-%s", string(data))
			continue
		} else {
			// fmt.Println("메서드", sip.Method.String())
			// if sip.Method == icspacketparser.ICS_SIP_METHOD_INVITE {
			// 	// conf := icsconf.GetIcsConfig()
			
			// 	// TODO - send bye
			// 	// defer func() {
			// 	// 	if err := recover(); err != nil {
			// 	// 		l.Printf(icslog.LOG_LEVEL_WARN, =1, "%s \n%s",
			// 	// 			icserror.ICSERRNETNotConnectError.GetMessage(), debug.Stack())
			// 	// 	}
			// 	// }()
			
			
			// 	l.Printf(icslog.LOG_LEVEL_INFO, -1, "sip 내용 전달! %+v", sip)
			// 	// ip := strings.Split(conf.SIPConfig.SIPProxy, ":")[0]
			// 	// port, cerr := strconv.Atoi(strings.Split(conf.SIPConfig.SIPProxy, ":")[1])
			// 	// if cerr != nil {
			// 	// 	fmt.Println("cerr err")
			// 	// }
			// 	// iport := fmt.Sprintf("%s:%d", ip, port)
				

			// 	// fmt.Println(ip, port)

			// 	sipPort := conf.SIPConfig.Port
			// 	// transport := conf.SIPConfig.Transport
			// 	sipProxy := conf.SIPConfig.SIPProxy

			// 	remoteaddr := icsnet.NewNetAddrWithIPAddr(sipProxy)
			// 	localAddrStr := fmt.Sprintf("192.168.0.4:%d", sipPort)
			// 	localAddr := icsnet.NewNetAddrWithIPAddr(localAddrStr)

			// 	t := icsnet.NewUDP(&localAddr, &remoteaddr)
			// 	// fmt.Println("local ", t.LocalAddr().String())
			// 	fmt.Println("remote ", t.RemoteAddr().String())
			// 	// sendSIP := []string{data[:]}

			// 	// for _, elem := range data {
			// 	sent, err := t.WriteSIP([]byte(data))
			// 	if err != nil {
			// 		fmt.Println(err)
			// 	}
			// 	// }
				
			// 	// wlen, werr := t.WriteSIP([]byte(data))
			// 	// if werr != nil {
			// 	// 	l.Print(icslog.LOG_LEVEL_FATAL, -1, werr.GetMessage())
			// 	// 	// s.SetAgentStatus(STATUS_AGENT_READY)
			// 	// 	// return werr
			// 	// }
			// 	fmt.Printf("send data \r\n%s, \r\n %d\r\n", string(data), sent)
				
			// } else {
				if SessionAvailableSipMethod(&sip) {
					l.Printf(icslog.LOG_LEVEL_DEBUG, -1, "Session Processing Method-[%s, %s, %s]",
						sip.Method, sip.ResType, sip.Cseq)
	
					s, serr := FindSession(sip)
					if serr != nil { //not found session, create new
						name1 := strings.SplitN(sip.To, "@", 2)
						name2 := strings.SplitN(name1[0], ":", 2)
						agentname := name2[1]
						s, serr = AllocSession(agentname, sip.GetCallID())
						if serr != nil {
							l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Licensed Session number[%d:%s] is EXCEEDED-%s",
								conf.GetChannelNum(), agentname, serr.GetMessage())
							if conf.Representative.Value && sip.Source == "486" {
								l.Printf(icslog.LOG_LEVEL_ERROR, -1, "All Agent Calling!!!!!")
								sipPort := conf.SIPConfig.Port
								// sipProxy := conf.SIPConfig.SIPProxy
								transport := conf.SIPConfig.Transport
								// remoteaddr := icsnet.NewNetAddrWithIPAddr(sipProxy)
								// localAddrStr := fmt.Sprintf("0.0.0.0:%d", sipPort)
								// localAddr := icsnet.NewNetAddrWithIPAddr(localAddrStr)
								//////////////////////////////////////////////
								ip := conf.InfoConfig.ServerIP
								ackMethod := fmt.Sprintf("sip:01025670081@%s;transport=%s", "192.168.0.222:5090", transport)
								reqAck := sipasm.NewSIPMessage(sipasm.ICSSIP_METHOD_ACK, ackMethod)
								maxforwards := "70"
								// s.uri = fmt.Sprintf("sip:%s@%s", conf.Representative.Name, ip)
								// l.Printf(icslog.LOG_LEVEL_INFO, -1, "Set URI [%s]", s.uri)
								contact := fmt.Sprintf("<sip:%s@%s:%d;transport=%s>", conf.Representative.Name, ip, sipPort, transport)
								userAgent := conf.InfoConfig.Product
								allow := "REGISTER,OPTIONS,INVITE,ACK,CANCEL,BYE,NOTIFY,PRACK,REFER,INFO,SUBSCRIBE,UPDATE"
								supported := "timer,path,replaces"
	
								for _, viav := range sip.Via {
									reqAck.AddSIPHeader(sipasm.ICSSIP_HEADER_VIA, viav)
								}
								reqAck.AddSIPHeader(sipasm.ICSSIP_HEADER_MAX_FORWARDS, maxforwards)
								reqAck.AddSIPHeader(sipasm.ICSSIP_HEADER_FROM, sip.From)
								reqAck.AddSIPHeader(sipasm.ICSSIP_HEADER_TO, sip.To)
								reqAck.AddSIPHeader(sipasm.ICSSIP_HEADER_CALL_ID, sip.CallID)
								reqAck.AddSIPHeader(sipasm.ICSSIP_HEADER_CSEQ, sip.Cseq)
								reqAck.AddSIPHeader(sipasm.ICSSIP_HEADER_CONTACT, contact)
								reqAck.AddSIPHeader(sipasm.ICSSIP_HEADER_USER_AGENT, userAgent)
								reqAck.AddSIPHeader(sipasm.ICSSIP_HEADER_ALLOW, allow)
								reqAck.AddSIPHeader(sipasm.ICSSIP_HEADER_SUPPORTED, supported)
								reqAck.AddSIPHeader(sipasm.ICSSIP_HEADER_CONTENT_LENGTH, "0")
								reqAck.AddSIPHeader(sipasm.ICSSIP_HEADER_TERMINATOR)
	
								// wlen, werr := (*s.sipNeter).WriteSIPTo([]byte(reqAck.String()), s.remoteSIPAddr)
								wlen, werr := (sm.SIPNeter).WriteSIP([]byte(reqAck.String()))
								if werr != nil {
									l.Print(icslog.LOG_LEVEL_FATAL, s.ID, werr.GetMessage())
									return werr
								}
								l.Printf(icslog.LOG_LEVEL_INFO, -1, "Sent Data(%d) [%s]->[%s]>\n%s",
													wlen,
													(sm.SIPNeter).LocalAddr().String(),
													(sm.SIPNeter).RemoteAddr().String(),
													reqAck.String())
								//////////////////////////////////////////////
							}
							continue
						}
						l.Printf(icslog.LOG_LEVEL_INFO, -1, "Session Allocated. Session ID[%d] Call ID[%s]", s.ID, sip.GetCallID())
						s.SetSessionMethod(sip)
						//session start
						s.Start()
					} else { //found session
						l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Session found [%s][%s]", sip.GetCallID(), s.callID)
						if sip.Method == icspacketparser.ICS_SIP_METHOD_INVITE {
							s.SetCallID(sip.GetCallID())
						}
						// 대표번호
						if sip.Method == icspacketparser.ICS_SIP_METHOD_SIP20 || strings.SplitN(sip.Cseq, " ", 2)[1] == "INVITE" {
							s.SetCallID(sip.GetCallID())
							// representative
							if conf.Representative.Value {
								sip.SetToRep()
								sip.SetTo(s.AgentName)
								// if sip.Source == "486" {
								// 	l.Printf(icslog.LOG_LEVEL_ERROR, -1, "All Agent Calling!!!!!")
								// 	fmt.Println("##### All Agent Clling!!!!!! ")
								// 	s.Res486Ack(&sip)
								// 	continue
								// }
							}
						}
	
						if s.CheckAutomata(&sip) {
							s.SetSessionMethod(sip)
						} else {
							l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Not Allowed Method(%d)", s.MethodAutomata)
							//TODO : response 400 error
							continue
						}
	
						// if conf.Representative.Value && sip.Source == "486" {
						//                             l.Printf(icslog.LOG_LEVEL_ERROR, -1, "All Agent Calling!!!!!")
						//                             fmt.Println("##### All Agent Clling!!!!!! ")
						//                             s.Res486Ack(&sip)
						//                     	continue
						//                     }
	
						//if cancel ACK or bye res, remove the session
						if s.MethodAutomata == ICS_SIP_AUTOMATA_CANCEL && sip.Method == icspacketparser.ICS_SIP_METHOD_ACK {
							s.Stop()
							serr := s.RemoveSession()
							if serr != nil {
								l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "RemoveSession Error %s", serr.GetMessage())
	
							} else {
								l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Session Removed")
							}
							continue
						}
					}

					s.remoteSIPAddr = addr
	
					//post the sip event to session
					h := icsevent.NewEventH()
					evt, evtErr := h.AllocEvent(sip)
					if evtErr != nil {
						return evtErr
					}
					perr := h.PostEvent(s.ID, evt)
					//perr := h.PostEvent(int(s.GetSessionID()), evt)
					if perr == nil {
						l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Post SIP event[%d] to Session[%03d]", evt.ID, s.ID)
					} else {
						l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to post SIP event[%d] to Session[%03d] - %s",
							evt.ID, s.ID, perr.GetError())
					}
				} else { // no session
					switch sip.Method {
					case icspacketparser.ICS_SIP_METHOD_OPTIONS:
						l.Printf(icslog.LOG_LEVEL_INFO, -1, "%v", sip)
					case icspacketparser.ICS_SIP_METHOD_SIP20:
						if strings.Contains(strings.ToUpper(sip.Cseq), "OPTIONS") {
							//l.Printf(icslog.LOG_LEVEL_INFO, -1, "%v", sip)
						} else {
							l.Printf(icslog.LOG_LEVEL_INFO, -1, "%v", sip)
						}
					default:
						l.Printf(icslog.LOG_LEVEL_INFO, -1, "%v", sip)
					}
				}
			// }
		}

		data = nil
	}

	return nil
}

//bot-command manager
func (sm *SessionManager) RunBotCommandMNG() (icserr *icserror.IcsError) {
	l := icslog.GetIcsLog()
	conf := icsconf.GetIcsConfig()

	//start bot-command listen
	commandPort := conf.CommandConfig.Port
	commandTransport := conf.CommandConfig.Transport
	commandLocalAddrStr := fmt.Sprintf("0.0.0.0:%d", commandPort)
	commandLocalAddr := icsnet.NewNetAddrWithIPAddr(commandLocalAddrStr)

	var cmdErr *icserror.IcsError
	sm.CommNet, cmdErr = icsnet.ListenAndServeTCP(&commandLocalAddr, nil, "\r\n\r\n", BotCommand)
	if cmdErr != nil {
		l.Printf(icslog.LOG_LEVEL_FATAL, -1, "%s", cmdErr.GetError())
		return nil
	}
	l.Printf(icslog.LOG_LEVEL_INFO, -1, "Listening Bot-Command %s port[%d]", commandTransport, commandPort)

	/*
		for !svc.GetExit() || !svc.GetStop() {
		}
	*/

	return nil
}

func BotCommand(t *icsnet.IcsTCPNet, bufend string) {
	l := icslog.GetIcsLog()

	defer t.Close()

	for {
		ttsHeader, rlen, rerr := t.ReadS(86, bufend)
		if rerr != nil {
			if rerr.GetError() != io.EOF {
				l.Printf(icslog.LOG_LEVEL_ERROR, -1, "[Bot Command] ReadS Error! - %s[%d:%s]",
					rerr.GetError(), rlen, len(ttsHeader))
			}
			break
		} else {
			l.Printf(icslog.LOG_LEVEL_INFO, -1, "Recved Bot Command(%s)", ttsHeader)

			ttscmd := binary.LittleEndian.Uint32(ttsHeader[0:])
			ttsrc := binary.LittleEndian.Uint32(ttsHeader[4:])
			ttspl := binary.LittleEndian.Uint64(ttsHeader[8:])
			agentname := string(ttsHeader[16:])
			//remove null terminator
			n := bytes.Index([]byte(agentname), []byte{0})
			agentName := string([]byte(agentname)[:n])
			telno := string(ttsHeader[36:])
			m := bytes.Index([]byte(telno), []byte{0})
			telNo := string([]byte(telno)[:m])

			s := findSessionWithAgentName2(agentName)
			if s == nil {
				l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Not found session - %s", agentName)
				return
			}

			l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Bot Command(%d) - [%s:%d]", rlen, agentName, ttscmd)

			switch ttscmd {
			case recorddata.TTS_COMMAND:
				l.Print(icslog.LOG_LEVEL_INFO, s.ID, "Recved TTS command")
				//fmt.Println("374LINE", ttscmd, ttsrc, ttspl, agentName)
				//recv tts data
				tts, rlen, rerr := t.Read(int(ttspl))
				if rerr != nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to recv TTS(%d,%s)", rlen, rerr.GetError())
					return
				}
				l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Recved TTS data. Length: %d", len(tts))

				//////////////////////
				//RTP start
				l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Started RTP Callback timer %+v", s.RTPSenderCallBackTimer)
				s.RTPSenderCallBackTimer.Stop()
				s.m.Lock()
				s.tts = make([]byte, int(ttspl))
				copy(s.tts, tts)
				s.m.Unlock()

				/*
					n := time.Now()
					filename := fmt.Sprintf("./%daaabbb%d-2.pcm", s.ID, n.Nanosecond())
					ttsfile, ferr := os.OpenFile(filename, os.O_CREATE|os.O_RDWR|os.O_APPEND|os.O_TRUNC|os.O_SYNC, os.FileMode(0644))
					if ferr != nil {
						fmt.Println(ferr)
						os.Exit(1)
					}
					ttsfile.Write(tts)
					ttsfile.Close()
				*/
				//s.tts = tts
				//s.txCnt = 0
				//s.callStartTime = time.Now()
				s.RTPSenderCallBackTimer.Start()
			case recorddata.BYE_COMMAND:
				l.Print(icslog.LOG_LEVEL_INFO, s.ID, "Recved BYE command")
				//fmt.Println("393LINE", ttscmd, ttsrc, ttspl, agentName)
				if int(ttspl) > 0 {
					//recv tts data
					tts, rlen, rerr := t.Read(int(ttspl))
					if rerr != nil {
						l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to recv TTS(%d,%s)", rlen, rerr.GetError())
						return
					}
					l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Read T: %v", t)
					l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Recved TTS data. Length: %d", len(tts))

					//////////////////////
					//RTP start
					l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Started RTP Callback timer %+v", s.RTPSenderCallBackTimer)
					s.RTPSenderCallBackTimer.Stop()
					s.m.Lock()
					s.tts = make([]byte, int(ttspl))
					copy(s.tts, tts)
					//s.tts = tts
					s.m.Unlock()
					//s.txCnt = 0
					//s.callStartTime = time.Now()
					s.RTPSenderCallBackTimer.Start()

					//request bye
					sleeptime := int(ttspl) / 16
					time.Sleep(time.Millisecond * time.Duration(sleeptime+200))
					agentStatus := s.GetAgentStatus()
					//l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Agent Status: %d", agentStatus)
					if agentStatus == STATUS_AGENT_BUSY {
						s.RequestBYE(s.InviteSIP)
						s.SetAgentStatus(STATUS_AGENT_BYEING)
						// fmt.Println("AGENT_STATUS : ", s.GetAgentStatus())
					}
					s.BotStatus = ttscmd
				} else {
					if s.InviteSIP == nil {
						agentStatus := s.GetAgentStatus()
						if agentStatus == STATUS_AGENT_BUSY {
							s.SetAgentStatus(STATUS_AGENT_ERROR)
						}
					} else {
						s.RequestBYE(s.InviteSIP)
					}
				}
			case recorddata.DTMF_COMMAND:
				l.Print(icslog.LOG_LEVEL_INFO, s.ID, "Recved DTMF command")
				//fmt.Println("374LINE", ttscmd, ttsrc, ttspl, agentName)
				//recv tts data
				tts, rlen, rerr := t.Read(int(ttspl))
				if rerr != nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to recv TTS(%d,%s)", rlen, rerr.GetError())
					// fmt.Println("error : ", rerr.GetError())
					return
				}
				l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Recved TTS data. Length: %d", len(tts))

				//////////////////////
				//RTP start
				l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Started RTP Callback timer %+v", s.RTPSenderCallBackTimer)
				s.RTPSenderCallBackTimer.Stop()
				s.m.Lock()
				s.tts = make([]byte, int(ttspl))
				copy(s.tts, tts)
				s.m.Unlock()
				s.BotStatus = ttscmd

				s.RTPSenderCallBackTimer.Start()
			case recorddata.REFER_COMMAND:
				l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Recved REFER command %+v", ttscmd)

				//fmt.Println("393LINE", ttscmd, ttsrc, ttspl, agentName)
				if int(ttspl) > 0 {
					//recv tts data
					tts, rlen, rerr := t.Read(int(ttspl))
					if rerr != nil {
						l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to recv TTS(%d,%s)", rlen, rerr.GetError())
						return
					}
					l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Recved TTS data. Length: %d", len(tts))

					//////////////////////
					//RTP start
					l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Started RTP Callback timer %+v", s.RTPSenderCallBackTimer)
					s.RTPSenderCallBackTimer.Stop()
					s.m.Lock()
					s.tts = make([]byte, int(ttspl))
					copy(s.tts, tts)
					//s.tts = tts
					s.m.Unlock()
					//s.txCnt = 0
					//s.callStartTime = time.Now()
					s.RTPSenderCallBackTimer.Start()

					//request bye
					sleeptime := int(ttspl) / 16
					time.Sleep(time.Millisecond * time.Duration(sleeptime+200))
					agentStatus := s.GetAgentStatus()
					//l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Agent Status: %d", agentStatus)
					if agentStatus == STATUS_AGENT_BUSY {
						s.RequestRefer(telNo, s.InviteSIP)
						s.SetAgentStatus(STATUS_AGENT_BYEING)
						// fmt.Println("AGENT_STATUS : ", s.GetAgentStatus())
					}
					s.BotStatus = ttscmd
				} else {
					if s.InviteSIP == nil {
						agentStatus := s.GetAgentStatus()
						if agentStatus == STATUS_AGENT_BUSY {
							s.SetAgentStatus(STATUS_AGENT_ERROR)
						}
					} else {
						s.RequestRefer(telNo, s.InviteSIP)
					}
				}
			default:
				l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "485LINE %+v, %+v, %+v, %s", ttscmd, ttsrc, ttspl, agentName)
			}
		}
		// fmt.Println("418LINE rlen", rlen, rerr)
	}
}
