package icsapp

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"

	"gitlab.com/cinnamon/voiceagent/icsconf"
	"gitlab.com/cinnamon/voiceagent/icserror"
	"gitlab.com/cinnamon/voiceagent/icsevent"
	"gitlab.com/cinnamon/voiceagent/icshttp"
	"gitlab.com/cinnamon/voiceagent/icshttpclient"
	"gitlab.com/cinnamon/voiceagent/icslog"
	"gitlab.com/cinnamon/voiceagent/icsnet"
	"gitlab.com/cinnamon/voiceagent/icssessionmanager"
	"gitlab.com/cinnamon/voiceagent/icssvc"
	"gitlab.com/cinnamon/voiceagent/icsws"
	"gitlab.com/cinnamon/voiceagent/recorddata"
	"gitlab.com/cinnamon/voiceagent/recorddata/readcallsignal"
)

const (
	LINEEND1 = "\r\n"
	LINEEND2 = "EOM"
)

type IcsExec struct {
	service *icssvc.IcsService
	config  *icsconf.IcsConfig
	httpsrv *icshttp.Router
	hbNet   *icsnet.IcsTCPNet
	sttNet  *icsnet.IcsTCPNet
	csNet   *icsnet.IcsTCPNet
	ttsNet  *icsnet.IcsTCPNet
	cmdNet  *icsnet.IcsTCPNet
}

func Init(conf *icsconf.IcsConfig) (e *IcsExec) {
	e = &IcsExec{}
	e.service = icssvc.GetServiceStatus()
	e.config = conf
	e.httpsrv = icshttp.NewRouter()

	return e
}

