package main

import (
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	_ "github.com/mattn/go-sqlite3"
	"math"
	"net/http"
	"strconv"
)

var router = gin.Default()

func gw_router() {
	router.Use(cors.Default())
	v1 := router.Group("/api/v1")
	{
		v1.GET("/weather", gw_weather_api)
		v1.POST("/renliu", get_renliu_api)
		v1.POST("/feedback", get_pj_api)
		v1.GET("/totalWater", sb_api)
		v1.GET("/totalElectricity", db_api)
		v1.GET("/environmentDate", kq_api)
		v1.GET("/traffic", renliu_api)
		v1.GET("/stink", aq_api)
		v1.GET("/satisfaction", pj_api)
		v1.GET("/seat/:id", seat_api)
	}
	router.Run(":10086")
}

type EventNotificationAlert struct {
	IPADDRESS        string         `xml:"ipAddress" json:"ipAddress"`
	PROTOCOLTYPE     string         `xml:"protocolType" json:"protocolType"`
	MACADDRESS       string         `xml:"macAddress" json:"macAddress"`
	CHANNELID        uint16         `xml:"channelID" json:"channelID"`
	DATETIME         string         `xml:"dateTime" json:"dateTime"`
	ACTIVEPOSTCOUNT  uint16         `xml:"activePostCount" json:"activePostCount"`
	EVENTTYPE        string         `xml:"eventType" json:"eventType"`
	EVENTSTATE       string         `xml:"eventState" json:"eventState"`
	EVENTDESCRIPTION string         `xml:"eventDescription" json:"eventDescription"`
	CHANNELNAME      string         `xml:"channelName" json:"channelName"`
	PEOPLECOUNTING   PeopleCounting `xml:"peopleCounting" json:"peopleCounting"`
}

type PeopleCounting struct {
	STATISTICALMETHODS string    `xml:"statisticalMethods" json:"statisticalMethods"`
	TIMERANGE          Timerange `xml:"TimeRange" json:"TimeRange"`
	ENTER              uint16    `xml:"enter" json:"enter"`
	EXIT               uint16    `xml:"exit" json:"exit"`
	PASS               uint16    `xml:"pass" json:"pass"`
}

type Timerange struct {
	STARTTIME string `xml:"startTime" json:"startTime"`
	ENDTIME   string `xml:"endTime" json:"endTime"`
}

type FeedBack struct {
	FEEDBACK string `json:"feedback"`
	ID       string `json:"id"`
}

var rl_data EventNotificationAlert

func get_renliu_api(c *gin.Context) {
	err := c.Bind(&rl_data)
	check(err)
	send_data(1004)
	c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": rl_data})
}

var pj_data FeedBack

func get_pj_api(c *gin.Context) {
	err = c.Bind(&pj_data)
	check(err)
	send_data(1006)
	c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": pj_data})
}

func sb_api(c *gin.Context) {
	DEVICEDATAS.RLock()
	var data = make(map[string]uint16)
	for _, i := range conf.DEVICES_LIST {
		if i[2] == "yunhorn_sb_c_v1" {
			if DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA["totalWater"] != nil {
				data["totalWater"] = data["totalWater"] + DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA["totalWater"].(uint16)
			}
		}
	}
	DEVICEDATAS.RUnlock()
	c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data})
}

func db_api(c *gin.Context) {
	DEVICEDATAS.RLock()
	var data = make(map[string]float32)
	for _, i := range conf.DEVICES_LIST {
		if i[2] == "yunhorn_db_c_v1" {
			if DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA["totalElectric"] != nil {
				data["totalElectric"] = data["totalElectric"] + DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA["totalElectric"].(float32)
			}
		}
	}
	DEVICEDATAS.RUnlock()
	c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data})
}

func kq_api(c *gin.Context) {
	DEVICEDATAS.RLock()
	var sum float32
	var toinitdata float32 = 0.0
	var data = make(map[string]interface{})
	for _, i := range conf.DEVICES_LIST {
		if i[2] == "yunhorn_kq_c_v1" {
			sum++
			for k, j := range DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA {
				if j != nil {
					data[k] = toinitdata
					data[k] = (data[k].(float32) + j.(float32)) / sum
				}
			}
		}
	}
	DEVICEDATAS.RUnlock()
	c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data})
}

func aq_api(c *gin.Context) {
	DEVICEDATAS.RLock()
	var sum uint16
	var toinitdata uint16 = 0
	var data_buf = make(map[string]interface{})
	var data = make(map[string]interface{})
	for _, i := range conf.DEVICES_LIST {
		if i[2] == "yunhorn_aq_c_v1" {
			sum++
			if DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA["氨气"] != nil {
				data_buf["氨气"] = toinitdata
				data_buf["氨气"] = (data_buf["氨气"].(uint16) + DEVICEDATAS.DATA["yunhorn_aq_c_v1_"+i[3]].DATA["氨气"].(uint16)) / sum
			}
		}
	}
	if data_buf["氨气"] == nil {
		data["stink"] = "无味"
	} else {
		if data_buf["氨气"].(uint16) <= 1 {
			data["stink"] = "无味"
		} else if data_buf["氨气"].(uint16) > 1 && data_buf["氨气"].(uint16) <= 10 {
			data["stink"] = "有味"
		} else if data_buf["氨气"].(uint16) > 10 && data_buf["氨气"].(uint16) <= 40 {
			data["stink"] = "恶臭"
		} else if data_buf["氨气"].(uint16) > 40 && data_buf["氨气"].(uint16) <= 100 {
			data["stink"] = "超级恶臭"
		}
	}
	DEVICEDATAS.RUnlock()
	c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data})
}

func renliu_api(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": traffic_data})
}

