package icssessionmanager

import (
	"bytes"
	"fmt"
	"runtime/debug"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"gitlab.com/cinnamon/voiceagent/icsconf"
	"gitlab.com/cinnamon/voiceagent/icserror"
	"gitlab.com/cinnamon/voiceagent/icsevent"
	"gitlab.com/cinnamon/voiceagent/icshttpclient"
	"gitlab.com/cinnamon/voiceagent/icslog"
	"gitlab.com/cinnamon/voiceagent/icsmediaconv"
	"gitlab.com/cinnamon/voiceagent/icsnet"
	"gitlab.com/cinnamon/voiceagent/icspacketparser"
	"gitlab.com/cinnamon/voiceagent/icssvc"
	"gitlab.com/cinnamon/voiceagent/icsws"
	"gitlab.com/cinnamon/voiceagent/recorddata"
	"gitlab.com/cinnamon/voiceagent/recorddata/readcallsignal"
	"gitlab.com/cinnamon/voiceagent/recorddata/responsecs"
	"gitlab.com/cinnamon/voiceagent/stt"
	"gitlab.com/ics_cinnamon/joy4/format"
)

type IcsSession struct {
	ID int

	goroutineID int

	//bot
	callId    string
	srcPort   int
	dstPort   int
	direction bool
	Station   string
	sstation  string
	botToken  string
	url       string
	custid    string

	eventSystem *icsevent.EventSystem

	//manage session
	lastTimestamp time.Time
	isStart       int32

	//media
	invitePayloads []string
	payloadType    icspacketparser.PayloadType
	isFoundPayload bool
	TxConverter    *icsmediaconv.Converter
	RxConverter    *icsmediaconv.Converter
	txSeq          int //first TX seq num
	rxSeq          int //first RX seq num
	STTTx          *stt.STT
	STTRx          *stt.STT
	cs             *readcallsignal.CallSignal

	isSTTStartTimer *time.Timer
	isSTTStart      bool

	dtmf string

	//websocket
	WSConn *icsws.WSClient

	//agent config
	AgentConfig *icsconf.AgentConfig

	//bot
	isBotStart bool
	botStatus  *icshttpclient.ProcessResp
	TcpConn    *icsnet.IcsTCPNet

	//call info
	StartTimeStamp int64
	ChannelID      string
	ServerID       string

	/*//////////////////
	rxFile *os.File
	txFile *os.File
	*/ //////////////////

	//Voice capture conn
	CallSignalNeter icsnet.IcsNeter
	VoiceNeter      icsnet.IcsNeter

	MethodAutomata int

	m *sync.Mutex
}

type IcsSessionID int

const MAX_SESSION_IDLE = time.Hour

const (
	ICS_INBOUND_CALL  = true
	ICS_OUTBOUND_CALL = false
)

//////////////////////////////////////////////////////////////////
//session routine

//init ffmpeg
func init() {
	format.RegisterAll()
}

//on/off check the session idle
func (s *IcsSession) Start() {

	s.SetTimestamp(time.Now())
	//s.isStart = true
	atomic.StoreInt32(&s.isStart, 1)
}

func (s *IcsSession) Stop() {
	l := icslog.GetIcsLog()

	defer func() {
		if err := recover(); err != nil {
			switch v := err.(type) {
			case error:
				icserror.ICSERRNETNotConnectError.SetError(v)
				l.Printf(icslog.LOG_LEVEL_WARN, s.ID, "PANIC!\n%s", string(debug.Stack()))
			}
		}
	}()

	l.Print(icslog.LOG_LEVEL_INFO, s.ID, "Session Stop")
	l.Print(icslog.LOG_LEVEL_INFO, s.ID, "Timer Stop")
	s.isSTTStartTimer.Stop()
	atomic.StoreInt32(&s.isStart, 0)
}