func (exe IcsExec) Execute() *icserror.IcsError {
	l := icslog.GetIcsLog()

	for !exe.service.GetExit() {
		for exe.service.GetStop() {
			time.Sleep(time.Millisecond)
		}

		//init session manager and run
		sm := icssessionmanager.NewSessionManager()
		sm.Load()

		/////////////////////////////////////////////////////////////////////
		//start Heart beat TCP server
		// hbDone := make(chan *icserror.IcsError)
		// if exe.config.HeartBeat.Value {
		// 	go func() {
		// 		saddr := fmt.Sprintf(":%d", exe.config.HeartBeat.Port)
		// 		hbladdr := icsnet.NewNetAddrWithIPAddr(saddr)
		// 		var hbErr *icserror.IcsError
		// 		//set handler
		// 		exe.hbNet, hbErr = icsnet.ListenAndServeTCP(&hbladdr, nil, LINEEND1, TCPConnHandlerHeartBeat)
		// 		if hbErr != nil {
		// 			l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Heart beat Listen - %s", hbErr.GetError())
		// 			hbDone <- hbErr
		// 		} else {
		// 			l.Printf(icslog.LOG_LEVEL_INFO, -1, "Liesting Heart beat - %s", saddr)
		// 		}
		// 	}()
		// }

		// /////////////////////////////////////////////////////////////////////
		// //start Call signal TCP server
		// csDone := make(chan *icserror.IcsError)
		// p1 := &exe.config.ServerConfig.CSConfig.Port
		// go func() {
		// 	//saddr := fmt.Sprintf("%s:%d", exe.config.STTConfig.SrcIP, exe.config.STTConfig.Port)
		// 	cslAddr := icsnet.NewNetAddrWithIPPort("0.0.0.0", *p1)
		// 	//cslAddr := icsnet.NewNetAddrWithIPPort("0.0.0.0", exe.config.AgentConfig[idx].CSConfig.Port)
		// 	//cslAddr := icsnet.NewNetAddrWithIPPort("0.0.0.0", exe.config.AgentConfig[iter].CSConfig.Port)
		// 	var csErr *icserror.IcsError
		// 	//set handler
		// 	exe.csNet, csErr = icsnet.ListenAndServeTCP(&cslAddr, nil, LINEEND2, TCPConnHandlerCS)
		// 	if csErr != nil {
		// 		l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Call Signal Listen failure - %s", csErr.GetMessage())
		// 		csDone <- csErr
		// 	} else {
		// 		l.Printf(icslog.LOG_LEVEL_INFO, -1, "Listening Call Signal - %s", cslAddr)
		// 	}
		// }()
		// /////////////////////////////////////////////////////////////////////
		// //start STT TCP server
		// sttDone := make(chan *icserror.IcsError)
		// if exe.config.STTConfig.Value {
		// 	go func() {
		// 		saddr := fmt.Sprintf("%s:%d", exe.config.STTConfig.SrcIP, exe.config.STTConfig.Port)
		// 		STTladdr := icsnet.NewNetAddrWithIPAddr(saddr)
		// 		var sttErr *icserror.IcsError
		// 		//set handler
		// 		exe.sttNet, sttErr = icsnet.ListenAndServeTCP(&STTladdr, nil, LINEEND1, TCPConnHandlerSTT)
		// 		if sttErr != nil {
		// 			l.Printf(icslog.LOG_LEVEL_ERROR, -1, "STT Listen failure - %s", sttErr.GetMessage())
		// 			sttDone <- sttErr
		// 		} else {
		// 			l.Printf(icslog.LOG_LEVEL_INFO, -1, "Listening STT - %s", saddr)
		// 		}
		// 		//sttDone <- nil
		// 	}()
		// }

		// /////////////////////////////////////////////////////////////////////
		// //start TTS TCP server
		// ttsDone := make(chan *icserror.IcsError)
		// if exe.config.TTSConfig.Value {
		// 	go func() {
		// 		saddr := fmt.Sprintf("%s:%d", exe.config.TTSConfig.SrcIP, exe.config.TTSConfig.Port)
		// 		TTSladdr := icsnet.NewNetAddrWithIPAddr(saddr)
		// 		var ttsErr *icserror.IcsError
		// 		//set handler
		// 		exe.ttsNet, ttsErr = icsnet.ListenAndServeTCP(&TTSladdr, nil, LINEEND2, TCPConnHandlerTTS)
		// 		if ttsErr != nil {
		// 			l.Printf(icslog.LOG_LEVEL_ERROR, -1, "TTS Listen - %s", ttsErr.GetMessage())
		// 			ttsDone <- ttsErr
		// 		} else {
		// 			l.Printf(icslog.LOG_LEVEL_INFO, -1, "Listening TTS - %s", saddr)
		// 		}
		// 		//ttsDone <- nil
		// 	}()
		// }

		// /////////////////////////////////////////////////////////////////////
		// //start command TCP server
		// cmdDone := make(chan *icserror.IcsError)
		// if exe.config.CommandConfig.Value {
		// 	go func() {
		// 		saddr := fmt.Sprintf("%s:%d", exe.config.CommandConfig.SrcIP, exe.config.CommandConfig.Port)
		// 		CMDladdr := icsnet.NewNetAddrWithIPAddr(saddr)
		// 		var cmdErr *icserror.IcsError
		// 		//set handler
		// 		exe.cmdNet, cmdErr = icsnet.ListenAndServeTCP(&CMDladdr, nil, LINEEND2, TCPConnHandlerCommand)
		// 		if cmdErr != nil {
		// 			l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Bot Command Listen - %s", cmdErr.GetMessage())
		// 			cmdDone <- cmdErr
		// 		} else {
		// 			l.Printf(icslog.LOG_LEVEL_INFO, -1, "Listeing Bot Command Listen - %s", saddr)
		// 		}
		// 		//ttsDone <- nil
		// 	}()
		// }

		/////////////////////////////////////////////////////////////////////
		//make http handler
		httpDone := make(chan error)
		if exe.config.HTTPConfig.Value {
			icshttp.BuildHandler(exe.httpsrv)
			l.Print(icslog.LOG_LEVEL_DEBUG2, -1, "Registered http handlers")

			//start http server
			go func() {
				saddr := fmt.Sprintf(":%d", exe.config.HTTPConfig.Port)
				httpErr := http.ListenAndServe(saddr, exe.httpsrv)
				if httpErr != nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, -1, "HTTP Listen failed - %v", httpErr)
					fmt.Println("HTTP Listen failed -", httpErr)
					httpDone <- httpErr
				} else {
					l.Printf(icslog.LOG_LEVEL_INFO, -1, "HTTP Listen - %s", saddr)
				}
				//httpDone <- nil
			}()
		}

		select {
		// case hbch := <-hbDone:
		// 	if hbch != nil {
		// 		return hbch
		// 	}
		// case sttch := <-sttDone:
		// 	if sttch != nil {
		// 		return sttch
		// 	}
		// 	/*
		// 		case csch := <-csDone:
		// 			if csch != nil {
		// 				return csch
		// 			}
		// 	*/
		// case ttsch := <-ttsDone:
		// 	if ttsch != nil {
		// 		return ttsch
		// 	}
		// case cmdch := <-cmdDone:
		// 	if cmdch != nil {
		// 		return cmdch
		// 	}
		case httpch := <-httpDone:
			if httpch != nil {
				icserror.ICSERRAPPHTTP.SetError(httpch)
				return icserror.ICSERRAPPHTTP
			}
		}
	}

	return nil
}