func pj_api(c *gin.Context) {
	var data float64
	data = good / (good + bad)
	satisfaction_data.SATISFACTION = Round(data, 2)
	c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": satisfaction_data})
}

func Round(f float64, n int) float64 {
	n10 := math.Pow10(n)
	return math.Trunc((f+0.5/n10)*n10) / n10
}

type Seat_data struct {
	POSITIONLIST   []interface{} `json:"positionList"`
	HASPERSONLIST  []interface{} `json:"hasPersonList"`
	EMPTYPOSITION  uint16        `json:"emptyPosition"`
	OCCUPYPOSITION uint16        `json:"occupyPosition"`
}

func seat_api(c *gin.Context) {
	DEVICEDATAS.RLock()
	type_id := c.Param("id")
	var data Seat_data
	var conf_data [][]interface{}
	for _, i := range conf.GATEWAY_INFO.CONFIG {
		arr := get_seat_device_data(i.ID)
		version, num := arr[0], arr[1]
		for k, j := range i.DATA {
			if DEVICEDATAS.DATA[version+"_"+num].DATA != nil {
				if DEVICEDATAS.DATA[version+"_"+num].DATA["data"+strconv.Itoa(k+1)] != nil {
					j = append(j, DEVICEDATAS.DATA[version+"_"+num].DATA["data"+strconv.Itoa(k+1)])
				}
			}
			conf_data = append(conf_data, j)
		}
	}
	switch type_id {
	case "1":
		data = scan_seat_from_confdata("男厕位", conf_data)
	case "2":
		data = scan_seat_from_confdata("男便池", conf_data)
	case "3":
		data = scan_seat_from_confdata("女厕位", conf_data)
	case "4":
		data = scan_seat_from_confdata("母婴", conf_data)
	case "5":
		data = scan_seat_from_confdata("残卫", conf_data)
	}
	DEVICEDATAS.RUnlock()
	c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data})
}

func get_seat_device_data(id string) []string {
	var data = make([]string, 2)
	for _, i := range conf.DEVICES_LIST {
		if id == i[0] {
			data[0], data[1] = i[2], i[3]
			break
		} else {
			data[0], data[1] = "null", "null"
		}
	}
	return data
}

func scan_seat_from_confdata(T string, conf_data [][]interface{}) Seat_data {
	var data Seat_data
	for _, i := range conf_data {
		if i[0] == T {
			data.POSITIONLIST = append(data.POSITIONLIST, i[1])
			if len(i) < 3 {
				i = append(i, 0)
			}
			data.HASPERSONLIST = append(data.HASPERSONLIST, i[2])
			switch i[2] {
			case 0:
				data.EMPTYPOSITION++
			case 1:
				data.OCCUPYPOSITION++
			}
		}
	}
	return data
}

type WEATHER struct {
	// gorm.Model
	SKYCON             string      `json:"skycon"`
	ICON_URL           string      `json:"icon_url"`
	O3                 float32     `json:"o3"`
	CO                 float32     `json:"co"`
	SO2                float32     `json:"so2"`
	NO2                float32     `json:"no2"`
	TEMPERATURE        float32     `json:"temperature"`
	HUMIDITY           float32     `json:"humidity"`
	PM25               float32     `json:"pm25"`
	PM10               float32     `json:"pm10"`
	CLOUDRATE          float32     `json:"cloudrate"`
	AQI                float32     `json:"aqi"`
	DSWRF              float32     `json:"dswrf"`
	VISIBILITY         float32     `json:"visibility"`
	ULTRAVIOLET_DESC   string      `json:"ultraviolet_desc"`
	PRES               float32     `json:"pres"`
	COMFORT_DESC       string      `json:"comfort_desc"`
	WIND_DIRECTION     float32     `json:"wind_direction"`
	WIND_SPEED         float32     `json:"wind_speed"`
	TEMPERATURE_INDOOR interface{} `json:"temperature_indoor"`
	HUMIDITY_INDOOR    interface{} `json:"humidity_indoor"`
}

func gw_weather_api(c *gin.Context) {
	DEVICEDATAS.RLock()
	rows, _ := db.Query("SELECT skycon, icon_url, o3, co, so2, no2, temperature,  humidity,  pm25, pm10, cloudrate, aqi, dswrf, visibility, ultraviolet_desc, pres, comfort_desc, wind_direction, wind_speed FROM weather order by id DESC limit 1")
	var data WEATHER
	rows.Next()
	rows.Scan(
		&data.SKYCON,
		&data.ICON_URL,
		&data.O3,
		&data.CO,
		&data.SO2,
		&data.NO2,
		&data.TEMPERATURE,
		&data.HUMIDITY,
		&data.PM25,
		&data.PM10,
		&data.CLOUDRATE,
		&data.AQI,
		&data.DSWRF,
		&data.VISIBILITY,
		&data.ULTRAVIOLET_DESC,
		&data.PRES,
		&data.COMFORT_DESC,
		&data.WIND_DIRECTION,
		&data.WIND_SPEED)
	rows.Close()
	var sum float32
	var toinitdata float32 = 0.0
	var data_buf = make(map[string]interface{})
	for _, i := range conf.DEVICES_LIST {
		if i[2] == "yunhorn_kq_c_v1" {
			sum++
			for k, j := range DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA {
				if j != nil {
					data_buf[k] = toinitdata
					data_buf[k] = (data_buf[k].(float32) + j.(float32)) / sum
				}
			}
		}
	}
	data.TEMPERATURE_INDOOR = data_buf["温度"]
	data.HUMIDITY_INDOOR = data_buf["湿度"]
	DEVICEDATAS.RUnlock()
	c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data})
}