func (s *IcsSession) Run() *icserror.IcsError {
	// MAX_SESSION_IDLE := time.Second * time.Duration(icsconf.GetIcsConfig().SessionExpired.SSec)
	mySessionID := s.GetSessionID()
	l := icslog.GetIcsLog()
	//conf := icsconf.GetIcsConfig()

	s.goroutineID = goid()

	l.Printf(icslog.LOG_LEVEL_INFO, int(mySessionID), "Session [%d] READY\n", mySessionID)

	svc := icssvc.GetServiceStatus()
	for !svc.GetExit() && !svc.GetStop() {
		//get event
		h := icsevent.NewEventH()
		evt, evterr := h.GetEvent(int(mySessionID))
		if evt == nil {
			if evterr != nil {
				//evterr.Print()
				time.Sleep(time.Millisecond)
				continue
			}

			duration := time.Since(s.lastTimestamp)

			if atomic.LoadInt32(&s.isStart) == 1 && duration >= MAX_SESSION_IDLE {
				//Session expired!
				err := icserror.ICSERRSESSMaxSessionIdle

				logmsg := fmt.Sprintf("Session expired. Duration: %v(%v) - %s\n", duration, s.lastTimestamp, err.GetMessage())
				l.Print(icslog.LOG_LEVEL_INFO, s.ID, logmsg)

				s.Stop()
				serr := s.RemoveSession()
				if serr != nil {
					//serr.Print()
					l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "RemoveSession Error %s", serr.GetMessage())
				}

				//return err
			}

			time.Sleep(time.Millisecond)
			continue
		}

		//refresh session timestamp
		s.SetTimestamp(time.Now())

		//l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Get Event[%d]", evt.ID)

		data := evt.GetData()

		switch v := (*data).(type) {
		case *readcallsignal.CallSignal:
			s.cs = v
			l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Get CallSignal Event[%d] - %+v", evt.ID, s.cs)
			//call start
			if s.cs.EventType == "S" { //call started
				switch s.AgentConfig.Action {
				case "voicecapture":
					l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Call Started - Station: %s, Tel: %s", s.cs.Station, s.cs.CustID)
					//fmt.Println("voice capture")
					s.STTRx = stt.NewSTT(nil)
					s.STTTx = stt.NewSTT(nil)

					s.isSTTStart = true

					go s.RecvVoice()
				case "voicegateway":
					l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Call Started - Station: %s, Tel: %s, %+v", s.cs.Station, s.cs.CustID, s.cs)

					//agentname := s.AgentConfig.Name

					s.STTRx = stt.NewSTT(nil)
					go s.RecvVoice()

					url := fmt.Sprintf("http://%s:%d%s",
						s.AgentConfig.BotConfig.IP,
						s.AgentConfig.BotConfig.Port,
						s.AgentConfig.BotConfig.URL2)
					//remove null terminator
					var custid, agentid string
					n := bytes.Index([]byte(s.cs.CustID), []byte{0})
					if n != -1 {
						custid = string([]byte(s.cs.CustID)[:n])
					} else {
						custid = s.cs.CustID
					}
					n = bytes.Index([]byte(s.cs.AgentID), []byte{0})
					if n != -1 {
						agentid = string([]byte(s.cs.AgentID)[:n])
					} else {
						agentid = s.cs.AgentID
					}

					n = bytes.Index([]byte(s.cs.Station), []byte{0})
					var sstation string
					if n != -1 {
						sstation = string([]byte(s.cs.Station)[:n])
					} else {
						sstation = s.cs.Station
					}

					//set callid
					timei := time.Now().UnixNano()
					if len(s.callId) == 0 {
						s.callId = fmt.Sprintf("%d@%s", timei, agentid)
						fmt.Println("callid :", s.callId)
					}

					s.url = url
					s.custid = custid
					s.sstation = sstation

					botRequest := icshttpclient.NewPostProcess(s.url, "INIT", "", s.custid, "ICS_RCP", s.callId, s.sstation, "", "")
					////////////////////////////////////////////////
					//post event to the session
					h := icsevent.NewEventH()
					var evt *icsevent.Event
					var evtErr *icserror.IcsError
					if evt, evtErr = h.AllocEvent(botRequest); evtErr != nil {
						l.Print(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error")
						s.SendVoiceGatewayByeSignal()
						continue
					}
					l.Printf(icslog.LOG_LEVEL_INFO, -1, "Post BOT Request[%d] to Session[%03d]", evt.ID, s.ID)
					h.PostEvent(s.ID, evt)

					/*
						processResp := icshttpclient.PostProcess(url, "INIT", "", custid, "ICS_RCP", s.callId, sstation, "", "")
						//processResp := icshttpclient.PostProcess(url, "INIT", result, custid, "ICS_RCP", s.callId, "", filename)
						if processResp == nil {
							l.Print(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error")
							s.SendVoiceGatewayByeSignal()
							continue
						} else {
							if processResp.ResultCode == 200 {
								s.botStatus = processResp
								s.botToken = processResp.Token
								l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Response : %+v", processResp)

								fmt.Println(">>> ment", processResp.AnnounceMents)
								//tts
								pcm, ttsErr := tts.TTS(processResp.AnnounceMents, 8000)
								if ttsErr != nil {
									l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "TTS Error[%s] - %s",
										processResp.AnnounceMents, ttsErr.GetError())
									s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
									continue
								} else {
									l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "%s!!! TTS Result: [%s] %d bytes",
										agentname, processResp.AnnounceMents, len(pcm))

									//send tts data to voice gateway
									r := responsecs.NewResponse(agentname, responsecs.TTS_COMMAND, responsecs.RC_SUCCESS, len(pcm))
									addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port)
									t, wlen, werr := icsnet.SendCallSignal2(&addr, nil, r.GetData())
									//wlen, werr := s.TcpConn.Write(r.GetData())
									if werr != nil {
										l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS header - %s [%+v]",
											werr.GetError(), s.TcpConn)
										s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
										continue
									}
									l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS header : %d [%s]", wlen, r)

									s.TcpConn = t
									wlen, werr = s.TcpConn.Write(pcm)
									if werr != nil {
										l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS data - %s",
											werr.GetError())
										s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
										continue
									}
									l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS data : %d", wlen)

									l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Barge-In: %s", processResp.Data.BargeIn)
									switch processResp.Data.BargeIn {
									case "Y":
										//s.StartSTT(wlen)
										s.isSTTStart = true
									case "N":
										s.StartSTT(wlen)
										//s.isSTTStart = false
									}
									//s.StartSTT(wlen)
								}
							} else {
								l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error : %+v", processResp)
								s.SendVoiceGatewayByeSignal()
							}
						}
					*/
				}
			} else if s.cs.EventType == "D" { //dtmf
				s.AddDtmf()
				//s.dtmf = s.cs.InOut
				l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "DTMF : %s(%s|%s)", s.cs.InOut, s.dtmf, s.GetDtmf(icsconf.GetIcsConfig().DtmfEndSignal.Signal))
				s.DTMFCB()
			} else {
				fmt.Println("198LINE CALL END!!")
			}
		case *icshttpclient.IcsHttpClient:
			request := v
			l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Get http.Request Event[%d] - %+v", evt.ID, request)
			s.DoScenario(request)
		case *stt.STTResult:
			sttResult := v
			l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Get STT Result Event[%d] - %s, %s", evt.ID, sttResult.GetResult(), sttResult.GetError().GetError())
			s.STTResultCB(sttResult)
			/*
				err := sttResult.GetError()
				if err == icserror.ICSERRSTTOK {
					l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "STT Completed - %s", err)
					s.STTResultCB(sttResult)
				}
			*/
		case icspacketparser.SIP:
			l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Get SIP Event[%d]", evt.ID)
			sip := v
			s.analyzeSIP(&sip)
		case icspacketparser.RTP:
			//l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Get RTP Event[%d]", evt.ID)
			rtp := v
			//fmt.Println(rtp)
			s.analyzeRTP(&rtp)
		//default:
		//fmt.Println(time.Now(), "NOT DEFINED EVENT TYPE!!!!!!!!!!!!!!!!!")
		default:
			l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Event Type : %T", v)
		}

		evt = nil
	}

	return nil
}