func TCPConnHandlerHeartBeat(t *icsnet.IcsTCPNet, bufend string) {
	l := icslog.GetIcsLog()
	l.Printf(icslog.LOG_LEVEL_INFO, -1, "[HeartBeat] Conencted - %s", t.RemoteAddr().String())
	fmt.Printf("[HeartBeat] Conencted - %s\n", t.RemoteAddr().String())

	defer t.Close()

	for {
		buf, rlen, rerr := t.ReadS(0, bufend)
		if rerr != nil {
			fmt.Println("Reads Error!", rerr.GetError())
			break
		} else {
			l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "[%d] %s", rlen, string(buf))
			fmt.Printf("[%d] %s\n", rlen, string(buf))
			buf = nil
		}
	}
}

func TCPConnHandlerSTT(t *icsnet.IcsTCPNet, bufend string) {
	l := icslog.GetIcsLog()
	l.Printf(icslog.LOG_LEVEL_INFO, -1, "[STT] Conencted - %s", t.RemoteAddr().String())
	fmt.Printf("[STT] Conencted - %s\n", t.RemoteAddr().String())

	defer t.Close()

	for {
		buf, rlen, rerr := t.ReadS(recorddata.MAX_CALLSIGNAL_PACKET_LEN, bufend)
		if rerr != nil {
			fmt.Println("Reads Error!", rerr.GetError())
			break
		} else {
			l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "STT - [%d] %s", rlen, string(buf))
			fmt.Printf("[%d] %s\n", rlen, string(buf))

			cs := readcallsignal.NewCallSignal(buf)
			l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "STT - call signal \n%v", cs)
			buf = nil
		}
	}
}

func TCPConnHandlerTTS(t *icsnet.IcsTCPNet, bufend string) {
	l := icslog.GetIcsLog()
	l.Printf(icslog.LOG_LEVEL_INFO, -1, "[TTS] Conencted - %s", t.RemoteAddr().String())
	fmt.Printf("[TTS] Conencted - %s\n", t.RemoteAddr().String())

	defer t.Close()

	for {
		buf, rlen, rerr := t.ReadS(0, bufend)
		if rerr != nil {
			fmt.Println("Reads Error!", rerr.GetError())
			break
		} else {
			l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "TTS - [%d] %s", rlen, string(buf))
			fmt.Printf("[%d] %s\n", rlen, string(buf))
			buf = nil
		}
	}
}

