package comm

import (
	"encoding/hex"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/jacobsa/go-serial/serial"
	"../pkg/app"
	"../pkg/e"
	"../pkg/setting"
	"../routers/restful"
	"log"
	"net/http"
	"time"
	"unsafe"
)

//一个已经被关闭的channel不会阻塞,已经被关闭的channel会实时返回
//goroutine退出,关闭done来进行广播
var done = make(chan struct{})
var Id = make(chan int)
var timeout = make(chan int)
var ReturnString = make(chan string)
//判断done是否关闭,即是否执行goroutine退出
func cancelled() bool {
	select {
	case <-done:
		return true
	default:
		return false
	}
}

func Int2Byte(data int)(ret []byte){
	var len uintptr = unsafe.Sizeof(data)
	ret = make([]byte, len)
	var tmp int = 0xff
	var index uint = 0
	for index=0; index<uint(len); index++{
		ret[index] = byte((tmp<<(index*8) & data)>>(index*8))
	}
	return ret
}

func OpenComm() {
	var sum byte
	var recLength,dataLength, state int
    comtimeout := 0
	buf := make([]byte, 32)
	recbuf := make([]byte, 1)
	//s_params := make([]interface{}, 1)
	openSerial:
	f, err := serial.Open(*setting.CommSetting)

	if err != nil {
		fmt.Println("Error opening serial port: ", err)
		time.Sleep(1 * time.Second)
		goto openSerial
	}else {
		log.Printf("[info] Serial %s is Started", setting.CommSetting.PortName)
		if comtimeout==0 {
			defer f.Close()
		}
		for {
			sum = (0x55 + 0xAA + 0x06 + 0x01 + 0x03 + 0x01) & 0xFF
            v := 0
			if comtimeout==0 {
				v, _ = <- Id
			}

			comtimeout = 0
			cowidByte := Int2Byte(v)[:3]
			sum = (sum + cowidByte[0] + cowidByte[1] + cowidByte[2]) & 0xFF
			cowidByte = append(cowidByte, sum)
			requestCowid := "55AA06010301" + hex.EncodeToString(cowidByte)

			txData_, err := hex.DecodeString(requestCowid)
			recLength = 0
			state = 0
			_, err = f.Write(txData_)

			fmt.Println(hex.EncodeToString(txData_))
			if err != nil {
				fmt.Println("Error writing to serial port: ", err)
				time.Sleep(1 * time.Second)
				comtimeout = 1
				goto openSerial
			}
			loop:
				for {
					select {
					case <-timeout:
						break loop
					default:
						n, err := f.Read(buf)
						if err != nil {
							//if err != io.EOF {
								fmt.Println("Error reading from serial port: ", err)
								time.Sleep(1 * time.Second)
								comtimeout = 1
								goto openSerial
							//}
							//break loop
						} else if n > 0 {
							buf = buf[:n]
							for _, value := range buf {
								switch state {
								case 0: //头判断
									if value == 0x55 {
										state = 1
										recLength = 1
										recbuf = recbuf[:0]
										recbuf = append(recbuf, (byte)(value&0xFF))
									}
								case 1: //头判断中
									if value == 0xAA {
										state = 2
										recLength = 2
										recbuf = append(recbuf, (byte)(value&0xFF))
									} else {
										state = 0
										recLength = 0
									}
								case 2: //接收数据长度
									state = 3
									recLength = 3
									dataLength = (int)(value + 4)
									recbuf = append(recbuf, (byte)(value&0xFF))
								case 3: //接收数据中
									recbuf = append(recbuf, (byte)(value&0xFF))
									recLength++
									if recLength == dataLength {
                                       fmt.Println(hex.EncodeToString(recbuf))
										ReturnString <- hex.EncodeToString(recbuf)
										state = 0
										recLength = 0
										break loop
									}
								}
							}
						} else {
							time.Sleep(10 * time.Millisecond)
						}
					}
				}
			}
	}
}

func saveData(ReceStr string,x int,y int) (string, error){
	s_params := make([]interface{}, 0)
	//bytelist, err := hex.DecodeString(ReturnS)
	s_params = append(s_params, 1)
	s_params = append(s_params, x)
	s_params = append(s_params, y)
	s_params = append(s_params, 1)
	_, err := restful.ExecQuery("INSERT INTO `cps_m` (`barid`, `x`, `y`) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE barid = ?", s_params)
	if err != nil {
		return "", err
	} else {
		bytelist, err := hex.DecodeString(ReceStr)
		rodecount := (int)((bytelist[2]-5)>>1)
		s_params = s_params[1:3]
		if rodecount>0{
			for i := 0; i < rodecount; i++{
				beaconname := (int)(bytelist[8+2*i])
				rssi := (int)(bytelist[9+2*i])
				s_params = s_params[:2]
				s_params = append(s_params, beaconname)
				s_params = append(s_params, rssi)
				s_params = append(s_params, rssi)
				_, err = restful.ExecQuery("INSERT INTO `cps_d`(`pid`,`beaconid`,`rssi`) "+
					"SELECT (SELECT `id` FROM `cps_m` WHERE `x`=? AND `y`=?),?,?  ON DUPLICATE KEY UPDATE rssi = ?", s_params)

				if err != nil {
					return "", err
				}
			}
			if err == nil{
				return "成功保存", nil
			}
		}else {
			return "没有收到数据", nil
		}
	}
	return "没有收到数据", nil
}