func (s *IcsSession) RecvVoice() {
	l := icslog.GetIcsLog()
	conf := icsconf.GetIcsConfig()
	//agentname := conf.AgentConfig[s.ID].Name
	agentname := s.AgentConfig.Name

	var uniq string

	wait := new(sync.WaitGroup)
	wait.Add(1)

	l.Print(icslog.LOG_LEVEL_DEBUG2, s.ID, "Started RecvVoice")

	go func() {
		defer wait.Done()
		start := atomic.LoadInt32(&s.isStart)
		for start == 1 {
			start = atomic.LoadInt32(&s.isStart)
			//receive voice data from voice server
			buf, rlen, rerr := s.VoiceNeter.Read(340)
			if rerr != nil {
				l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to Read VoiceNeter - %s-%s", rerr.GetMessage(), rerr.GetError())
				// s.SendVoiceGatewayByeSignal()
				break
			}

			if strings.Compare(s.AgentConfig.Action, "voicegateway") == 0 { //for barge-in
				if !s.isSTTStart {
					continue
				} else {
					//s.isSTTStartTimer.Stop()
				}
			}

			//parsing voice data header
			voicedata := recorddata.NewVoiceDataHDR(buf[:rlen])

			switch voicedata.Type {
			case 0: //RX
				//var url, custid string
				//var processResp *icshttpclient.ProcessResp
				uniq = fmt.Sprintf("%s-RX-", s.cs.Station)
				//file.Write(voicedata.Payload)
				//file.Sync()
				//STT
				result, rmsval, err := s.STTRx.STT(voicedata)
				// s.STTStatus = s.STTStatus{err, err}

				//l.Printf(icslog.LOG_LEVEL_DEBUG2, a.ID, "[%f]%+v\n", rmsval, voicedata)
				//fmt.Printf("[%f]%+v\n", rms, voicedata)
				if err == icserror.ICSERRSTTContinue {
					//fmt.Printf("RX CONT >>> %f %s\n", rmsval, result)
					continue
				} else if err == icserror.ICSERRSTTBargeIn {
					//send barge-in command to voice gateway
					r := responsecs.NewResponse(agentname, "", responsecs.BARGEIN_COMMAND, responsecs.RC_SUCCESS, 0)
					addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port)
					_, wlen, werr := icsnet.SendCallSignal2(&addr, nil, r.GetData())
					//wlen, werr := s.TcpConn.Write(r.GetData())
					if werr != nil {
						l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send Barge-In Command - %s [%+v]",
							werr.GetError(), s.TcpConn)
						continue
					}
					l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent Barge-In Command : %d", wlen)
				} else if err == icserror.ICSERRSTTOK {
					s.isSTTStart = false
					filename := s.STTRx.Save(uniq, conf.VoiceConfig.Path)
					size := s.STTRx.GetVoiceBufCur()
					s.STTRx.Close()

					switch s.AgentConfig.Action {
					case "voicegateway": //only RX!!!
						sttResult := stt.NewSTTResult(result, err)
						////////////////////////////////////////////////
						//post event to the session
						h := icsevent.NewEventH()
						var evt *icsevent.Event
						var evtErr *icserror.IcsError
						if evt, evtErr = h.AllocEvent(sttResult); evtErr != nil {
							l.Print(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error")
							s.SendVoiceGatewayByeSignal()
							continue
						}
						l.Printf(icslog.LOG_LEVEL_INFO, -1, "Post STT Result[%d] to Session[%03d]", evt.ID, s.ID)
						h.PostEvent(s.ID, evt)

					/*****************************
											if s.botStatus != nil { //processing
												url = fmt.Sprintf("http://%s:%d%s",
													s.AgentConfig.BotConfig.IP,
													s.AgentConfig.BotConfig.Port,
													s.AgentConfig.BotConfig.URL2)
												//remove null terminator
												n := bytes.Index([]byte(s.cs.CustID), []byte{0})
												if n != -1 {
													custid = string([]byte(s.cs.CustID)[:n])
												} else {
													custid = s.cs.CustID
												}
												var agentid string
												n = bytes.Index([]byte(s.cs.AgentID), []byte{0})
												if n != -1 {
													agentid = string([]byte(s.cs.AgentID)[:n])
												} else {
													agentid = s.cs.AgentID
												}

												n = bytes.Index([]byte(s.cs.Station), []byte{0})
												var sstation string
												if n != -1 {
													sstation = string([]byte(s.cs.Station)[:n])
												} else {
													sstation = s.cs.Station
												}

												timei := time.Now().UnixNano()
												if len(s.callId) == 0 {
													s.callId = fmt.Sprintf("%d@%s", timei, agentid)
												}

												//var processResp *icshttpclient.ProcessResp
												if strings.Compare(s.botStatus.Action, "END") != 0 {
													fmt.Println(url, s.botStatus.Action, "", custid, "ICS_RCP", s.callId, s.botToken, "")
													processResp = icshttpclient.PostProcess(url, s.botStatus.Action, result, custid, "ICS_RCP", s.callId, sstation, s.botToken, "")
												}
												//processResp := icshttpclient.PostProcess(url, "INIT", result, custid, "ICS_RCP", s.callId, "", filename)
												if processResp == nil {
													l.Print(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error")
													continue
													// s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
													// break // 특정 session에 대해서 처리하는 부분이라 break가 맞을거같음, 그래야 아랫쪽에서도 문제가 안생김
												} else {
													if processResp.ResultCode == 200 {
														s.botStatus = processResp
														l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Response : %+v", processResp)

														if strings.Compare(s.botStatus.Action, "END") != 0 {
															fmt.Println(">>> ment", processResp.AnnounceMents)
															//tts
															pcm, ttsErr := tts.TTS(processResp.AnnounceMents, 8000)
															if ttsErr != nil {
																l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "TTS Error[%s] - %s",
																	processResp.AnnounceMents, ttsErr.GetError())
																continue
																// s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
																// break
															} else {
																l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "%s!!! TTS Result: [%s]%d bytes",
																	agentname, processResp.AnnounceMents, len(pcm))

																//send tts data to voice gateway
																r := responsecs.NewResponse(agentname, responsecs.TTS_COMMAND, responsecs.RC_SUCCESS, len(pcm))
																addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port)
																t, wlen, werr := icsnet.SendCallSignal2(&addr, nil, r.GetData())
																//wlen, werr := s.TcpConn.Write(r.GetData())
																if werr != nil {
																	l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS header - %s [%+v]",
																		werr.GetError(), s.TcpConn)
																	continue
																	// s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
																	// break
																}
																l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS header : %d", wlen)

																s.TcpConn = t
																wlen, werr = s.TcpConn.Write(pcm)
																if werr != nil {
																	l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS data - %s",
																		werr.GetError())
																	continue
																	// s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
																	// break
																}
																l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS data : %d", wlen)

																l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Barge-In: %s", processResp.Data.BargeIn)
																switch processResp.Data.BargeIn {
																case "Y":
																	//s.StartSTT(wlen)
																	s.isSTTStart = true
																case "N":
																	s.StartSTT(wlen)
																	//s.isSTTStart = false
																}
															}
														} else { //end
															fmt.Println(">>> ment", processResp.AnnounceMents)
															//tts
															pcm, ttsErr := tts.TTS(processResp.AnnounceMents, 8000)
															if ttsErr != nil {
																l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "TTS Error[%s] - %s",
																	processResp.AnnounceMents, ttsErr.GetError())
																continue
																// s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
																// break
															} else {
																l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "%s!!! TTS Result: [%s]%d bytes",
																	agentname, processResp.AnnounceMents, len(pcm))

																//send command BYE to voice gateway
																//send tts data to voice gateway
																r := responsecs.NewResponse(agentname, responsecs.BYE_COMMAND, responsecs.RC_SUCCESS, len(pcm))
																addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port)
																t, wlen, werr := icsnet.SendCallSignal2(&addr, nil, r.GetData())
																//wlen, werr := s.TcpConn.Write(r.GetData())
																if werr != nil {
																	l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS header - %s [%+v]",
																		werr.GetError(), s.TcpConn)
																	continue
																	// s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
																	// break
																}

																l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Barge-In: %s", processResp.Data.BargeIn)
																switch processResp.Data.BargeIn {
																case "Y":
																	//s.StartSTT(wlen)
																	s.isSTTStart = true
																case "N":
																	s.StartSTT(wlen)
																	//s.isSTTStart = false
																}

																s.TcpConn = t
																wlen, werr = s.TcpConn.Write(pcm)
																if werr != nil {
																	l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS data - %s",
																		werr.GetError())
																	continue
																	// s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
																	// break
																}
																l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS data : %d", wlen)
															}
																	//send command BYE to voice gateway
																	//r := responsecs.NewResponse(agentname, responsecs.BYE_COMMAND, responsecs.RC_SUCESS, 0)
																	//addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port)
																	//_, wlen, werr := icsnet.SendCallSignal2(&addr, nil, r.GetData())
																	//if werr != nil {
																		//l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send BYE command - %s [%+v]",
																			//werr.GetError(), s.TcpConn)
																		//continue
																	//}
																//l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent BYE command : %d", wlen)

														}
													} else {
														l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error : %+v", processResp)
													}
												}
											}
					********************************/
					case "voicecapture":
						//TODO: websocket
						//fmt.Println("RX RESULT>>>", result, rms)
						s.rxSeq++
						imsg := icsws.NewIAP()
						imsg.SendMessage("RX", agentname, result, s.rxSeq)
						l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Send Message: %+v", imsg)
						s.WSConn.Write(imsg.String())
					}

					//voice save yn
					if conf.VoiceConfig.SaveYn == "N" {
						l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "[%d]RX Recog Result> %s, PCM(%f), BufLen(%d)",
							s.goroutineID, result, rmsval, size)
					} else {
						l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "[%d]RX Recog Result> %s, PCM(%f), BufLen(%d) %s",
							s.goroutineID, result, rmsval, size, filename)
					}
				} else if err == icserror.ICSERRSTTFail || err == icserror.ICSERRSTTFailEmpty {
					l.Printf(icslog.LOG_LEVEL_WARN, s.ID, "Rx STT Failed - %s", err.GetError())
					s.isSTTStart = false

					//if err == icserror.ICSERRSTTFail {
					uniq = fmt.Sprintf("%s-RX-Fail-", s.cs.Station)
					filename := s.STTRx.Save(uniq, conf.VoiceConfig.Path)
					s.STTRx.Close()
					l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "RX Recog Failed> %s-%v, PCM(%f), %s", err.GetMessage(), err.GetError(), rmsval, filename)

					switch s.AgentConfig.Action {
					case "voicegateway":
						sttResult := stt.NewSTTResult(result, err)
						////////////////////////////////////////////////
						//post event to the session
						h := icsevent.NewEventH()
						var evt *icsevent.Event
						var evtErr *icserror.IcsError
						if evt, evtErr = h.AllocEvent(sttResult); evtErr != nil {
							l.Print(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error")
							s.SendVoiceGatewayByeSignal()
							continue
						}
						l.Printf(icslog.LOG_LEVEL_INFO, -1, "Post STT Result[%d] to Session[%03d]", evt.ID, s.ID)
						h.PostEvent(s.ID, evt)

						/**********************
												url = fmt.Sprintf("http://%s:%d%s",
													s.AgentConfig.BotConfig.IP,
													s.AgentConfig.BotConfig.Port,
													s.AgentConfig.BotConfig.URL2)
												//remove null terminator
												var custid, agentid string
												n := bytes.Index([]byte(s.cs.CustID), []byte{0})
												if n != -1 {
													custid = string([]byte(s.cs.CustID)[:n])
												} else {
													custid = s.cs.CustID
												}
												n = bytes.Index([]byte(s.cs.AgentID), []byte{0})
												if n != -1 {
													agentid = string([]byte(s.cs.AgentID)[:n])
												} else {
													agentid = s.cs.AgentID
												}

												n = bytes.Index([]byte(s.cs.Station), []byte{0})
												var sstation string
												if n != -1 {
													sstation = string([]byte(s.cs.Station)[:n])
												} else {
													sstation = s.cs.Station
												}

												timei := time.Now().UnixNano()
												if len(s.callId) == 0 {
													s.callId = fmt.Sprintf("%d@%s", timei, agentid)
												}

												fmt.Println(url, "STT_FAIL", "", custid, "ICS_RCP", s.callId, s.botToken, "")

												processResp = icshttpclient.PostProcess(url, "STT_FAIL", "", custid, "ICS_RCP", s.callId, sstation, s.botToken, "")
												s.botStatus = processResp
												l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "processResp - %+v", processResp)
												//////////////////////////////////////////////////////////////////

												if strings.Compare(s.botStatus.Action, "END") != 0 {
													fmt.Println(">>> ment", processResp.AnnounceMents)
													//tts
													pcm, ttsErr := tts.TTS(processResp.AnnounceMents, 8000)
													if ttsErr != nil {
														l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "TTS Error[%s] - %s",
															processResp.AnnounceMents, ttsErr.GetError())
														continue
														// s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
														// break
													} else {
														l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "%s!!! TTS Result: [%s]%d bytes",
															agentname, processResp.AnnounceMents, len(pcm))

														//send tts data to voice gateway
														r := responsecs.NewResponse(agentname, responsecs.TTS_COMMAND, responsecs.RC_SUCCESS, len(pcm))
														addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port)
														t, wlen, werr := icsnet.SendCallSignal2(&addr, nil, r.GetData())
														//wlen, werr := s.TcpConn.Write(r.GetData())
														if werr != nil {
															l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS header - %s [%+v]",
																werr.GetError(), s.TcpConn)
															continue
															// s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
															// break
														}
														l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS header : %d", wlen)

														s.TcpConn = t
														wlen, werr = s.TcpConn.Write(pcm)
														if werr != nil {
															l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS data - %s",
																werr.GetError())
															continue
															// s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
															// break
														}
														l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS data : %d", wlen)

														l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Barge-In: %s", processResp.Data.BargeIn)
														switch processResp.Data.BargeIn {
														case "Y":
															//s.StartSTT(wlen)
															s.isSTTStart = true
														case "N":
															s.StartSTT(wlen)
															//s.isSTTStart = false
														}
													}
												} else { //end
													fmt.Println(">>> ment", processResp.AnnounceMents)
													//tts
													pcm, ttsErr := tts.TTS(processResp.AnnounceMents, 8000)
													if ttsErr != nil {
														l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "TTS Error[%s] - %s",
															processResp.AnnounceMents, ttsErr.GetError())
														continue
														// s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
														// break
													} else {
														l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "%s!!! TTS Result: [%s]%d bytes",
															agentname, processResp.AnnounceMents, len(pcm))

														//send command BYE to voice gateway
														//send tts data to voice gateway
														r := responsecs.NewResponse(agentname, responsecs.BYE_COMMAND, responsecs.RC_SUCCESS, len(pcm))
														addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port)
														t, wlen, werr := icsnet.SendCallSignal2(&addr, nil, r.GetData())
														//wlen, werr := s.TcpConn.Write(r.GetData())
														if werr != nil {
															l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS header - %s [%+v]",
																werr.GetError(), s.TcpConn)
															continue
															// s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
															// break
														}
														l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent BYE command header(%d)", wlen)

														s.TcpConn = t
														wlen, werr = s.TcpConn.Write(pcm)
														if werr != nil {
															l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS data - %s",
																werr.GetError())
															continue
															// s.SendVoiceGatewayBotByeSignal(url, custid, sstation)
															// break
														}
														l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS data : %d", wlen)

														l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Barge-In: %s", processResp.Data.BargeIn)
														switch processResp.Data.BargeIn {
														case "Y":
															//s.StartSTT(wlen)
															s.isSTTStart = true
														case "N":
															s.StartSTT(wlen)
															//s.isSTTStart = false
														}
													}
												}
												//////////////////////////////////////////////////////////////////
						*********************************/
					}
					/*
						} else { //empty activity voice
							s.STTRx.Close()
							//fmt.Printf("RX fail>> %+v, %f, %+v\n", result, rms, err)
							//l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "RX Recog Failed(empty result)> %s-%v(%f)", err.GetMessage(), err.GetError(), rmsval)
						}
					*/
				}

			case 1: //TX
				uniq = fmt.Sprintf("%s-TX-", s.cs.Station)
				//STT
				//l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "%s\n%s", s.STTTx, s.STTRx)
				result, rmsval, err := s.STTTx.STT(voicedata)
				//l.Printf(icslog.LOG_LEVEL_DEBUG2, a.ID, "[%f]%+v\n", rmsval, voicedata)
				if err == icserror.ICSERRSTTContinue {
					//fmt.Printf("TX >>> %f, %s\n", rms, result)
					continue
				} else if err == icserror.ICSERRSTTOK {
					filename := s.STTTx.Save(uniq, conf.VoiceConfig.Path)
					size := s.STTTx.GetVoiceBufCur()
					s.STTTx.Close()

					//websocket
					//fmt.Println("TX RESULT>>>", result, rms)
					s.txSeq++
					imsg := icsws.NewIAP()
					imsg.SendMessage("TX", agentname, result, s.txSeq)
					l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Send Message: %+v", imsg)
					s.WSConn.Write(imsg.String())

					l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "[%d]TX Recog Result> %s, PCM(%f), BufLen(%d) %s",
						s.goroutineID, result, rmsval, size, filename)
				} else if err == icserror.ICSERRSTTFail || err == icserror.ICSERRSTTFailEmpty {
					l.Printf(icslog.LOG_LEVEL_WARN, s.ID, "Tx STT Failed - %s", err.GetError())
					if err == icserror.ICSERRSTTFail {
						uniq = fmt.Sprintf("%s-TX-Fail-", s.cs.Station)
						filename := s.STTTx.Save(uniq, conf.VoiceConfig.Path)

						//voice save
						if conf.VoiceConfig.SaveYn == "N" {
							l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "TX Recog Failed> %s-%v, PCM(%f)>",
								err.GetMessage(), err.GetError(), rmsval)
						} else {
							l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "TX Recog Failed> %s-%v, PCM(%f)> %s",
								err.GetMessage(), err.GetError(), rmsval, filename)
						}

						s.STTTx.Close()
					} else { //empty activity voice
						s.STTTx.Close()
						//fmt.Printf("TX fail>> %+v, %f, %+v\n", result, rms, err)
						//l.Printf(icslog.LOG_LEVEL_INFO, a.ID, "TX Recog Failed> %s-%v(%f)", err.GetMessage(), err.GetError(), rmsval)
					}
				}
			default:
				fmt.Printf("Type: %T, value: %v\n", voicedata.Type, voicedata.Type)
			}
		}
		//file.Close()
	}()

	wait.Wait()

	l.Print(icslog.LOG_LEVEL_DEBUG2, s.ID, "Stoped RecvVoice")
}

func (s *IcsSession) StartSTT(length int) {
	l := icslog.GetIcsLog()
	fst := float32(length/16) * 0.6
	//fst := float32(wlen/16) * 0.5
	stttime := int64(fst)
	//stttime := time.Duration(wlen / 16)
	fmt.Println("STT timer", time.Duration(stttime), stttime, time.Now())
	l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "STT timer ", time.Duration(stttime), stttime, time.Now())
	// STTStartTimer := time.NewTimer(time.Millisecond * time.Duration(stttime))
	s.isSTTStartTimer = time.NewTimer(time.Millisecond * time.Duration(stttime))
	//s.isSTTStartTimer = *time.NewTimer(time.Millisecond * time.Duration(wlen/16))
	go func() {
		// <-STTStartTimer.C
		<-s.isSTTStartTimer.C
		s.isSTTStart = true
		// fmt.Println("STT START2", time.Now())
		l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "STT START2 ", time.Now())
	}()
}