//processing bot command
func TCPConnHandlerCommand(t *icsnet.IcsTCPNet, bufend string) {
	l := icslog.GetIcsLog()
	//conf := icsconf.GetIcsConfig()
	l.Printf(icslog.LOG_LEVEL_INFO, -1, "[Bot Command] Conencted - %s", t.RemoteAddr().String())

	defer func() {
		l.Printf(icslog.LOG_LEVEL_INFO, -1, "[Bot Command] Closed - %s", t.RemoteAddr().String())
		t.Close()
	}()

	for {
		buf, rlen, rerr := t.ReadS(81, bufend)
		//buf, rlen, rerr := t.ReadS(0, bufend)
		if rerr != nil {
			if rerr.GetError() != io.EOF {
				//fmt.Println("Reads Error!", rerr.GetError())
				l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "[Bot Command] Reads Error! - %s[%s]",
					rerr.GetError(), string(buf))
			}
			/*
				aerr := rerr.GetError()
				if aerr.Error() == "EOF" {
					fmt.Println("Reads Error EOFFF!", rerr.GetError())
				}
			*/
			break
		} else {
			l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "Recved Command - [%d] %s", rlen, string(buf))
			//fmt.Printf("[%d] %s\n", rlen, string(buf))

			cs := readcallsignal.NewCallSignal(buf)
			if cs == nil {
				l.Print(icslog.LOG_LEVEL_DEBUG2, -1, "[Call Signal] CallSignal Parsing Error!")
				buf = nil
				return
			}

			n := bytes.Index([]byte(cs.ChannelID), []byte{0})
			if n != -1 {
				cs.ChannelID = string([]byte(cs.ChannelID)[:n])
			}
			n = bytes.Index([]byte(cs.Station), []byte{0})
			if n != -1 {
				cs.Station = string([]byte(cs.Station)[:n])
			}
			n = bytes.Index([]byte(cs.AgentID), []byte{0})
			if n != -1 {
				cs.AgentID = string([]byte(cs.AgentID)[:n])
			}
			l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "Call Signal - [%d] chID: %s, SID: %s, Station: %s, AgentID: %s, EventType: %s, CustTel: %s, %d:%d",
				len(buf),
				cs.ChannelID,
				cs.ServerID,
				cs.Station,
				cs.AgentID,
				cs.EventType,
				cs.CustID,
				cs.StartTime,
				cs.EndTime)
			//fmt.Printf("345LINE [%d] %s\n", len(buf), string(buf))

			if strings.Compare(cs.EventType, "S") == 0 { //START CALL
				l.Print(icslog.LOG_LEVEL_INFO, -1, "Call Started")
				//alloc session with station
				session, serr := icssessionmanager.AllocSession(cs.ChannelID, cs.ServerID, cs.Station, "", true)
				if serr != nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Session Aloocation Failure. Check Licensed Session Number - %s", serr.GetError())
					buf = nil
					return
				}

				//find agent conf
				//if session.AgentConfig == nil {
				agentConf := session.FindAgentConfig(cs.AgentID)
				if agentConf == nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Could not find Agent Config - %s", cs.AgentID)
					buf = nil
					return
				}
				session.SetAgentConfig(agentConf)
				l.Printf(icslog.LOG_LEVEL_DEBUG, session.ID, "Set Agent Config - %s", cs.AgentID)
				//}

				//set tcp connection to session's for response
				session.TcpConn = t

				//listen voice port
				vraddr := icsnet.NewNetAddrWithIPPort("0.0.0.0", session.AgentConfig.Port)
				//vraddr := icsnet.NewNetAddrWithIPPort("0.0.0.0", conf.AgentConfig[session.ID].Port)
				session.VoiceNeter = icsnet.NewUDP(&vraddr, nil)
				lerr := session.VoiceNeter.Listen()
				if lerr != nil {
					l.Printf(icslog.LOG_LEVEL_FATAL, session.ID, "Port[%s] Listen Failure - %s", vraddr, lerr.GetError())
				} else {
					l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Voice port listening - %s", vraddr)
				}

				/*
					url := fmt.Sprintf("http://%s:%d%s",
						session.AgentConfig.BotConfig.IP,
						session.AgentConfig.BotConfig.Port,
						session.AgentConfig.BotConfig.URL)
					icshttpclient.PostServiceInfo(url, session.AgentConfig.BotConfig.CustTel)
				*/

				//sesion start
				session.Start()

				////////////////////////////////////////////////
				//post event to the session
				h := icsevent.NewEventH()
				var evt *icsevent.Event
				var evtErr *icserror.IcsError
				if evt, evtErr = h.AllocEvent(cs); evtErr != nil {
					//evtErr.Print()
					return
				}
				l.Printf(icslog.LOG_LEVEL_INFO, -1, "Post SIP event[%d] to Session[%03d]", evt.ID, session.ID)
				h.PostEvent(int(session.GetSessionID()), evt)

			} else if strings.Compare(cs.EventType, "D") == 0 { //DTMF
				l.Printf(icslog.LOG_LEVEL_INFO, -1, "DTMF Event - %s", cs.InOut)

				//find session
				session, serr := icssessionmanager.FindSession(cs)
				if serr != nil || session == nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Finding Session Failure - %s", serr.GetError())
					buf = nil
					return
				}
				////////////////////////////////////////////////
				//post event to the session
				h := icsevent.NewEventH()
				var evt *icsevent.Event
				var evtErr *icserror.IcsError
				if evt, evtErr = h.AllocEvent(cs); evtErr != nil {
					//evtErr.Print()
					return
				}
				l.Printf(icslog.LOG_LEVEL_INFO, -1, "Post SIP event[%d] to Session[%03d]", evt.ID, session.ID)
				h.PostEvent(int(session.GetSessionID()), evt)
			} else if strings.Compare(cs.EventType, "E") == 0 { //END CALL
				l.Print(icslog.LOG_LEVEL_INFO, -1, "Call Ended")

				//find session
				session, serr := icssessionmanager.FindSession(cs)
				if serr != nil || session == nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Finding Session Failure - %s", serr.GetError())
					buf = nil
					return
				}

				//find agent conf
				if session.AgentConfig == nil {
					agentConf := session.FindAgentConfig(cs.AgentID)
					if agentConf == nil {
						l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Could not find Agent Config - %s", cs.AgentID)
						buf = nil
						return
					}
					session.SetAgentConfig(agentConf)
				}

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

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

					scallID := session.GetCallID()
					botToken := session.GetBotToken()

					//send hangup to bot
					processResp := icshttpclient.PostProcess(url, "HANGUP", "", custid, "ICS_RCP", scallID, sstation, botToken, "")
					l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "CALL HANGUP - %+v", processResp)
				}

				//close voiceneter
				verr := session.VoiceNeter.Close()
				if verr != nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to close Voice port - %s", verr.GetError())
				} else {
					l.Print(icslog.LOG_LEVEL_INFO, session.ID, "Closed Voice port")
				}

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

			buf = nil
		}
	}
}