func savePointData(ReceStr string,limit int) (interface{}, error){
	s_params := make([]interface{}, 1)
	//bytelist, err := hex.DecodeString(ReturnS)
	bytelist, err := hex.DecodeString(ReceStr)
	rodecount := (int)((bytelist[2]-5)>>1)
	low := (int)(bytelist[5])
	mid := (int)(bytelist[6])
	mid = mid<<8
	high := (int)(bytelist[7])
	high = high<<16
	tagid := (int)(low|mid|high)
	s_params[0] = tagid
	if rodecount>0{
		for i := 0; i < rodecount; i++{
			beaconname := (int)(bytelist[8+2*i])
			rssi := (int)(bytelist[9+2*i])
			s_params = s_params[:1]
			s_params = append(s_params, beaconname)
			s_params = append(s_params, rssi)
			s_params = append(s_params, rssi)
			_, err = restful.ExecQuery(" INSERT INTO `cps_point`(`tagid`,`beaconid`,`rssi`) "+
				                              " Values( ?, ?, ?)  ON DUPLICATE KEY UPDATE rssi = ?", s_params)
			if err != nil {
				return "", err
			}
		}
		if err == nil{
			s_params = s_params[:2]
			s_params[0] = tagid
			s_params[1] = limit
			resultdata, err := restful.QueryByMap(" SELECT AVG(X) X,AVG(Y) Y FROM  ( "+
			"SELECT `cps_m`.x,`cps_m`.y, SUM(ABS(`cps_d`.`rssi`-`cps_point`.`rssi`)) absrssi "+
			"FROM `cps_d` JOIN `cps_point` ON `cps_d`.`beaconid`=`cps_point`.`beaconid` "+
			"JOIN `cps_m` ON `cps_m`.`id`=`cps_d`.`pid` WHERE  `cps_point`.`tagid`= ? "+
			"GROUP BY `cps_m`.x,`cps_m`.y "+
			"ORDER BY SUM(ABS(`cps_d`.`rssi`-`cps_point`.`rssi`)) "+
			"LIMIT ?) AS d "		, 0,0,s_params)
			if err != nil {
				return "", err
			} else {
				return resultdata, nil
			}
		}
	}else {
		return "没有收到数据", nil
	}
	return "没有收到数据", nil
}


func ProcessHttp(c *gin.Context) {
	var (
		appG = app.Gin{C: c}
	)

	id := 0//com.StrTo(c.Param("id")).MustInt()
	x := 0//com.StrTo(c.Param("x")).MustInt()
	y := 0//com.StrTo(c.Param("y")).MustInt()
	Id <- id
	select {
	case ReturnS := <- ReturnString: //拿到锁
		if x>=0 && y>=0{
			returnData, err := saveData(ReturnS,x,y)
			if err  != nil{
				appG.Response(http.StatusOK, e.ERROR, err.Error())
			}else {
				appG.Response(http.StatusOK, e.SUCCESS, returnData)
			}
		}else {
			returnData, err := savePointData(ReturnS,1)
			if err  != nil{
				appG.Response(http.StatusOK, e.ERROR, err.Error())
			}else {
				appG.Response(http.StatusOK, e.SUCCESS, returnData)
			}
		}
	case <-time.After(10 * time.Second): //超时5s
		timeout <- 1
		appG.Response(http.StatusOK, e.ERROR, "超时")
	}
}

func ProcessHttpCPS(c *gin.Context) {
	var (
		appG = app.Gin{C: c}
	)

	id := 0//com.StrTo(c.Param("id")).MustInt()
	limit := 0//com.StrTo(c.Param("limit")).MustInt()
	Id <- id
	select {
	case ReturnS := <- ReturnString: //拿到锁
		{

			returnData, err := savePointData(ReturnS, limit)
			if err  != nil{
				appG.Response(http.StatusOK, e.ERROR, err.Error())
			}else {
				appG.Response(http.StatusOK, e.SUCCESS, returnData)
			}
		}
	case <-time.After(10 * time.Second): //超时5s
		timeout <- 1
		appG.Response(http.StatusOK, e.ERROR, "超时")
	}
}