//from VoiceCapture
func TCPConnHandlerCS(t *icsnet.IcsTCPNet, bufend string) {
	l := icslog.GetIcsLog()
	//conf := icsconf.GetIcsConfig()

	l.Printf(icslog.LOG_LEVEL_INFO, -1, "[Call Signal] Connected - %s", t.RemoteAddr().String())

	defer t.Close()

	for {
		buf, _, rerr := t.ReadS(recorddata.MAX_CALLSIGNAL_PACKET_LEN, bufend)
		//buf, _, rerr := t.ReadS(61, bufend)
		//buf, rlen, rerr := t.ReadS(0, bufend)
		if rerr != nil {
			if aerr := rerr.GetError(); aerr != io.EOF {
				l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "[Call Signal] Reads Error! - %s", rerr.GetError())
			}
			buf = nil
			return
		} else {
			cs := readcallsignal.NewCallSignal(buf)
			if cs == nil {
				l.Print(icslog.LOG_LEVEL_DEBUG2, -1, "[Call Signal] CallSignal Parsing Error!")
				buf = nil
				return
			}
			//var agentid string
			n := bytes.Index([]byte(cs.CustID), []byte{0})
			if n != -1 {
				cs.CustID = string([]byte(cs.CustID)[:n])
			}
			n = bytes.Index([]byte(cs.AgentID), []byte{0})
			if n != -1 {
				cs.AgentID = string([]byte(cs.AgentID)[:n])
			}
			n = bytes.Index([]byte(cs.ChannelID), []byte{0})
			if n != -1 {
				cs.ChannelID = string([]byte(cs.ChannelID)[:n])
			}
			l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "Call Signal - [%d] chID: %s, SID: %s, Station: %s, AgentID: %s, EventType: %s, CustTel: %s, %d:%d",
				len(buf),
				cs.ChannelID,
				cs.ServerID,
				cs.Station,
				cs.AgentID,
				cs.EventType,
				cs.CustID,
				cs.StartTime,
				cs.EndTime)
			fmt.Printf("345LINE [%d] %s\n", len(buf), string(buf))

			if strings.Compare(cs.EventType, "S") == 0 { //START CALL
				l.Print(icslog.LOG_LEVEL_INFO, -1, "Call Started")
				session, serr := icssessionmanager.AllocSession(cs.ChannelID, cs.ServerID, cs.Station, "", true)
				if serr != nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Session Aloocation Failure. Check Licensed Session Number - %s", serr.GetError())
					buf = nil
					return
				}

				//find agent conf
				//if session.AgentConfig == nil {
				agentConf := session.FindAgentConfig(cs.AgentID)
				if agentConf == nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Could not find Agent Config - %s", cs.AgentID)
					buf = nil
					return
				}
				session.SetAgentConfig(agentConf)
				l.Printf(icslog.LOG_LEVEL_DEBUG, session.ID, "Set Agent Config - %s", cs.AgentID)
				//}

				//listen voice port
				vraddr := icsnet.NewNetAddrWithIPPort("0.0.0.0", session.AgentConfig.Port)
				session.VoiceNeter = icsnet.NewUDP(&vraddr, nil)
				lerr := session.VoiceNeter.Listen()
				if lerr != nil {
					l.Printf(icslog.LOG_LEVEL_FATAL, session.ID, "Port[%s] Listen Failure - %s", vraddr, lerr.GetError())
				} else {
					l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Voice port open - %s", vraddr)
				}

				//connect to websocket server
				//TODO: error-handling!!
				wshost := fmt.Sprintf("%s:%d", session.AgentConfig.WSConfig.IP, session.AgentConfig.WSConfig.Port)
				wspath := fmt.Sprintf("/%s/%s/websocket", cs.Station, cs.Station) //cs.AgentID)
				path := fmt.Sprintf("%s%s", session.AgentConfig.WSConfig.Path, wspath)
				//path := fmt.Sprintf("%s%s", session.AgentConfig.WSConfig.Path, "/123/01234567/websocket")
				//path := fmt.Sprintf("%s%s", conf.AgentConfig[session.ID].WSConfig.Path, "/123/01234567/websocket")
				session.WSConn = icsws.NewWSClient(wshost, path)
				wserr := session.WSConn.Connect()
				if wserr != nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to connect Websocket server[%s/%s] - %s",
						wshost, path, wserr.GetError())
				} else {
					//connect
					imsg := icsws.NewIAP()
					imsg.Connect()
					ierr := session.WSConn.Write(imsg.String())
					if ierr != nil {
						l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to connect Websocket server[%s/%s] - %s",
							wshost, path, ierr.GetError())
					} else {
						for iter := 0; iter < 3; iter++ {
							connected, ierr := session.WSConn.Read()
							if ierr != nil {
								l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to connect Websocket server[%s/%s] - %s",
									wshost, path, ierr.GetError())
							} else {
								if !strings.Contains(string(connected), "CONNECTED") {
									l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to connect Websocket server[%s/%s]. Retry - %d",
										wshost, path, iter)
									continue
								} else {
									l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Connected Websocket server - %s",
										string(connected))
									break
								}
							}
						}
						//subscribe
						agentname := session.AgentConfig.Name
						imsg.Subscribe(agentname)
						ierr = session.WSConn.Write(imsg.String())
						if ierr != nil {
							l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to Subscribe - %s", ierr.GetError())
						} else {
							l.Print(icslog.LOG_LEVEL_INFO, session.ID, "Subscribe Websocket")
						}
						//room in
						imsg.RoomIn(agentname, agentname)
						ierr = session.WSConn.Write(imsg.String())
						if ierr != nil {
							l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to sent Room-In - %s", ierr.GetError())
						} else {
							l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Sent Room-In to Websocket server [%s]", imsg.String())
						}
						//call start
						var custid string
						n := bytes.Index([]byte(cs.CustID), []byte{0})
						if n != -1 {
							custid = string([]byte(cs.CustID)[:n])
						} else {
							custid = cs.CustID
						}
						imsg.CallStart(agentname, custid)
						ierr = session.WSConn.Write(imsg.String())
						if ierr != nil {
							l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to sent Call Start - %s", ierr.GetError())
						} else {
							l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Sent Call start to Websocket server [%s]", imsg.String())
						}
					}
				}

				session.Start()

				////////////////////////////////////////////////
				h := icsevent.NewEventH()
				var evt *icsevent.Event
				var evtErr *icserror.IcsError
				if evt, evtErr = h.AllocEvent(cs); evtErr != nil {
					//evtErr.Print()
					return
				}
				l.Printf(icslog.LOG_LEVEL_INFO, -1, "Post SIP event[%d] to Session[%03d]", evt.ID, session.ID)
				h.PostEvent(int(session.GetSessionID()), evt)

				buf = nil
			} else if strings.Compare(cs.EventType, "E") == 0 { //END CALL
				l.Print(icslog.LOG_LEVEL_INFO, -1, "Call Ended")
				session, serr := icssessionmanager.FindSession(cs)
				if serr != nil || session == nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Finding Session Failure - %s", serr.GetError())
					buf = nil
					return
				}

				//find agent conf
				if session.AgentConfig == nil {
					agentConf := session.FindAgentConfig(cs.AgentID)
					if agentConf == nil {
						l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Could not find Agent Config - %s", cs.AgentID)
						buf = nil
						return
					}
					session.SetAgentConfig(agentConf)
				}

				//close voiceneter
				verr := session.VoiceNeter.Close()
				if verr != nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failted to close Voice port - %s", verr.GetError())
				} else {
					l.Print(icslog.LOG_LEVEL_INFO, session.ID, "Close Voice port")
				}

				agentname := session.AgentConfig.Name
				//agentname := conf.AgentConfig[session.ID].Name
				imsg := icsws.NewIAP()
				//call end
				var custid string
				n := bytes.Index([]byte(cs.CustID), []byte{0})
				if n != -1 {
					custid = string([]byte(cs.CustID)[:n])
				} else {
					custid = cs.CustID
				}
				imsg.CallEnd(agentname, custid)
				ierr := session.WSConn.Write(imsg.String())
				if ierr != nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to sent Call End - %s", ierr.GetError())
				} else {
					l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Sent Call End to Websocket server [%s]", imsg.String())
				}
				time.Sleep(time.Second)
				//room out
				imsg.RoomOut(agentname, agentname)
				ierr = session.WSConn.Write(imsg.String())
				if ierr != nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to sent Room-Out - %s", ierr.GetError())
				} else {
					l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Sent Room-Out to Websocket server [%s]", imsg.String())
				}
				//disconnect stomp
				imsg.Disconnect()
				ierr = session.WSConn.Write(imsg.String())
				if ierr != nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to sent Disconnect - %s", ierr.GetError())
				} else {
					l.Print(icslog.LOG_LEVEL_INFO, session.ID, "Sent Disconnect to Websocket server")
				}
				//close ws connection
				verr = session.WSConn.Close()
				if verr != nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to Close Websocket Connection - %s", verr.GetError())
				} else {
					l.Print(icslog.LOG_LEVEL_INFO, session.ID, "Close Websocket Connection")
				}

				session.Stop()
				serr = session.RemoveSession()
				if serr != nil {
					l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "RemoveSession Error %s", serr.GetMessage())
				}
				buf = nil
				return
			}

		}
	}
}
