package test_data

import (
	"bufio"
	"encoding/json"
	"errors"
	"github.com/shopspring/decimal"
	"log"
	"math"
	"os"
	"sort"
	"strconv"
	"strings"
	"testData/global"
	"testData/model"
	"testData/request"
)

// QuerySelection 查询可选择的参数
func QuerySelection(req *request.QuerySelection) map[string][]string {
	return LotInMultipleFilesSelection(req.Product, req.Lot, req.PBI)
}

// Histogram 直方图
func Histogram(req *request.Histogram) ([]*model.Histogram, error) {
	var fTHistogram []*model.Histogram
	var x, groups []string
	var xMax, xMin string

	//var datas [][]string
	//fieldMap := make(map[string]int)
	if len(req.SubBatch) == 0 && len(req.WaferID) == 0 {
		//datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI, req.Step)
		groups = append(groups, "")
	} else if len(req.SubBatch) != 0 {
		groups = req.SubBatch
	} else if len(req.WaferID) != 0 {
		groups = req.WaferID
	}

	for _, group := range groups {
		var datas [][]string
		fieldMap := make(map[string]int)
		if group == "" {
			datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI)
		} else if len(req.SubBatch) != 0 {
			datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, group, "")
		} else if len(req.WaferID) != 0 {
			datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, "", group)
		}

		left := req.Average - req.Offset*req.StandardDeviation
		right := req.Average + req.Offset*req.StandardDeviation
		for _, selection := range req.Selections {
			if _, ok := fieldMap[selection]; !ok {

				continue
			}
			if len(req.Site) == 0 {
				var n float64
				var sumSelection float64 = 0
				// 计算最大值、最小值、标准差、均值、数量
				//var standardDeviation float64
				var max, min string
				for _, data := range datas {
					selectionDecimal, _ := decimal.NewFromString(data[fieldMap[selection]])
					if req.XMax != "" && req.XMin != "" {
						xMaxDecimal, _ := decimal.NewFromString(req.XMax)
						xMinDecimal, _ := decimal.NewFromString(req.XMin)
						if !(selectionDecimal.LessThanOrEqual(xMaxDecimal) && xMinDecimal.LessThanOrEqual(selectionDecimal)) {
							continue
						}
					}

					if req.Offset != 0 {
						leftDecimal := decimal.NewFromFloat(left)
						rightDecimal := decimal.NewFromFloat(right)
						if selectionDecimal.LessThan(leftDecimal) || rightDecimal.LessThan(selectionDecimal) {
							continue
						}
					}
					// 筛选SBin
					var binInclude bool
					if len(req.Bin) == 0 {
						binInclude = true
					} else {
						for _, bin := range req.Bin {
							if data[fieldMap["SOFT_BIN"]] == bin {
								binInclude = true
								break
							}
						}
					}
					if binInclude {
						if data[fieldMap[selection]] != "" {
							selectionData, _ := strconv.ParseFloat(data[fieldMap[selection]], 64)
							sumSelection += selectionData
							n++
							//difference := sumSelection/n - selectionData
							//standardDeviation += math.Pow(difference, 2)
							if max == "" {
								max = data[fieldMap[selection]]
							} else {
								maxDecimal, _ := strconv.ParseFloat(max, 64)
								if maxDecimal < selectionData {
									max = data[fieldMap[selection]]
								}
							}
							if min == "" {
								min = data[fieldMap[selection]]
							} else {
								minDecimal, _ := strconv.ParseFloat(min, 64)
								if selectionData < minDecimal {
									min = data[fieldMap[selection]]
								}
							}
							if xMax == "" {
								xMax = data[fieldMap[selection]]
							} else {
								maxDecimal, _ := strconv.ParseFloat(xMax, 64)
								if maxDecimal < selectionData {
									xMax = data[fieldMap[selection]]
								}
							}
							if xMin == "" {
								xMin = data[fieldMap[selection]]
							} else {
								minDecimal, _ := strconv.ParseFloat(xMin, 64)
								if selectionData < minDecimal {
									xMin = data[fieldMap[selection]]
								}
							}
						}
					}
				}
				averageFloat64 := sumSelection / n
				//standardDeviation = math.Sqrt(standardDeviation / n)
				var filed string
				if group == "" {
					filed = selection
				} else {
					filed = selection + "-" + group
				}
				fTHistogram = append(fTHistogram, &model.Histogram{
					Field:   filed,
					Average: averageFloat64,
					//StandardDeviation: standardDeviation,
					Max: max,
					Min: min,
					N:   n,
				})
			} else {
				for _, site := range req.Site {
					var n float64
					var sumSelection float64 = 0
					// 计算最大值、最小值、标准差、均值、数量
					//var standardDeviation float64
					var max, min string
					for _, data := range datas {
						selectionDecimal, _ := decimal.NewFromString(data[fieldMap[selection]])
						if req.XMax != "" && req.XMin != "" {
							xMaxDecimal, _ := decimal.NewFromString(req.XMax)
							xMinDecimal, _ := decimal.NewFromString(req.XMin)
							if !(selectionDecimal.LessThanOrEqual(xMaxDecimal) && xMinDecimal.LessThanOrEqual(selectionDecimal)) {
								continue
							}
						}

						if req.Offset != 0 {
							leftDecimal := decimal.NewFromFloat(left)
							rightDecimal := decimal.NewFromFloat(right)
							if selectionDecimal.LessThan(leftDecimal) || rightDecimal.LessThan(rightDecimal) {
								continue
							}
						}
						// 筛选Site
						var siteInclude bool
						if data[fieldMap["SITE_NUM"]] == site {
							siteInclude = true
						}
						// 筛选SBin
						var binInclude bool
						if len(req.Bin) == 0 {
							binInclude = true
						} else {
							for _, bin := range req.Bin {
								if data[fieldMap["SOFT_BIN"]] == bin {
									binInclude = true
									break
								}
							}
						}
						if siteInclude && binInclude {
							if data[fieldMap[selection]] != "" {
								selectionData, _ := strconv.ParseFloat(data[fieldMap[selection]], 64)
								sumSelection += selectionData
								n++
								//difference := sumSelection/n - selectionData
								//standardDeviation += math.Pow(difference, 2)
								if max == "" {
									max = data[fieldMap[selection]]
								} else {
									maxDecimal, _ := strconv.ParseFloat(max, 64)
									if maxDecimal < selectionData {
										max = data[fieldMap[selection]]
									}
								}
								if min == "" {
									min = data[fieldMap[selection]]
								} else {
									minDecimal, _ := strconv.ParseFloat(min, 64)
									if selectionData < minDecimal {
										min = data[fieldMap[selection]]
									}
								}
								if xMax == "" {
									xMax = data[fieldMap[selection]]
								} else {
									maxDecimal, _ := strconv.ParseFloat(xMax, 64)
									if maxDecimal < selectionData {
										xMax = data[fieldMap[selection]]
									}
								}
								if xMin == "" {
									xMin = data[fieldMap[selection]]
								} else {
									minDecimal, _ := strconv.ParseFloat(xMin, 64)
									if selectionData < minDecimal {
										xMin = data[fieldMap[selection]]
									}
								}
							}
						}
					}

					averageFloat64 := sumSelection / n
					//standardDeviation = math.Sqrt(standardDeviation / n)
					var filed string
					if group == "" {
						filed = selection + "-Site" + site
					} else {
						filed = selection + "-" + group + "-Site" + site
					}
					fTHistogram = append(fTHistogram, &model.Histogram{
						Field:   filed,
						Average: averageFloat64,
						//StandardDeviation: standardDeviation,
						Max: max,
						Min: min,
						N:   n,
					})
				}
			}
		}
	}

	// 生成X坐标
	if req.XMax != "" {
		xMax = req.XMax
	}
	if req.XMin != "" {
		xMin = req.XMin
	}
	//minDecimal, _ := strconv.ParseFloat(xMin, 64)
	//maxDecimal, _ := strconv.ParseFloat(xMax, 64)
	//interval := (maxDecimal - minDecimal) / 50
	//for i := 0; i < 51; i++ {
	//	xPoint := strconv.FormatFloat(minDecimal+interval*float64(i), 'f', 6, 64)
	//	x = append(x, xPoint)
	//}

	minDecimal, _ := decimal.NewFromString(xMin)
	if minDecimal.LessThan(decimal.NewFromInt(0)) {
		minDecimal = minDecimal.RoundUp(0)
	} else {
		minDecimal = minDecimal.RoundDown(0)
	}
	maxDecimal, _ := decimal.NewFromString(xMax)
	if maxDecimal.LessThan(decimal.NewFromInt(0)) {
		maxDecimal = maxDecimal.RoundDown(0)
	} else {
		maxDecimal = maxDecimal.RoundUp(0)
	}
	interval := maxDecimal.Sub(minDecimal).Div(decimal.NewFromInt(50))
	for i := 0; i < 51; i++ {
		xPoint := minDecimal.Add(interval.Mul(decimal.NewFromInt(int64(i)))).String()
		x = append(x, xPoint)
	}

	for _, group := range groups {
		var datas [][]string
		fieldMap := make(map[string]int)
		if group == "" {
			datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI)
		} else if len(req.SubBatch) != 0 {
			datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, group, "")
		} else if len(req.WaferID) != 0 {
			datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, "", group)
		}

		for _, selection := range req.Selections {
			if _, ok := fieldMap[selection]; !ok {
				continue
			}
			if len(req.Site) == 0 {
				var filed string
				if group == "" {
					filed = selection
				} else {
					filed = selection + "-" + group
				}
				var standardDeviation, average float64
				var index int
				for k, v := range fTHistogram {
					if v.Field == filed {
						average = v.Average
						index = k
						break
					}
				}
				var y []string
				counter := make(map[float64]int)
				// 计算最大值、最小值、标准差、均值、数量
				for _, data := range datas {
					// 筛选SBin
					var binInclude bool
					if len(req.Bin) == 0 {
						binInclude = true
					} else {
						for _, bin := range req.Bin {
							if data[fieldMap["SOFT_BIN"]] == bin {
								binInclude = true
								break
							}
						}
					}
					if binInclude {
						if data[fieldMap[selection]] != "" {
							selectionData, _ := strconv.ParseFloat(data[fieldMap[selection]], 64)
							standardDeviation += math.Pow(average-selectionData, 2)
							counter[selectionData]++
						}
					}
				}
				fTHistogram[index].StandardDeviation = math.Sqrt(standardDeviation / fTHistogram[index].N)

				for i := 0; i < len(x); i++ {
					if i == len(x)-1 {
						xFloat, _ := strconv.ParseFloat(x[i], 64)
						if yValue, ok := counter[xFloat]; ok {
							y = append(y, strconv.Itoa(yValue))
						} else {
							y = append(y, "0")
						}
						break
					}
					xPointMin, _ := decimal.NewFromString(x[i])
					xPointMax, _ := decimal.NewFromString(x[i+1])

					var yCounter float64 = 0
					for k, v := range counter {
						if xPointMin.LessThanOrEqual(decimal.NewFromFloat(k)) && decimal.NewFromFloat(k).LessThan(xPointMax) {
							yCounter += float64(v)
						}
					}
					yPoint := strconv.FormatFloat(yCounter, 'f', 0, 64)
					y = append(y, yPoint)
				}

				fTHistogram[index].X = x
				fTHistogram[index].Y = y
			} else {
				for _, site := range req.Site {
					var filed string
					if group == "" {
						filed = selection + "-Site" + site
					} else {
						filed = selection + "-" + group + "-Site" + site
					}
					var standardDeviation, average float64
					var index int
					for k, v := range fTHistogram {
						if v.Field == filed {
							average = v.Average
							index = k
							break
						}
					}
					var y []string
					counter := make(map[float64]int)
					for _, data := range datas {
						// 筛选Site
						var siteInclude bool
						if data[fieldMap["SITE_NUM"]] == site {
							siteInclude = true
						}
						// 筛选SBin
						var binInclude bool
						if len(req.Bin) == 0 {
							binInclude = true
						} else {
							for _, bin := range req.Bin {
								if data[fieldMap["SOFT_BIN"]] == bin {
									binInclude = true
									break
								}
							}
						}
						if siteInclude && binInclude {
							if data[fieldMap[selection]] != "" {
								selectionData, _ := strconv.ParseFloat(data[fieldMap[selection]], 64)
								standardDeviation += math.Pow(average-selectionData, 2)
								counter[selectionData]++
							}
						}
					}
					fTHistogram[index].StandardDeviation = math.Sqrt(standardDeviation / fTHistogram[index].N)
					for i := 0; i < len(x); i++ {
						if i == len(x)-1 {
							xFloat, _ := strconv.ParseFloat(x[i], 64)
							if yValue, ok := counter[xFloat]; ok {
								y = append(y, strconv.Itoa(yValue))
							} else {
								y = append(y, "0")
							}
							break
						}
						xPointMin, _ := strconv.ParseFloat(x[i], 64)
						xPointMax, _ := strconv.ParseFloat(x[i+1], 64)
						var yCounter float64 = 0
						for k, v := range counter {
							if xPointMin <= k && k < xPointMax {
								yCounter += float64(v)
							}
						}
						yPoint := strconv.FormatFloat(yCounter, 'f', 0, 64)
						y = append(y, yPoint)
					}

					fTHistogram[index].X = x
					fTHistogram[index].Y = y
				}
			}
		}
	}
	return fTHistogram, nil
}

// Scatter 散点图
func Scatter(req *request.Scatter) ([]*model.Scatter, model.ScatterLimit, model.ScatterLimit, error) {
	var groups []string

	if len(req.SubBatch) == 0 && len(req.WaferID) == 0 {
		groups = append(groups, "")
	} else if len(req.SubBatch) != 0 {
		groups = req.SubBatch
	} else if len(req.WaferID) != 0 {
		groups = req.WaferID
	}
	// 判断子批次还是大批次查询数据
	var datas [][]string
	fieldMap := make(map[string]int)
	if len(req.SubBatch) == 0 {
		datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI)
	} else {
		for _, group := range groups {
			if len(req.SubBatch) != 0 {
				groupDatas, groupFieldMap := LotInAFile(req.Product, req.Lot, req.PBI, group, "")
				datas = append(datas, groupDatas...)
				fieldMap = groupFieldMap
			} else {
				groupDatas, groupFieldMap := LotInAFile(req.Product, req.Lot, req.PBI, "", group)
				datas = append(datas, groupDatas...)
				fieldMap = groupFieldMap
			}
		}
	}

	var scatters []*model.Scatter
	var xScatterLimit, yScatterLimit model.ScatterLimit
	if len(req.Site) == 0 {
		scatterFieldMap := make(map[string]int)
		counter := make(map[string]map[string]int)
		for _, data := range datas {
			// 筛选SBin
			var binInclude bool
			if len(req.Bin) == 0 {
				binInclude = true
			} else {
				for _, bin := range req.Bin {
					if data[fieldMap["SOFT_BIN"]] == bin {
						binInclude = true
						break
					}
				}
			}
			if binInclude {
				for _, xySelection := range req.XYSelection {
					if data[fieldMap[xySelection.X]] == "" || data[fieldMap[xySelection.Y]] == "" {
						continue
					}
					if _, ok := counter[xySelection.X+","+xySelection.Y]; !ok {
						counter[xySelection.X+","+xySelection.Y] = map[string]int{}
					}
					// 过滤重复点
					needAppend := true
					coordinate := data[fieldMap[xySelection.X]] + "," + data[fieldMap[xySelection.Y]]
					if _, ok := counter[xySelection.X+","+xySelection.Y][coordinate]; ok {
						needAppend = false
					}
					if needAppend {
						counter[xySelection.X+","+xySelection.Y][coordinate]++
						if _, ok := scatterFieldMap[xySelection.X+","+xySelection.Y]; !ok {
							scatter := &model.Scatter{
								Field: xySelection.X + "," + xySelection.Y + " All Site", Datas: [][]string{}}
							scatterFieldMap[xySelection.X+","+xySelection.Y] = len(scatters)
							scatters = append(scatters, scatter)
						}
						scatters[scatterFieldMap[xySelection.X+","+xySelection.Y]].Datas = append(
							scatters[scatterFieldMap[xySelection.X+","+xySelection.Y]].Datas,
							[]string{data[fieldMap[xySelection.X]], data[fieldMap[xySelection.Y]]})
						if xScatterLimit.Min == "" {
							xScatterLimit.Min = data[fieldMap[xySelection.X]]
						} else {
							xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimit.Min, 8)
							dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8)
							if xScatterLimitFloat > dataFloat {
								xScatterLimit.Min = data[fieldMap[xySelection.X]]
							}
						}
						if xScatterLimit.Max == "" {
							xScatterLimit.Max = data[fieldMap[xySelection.X]]
						} else {
							xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimit.Max, 8)
							dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8)
							if xScatterLimitFloat < dataFloat {
								xScatterLimit.Max = data[fieldMap[xySelection.X]]
							}
						}
						if yScatterLimit.Min == "" {
							yScatterLimit.Min = data[fieldMap[xySelection.Y]]
						} else {
							yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimit.Min, 8)
							dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8)
							if yScatterLimitFloat > dataFloat {
								yScatterLimit.Min = data[fieldMap[xySelection.Y]]
							}
						}
						if yScatterLimit.Max == "" {
							yScatterLimit.Max = data[fieldMap[xySelection.Y]]
						} else {
							yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimit.Max, 8)
							dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8)
							if yScatterLimitFloat < dataFloat {
								yScatterLimit.Max = data[fieldMap[xySelection.Y]]
							}
						}
					}
				}
			}
		}
	} else {
		scatterFieldMap := make(map[string]int)
		for _, site := range req.Site {
			counter := make(map[string]map[string]int)
			for _, data := range datas {
				// 筛选Site
				if data[fieldMap["SITE_NUM"]] != site {
					continue
				}
				// 筛选SBin
				var binInclude bool
				if len(req.Bin) == 0 {
					binInclude = true
				} else {
					for _, bin := range req.Bin {
						if data[fieldMap["SOFT_BIN"]] == bin {
							binInclude = true
							break
						}
					}
				}
				if binInclude {
					for _, xySelection := range req.XYSelection {
						if data[fieldMap[xySelection.X]] == "" || data[fieldMap[xySelection.Y]] == "" {
							continue
						}
						if _, ok := counter[xySelection.X+","+xySelection.Y]; !ok {
							counter[xySelection.X+","+xySelection.Y] = map[string]int{}
						}
						// 过滤重复点
						needAppend := true
						coordinate := data[fieldMap[xySelection.X]] + "," + data[fieldMap[xySelection.Y]]
						if _, ok := counter[xySelection.X+","+xySelection.Y][coordinate]; ok {
							needAppend = false
						}
						if needAppend {
							counter[xySelection.X+","+xySelection.Y][coordinate]++
							if _, ok := scatterFieldMap[xySelection.X+","+xySelection.Y]; !ok {
								scatter := &model.Scatter{
									Field: xySelection.X + "," + xySelection.Y + "-Site" + site, Datas: [][]string{}}
								scatterFieldMap[xySelection.X+","+xySelection.Y] = len(scatters)
								scatters = append(scatters, scatter)
							}
							scatters[scatterFieldMap[xySelection.X+","+xySelection.Y]].Datas = append(
								scatters[scatterFieldMap[xySelection.X+","+xySelection.Y]].Datas,
								[]string{data[fieldMap[xySelection.X]], data[fieldMap[xySelection.Y]]})
							if xScatterLimit.Min == "" {
								xScatterLimit.Min = data[fieldMap[xySelection.X]]
							} else {
								xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimit.Min, 8)
								dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8)
								if xScatterLimitFloat > dataFloat {
									xScatterLimit.Min = data[fieldMap[xySelection.X]]
								}
							}
							if xScatterLimit.Max == "" {
								xScatterLimit.Max = data[fieldMap[xySelection.X]]
							} else {
								xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimit.Max, 8)
								dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8)
								if xScatterLimitFloat < dataFloat {
									xScatterLimit.Max = data[fieldMap[xySelection.X]]
								}
							}
							if yScatterLimit.Min == "" {
								yScatterLimit.Min = data[fieldMap[xySelection.Y]]
							} else {
								yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimit.Min, 8)
								dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8)
								if yScatterLimitFloat > dataFloat {
									yScatterLimit.Min = data[fieldMap[xySelection.Y]]
								}
							}
							if yScatterLimit.Max == "" {
								yScatterLimit.Max = data[fieldMap[xySelection.Y]]
							} else {
								yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimit.Max, 8)
								dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8)
								if yScatterLimitFloat < dataFloat {
									yScatterLimit.Max = data[fieldMap[xySelection.Y]]
								}
							}
						}
					}
				}
			}
		}
	}
	return scatters, xScatterLimit, yScatterLimit, nil
}

func Pie(req *request.Pie) ([]*model.Pie, error) {
	var pie []*model.Pie
	var datas [][]string
	fieldMap := make(map[string]int)
	if req.SubBatch == "" {
		datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI)
	} else {
		datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, req.SubBatch, req.Step)
	}
	if _, ok := fieldMap[req.Selection]; !ok {
		return nil, errors.New("不存在该参数")
	}
	m := make(map[string]int)
	if req.Min == "" {
		req.Min = "0"
	}
	if req.Max == "" {
		req.Max = "0"
	}
	minDecimal, _ := decimal.NewFromString(req.Min)
	maxDecimal, _ := decimal.NewFromString(req.Max)
	for _, data := range datas {
		var siteInclude bool
		if len(req.Site) == 0 {
			siteInclude = true
		} else {
			for _, site := range req.Site {
				if data[fieldMap["SITE_NUM"]] == site {
					siteInclude = true
					break
				}
			}
		}
		var binInclude bool
		if len(req.Bin) == 0 {
			binInclude = true
		} else {
			for _, bin := range req.Bin {
				if data[fieldMap["SOFT_BIN"]] == bin {
					binInclude = true
					break
				}
			}
		}
		if siteInclude && binInclude {
			if data[fieldMap[req.Selection]] == "" {
				data[fieldMap[req.Selection]] = "0"
			}
			selectionDecimal, _ := decimal.NewFromString(data[fieldMap[req.Selection]])
			if minDecimal.LessThanOrEqual(selectionDecimal) && selectionDecimal.LessThanOrEqual(maxDecimal) {
				var isValid bool
				for _, interval := range req.PieInterval {
					if interval.Min == "" {
						interval.Min = "0"
					}
					if interval.Max == "" {
						interval.Max = "0"
					}
					minIntervalDecimal, _ := decimal.NewFromString(interval.Min)
					maxIntervalDecimal, _ := decimal.NewFromString(interval.Max)
					if minIntervalDecimal.LessThanOrEqual(selectionDecimal) && selectionDecimal.LessThan(maxIntervalDecimal) {
						m[interval.Name]++
						isValid = true
						break
					}
				}
				if !isValid {
					m["else"]++
				}
			}
		}
	}
	for k, v := range m {
		pie = append(pie, &model.Pie{
			Name:  k,
			Value: v,
		})
	}
	return pie, nil
}

func Line(req *request.Line) (*model.Line, error) {
	var datas [][]string
	fieldMap := make(map[string]int)
	if req.SubBatch == "" {
		datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI)
	} else {
		datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, req.SubBatch, req.Step)
	}
	var x, y []string
	for index, data := range datas {
		var siteInclude bool
		if len(req.Site) == 0 {
			siteInclude = true
		} else {
			for _, site := range req.Site {
				if data[fieldMap["SITE_NUM"]] == site {
					siteInclude = true
					break
				}
			}
		}
		var binInclude bool
		if len(req.Bin) == 0 {
			binInclude = true
		} else {
			for _, bin := range req.Bin {
				if data[fieldMap["SOFT_BIN"]] == bin {
					binInclude = true
					break
				}
			}
		}
		if siteInclude && binInclude {
			x = append(x, strconv.Itoa(index))
			y = append(y, data[fieldMap[req.Selection]])
		}
	}
	lineChart := &model.Line{
		X: x,
		Y: y,
	}
	return lineChart, nil
}

// CPMap CP晶圆图
func CPMap(req *request.CPMap) (map[string]interface{}, error) {
	// 需要显示的参数
	selections := []string{"SITE_NUM", "SOFT_BIN", "HARD_BIN"}
	if len(req.Selection) > 0 {
		selections = append(selections, req.Selection[0])
	}

	// CP测试没有子批次
	var fileHandle *model.FileHandled
	global.PostGreSQL.Where("pbi = ? AND product = ? AND lot = ? AND wafer_id = ?",
		req.PBI, req.Product, req.Lot, req.WaferID).
		Find(&fileHandle)

	f, err := os.Open(fileHandle.Path)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	defer f.Close()
	scanner := bufio.NewScanner(f)
	datas := make([][]string, 0)
	fieldMap := make(map[string]int)
	for scanner.Scan() {
		line := scanner.Text()
		s := strings.Split(line, ",")
		datas = append(datas, s[:len(s)-1])
		if len(datas) == 1 {
			for index, cell := range s {
				if index == len(s)-1 {
					continue
				}
				fieldMap[cell] = index
			}
		}
	}
	if len(datas) >= 1 {
		datas = datas[1:]
	}

	sbinHbinMap := make(map[string]map[string]string)
	res := make(map[string]interface{})
	resDatas := make([]map[string]interface{}, 0)
	selectDatas := make(map[string]interface{})
	// 颜色、标题、数据数组初始化
	color := []string{"#4FFF00", "#FF0000", "#1B81FF", "#FF0000", "#E12AE8"}
	datasTitle := []string{"第一次测试Pass", "第一次测试Fail", "复测Pass", "复测Fail", "复测Fail变动"}
	selectDatas["第一次测试Pass"] = [][]string{}
	selectDatas["第一次测试Fail"] = [][]string{}
	selectDatas["复测Pass"] = [][]string{}
	selectDatas["复测Fail"] = [][]string{}
	selectDatas["复测Fail变动"] = [][]string{}
	for _, sBinColor := range req.SBinColor {
		color = append(color, sBinColor.Color)
		datasTitle = append(datasTitle, sBinColor.Name)
		selectDatas[sBinColor.Name] = [][]string{}
	}
	for _, hBinColor := range req.HBinColor {
		color = append(color, hBinColor.Color)
		datasTitle = append(datasTitle, hBinColor.Name)
		selectDatas[hBinColor.Name] = [][]string{}
	}
	for _, selectionColor := range req.SelectionColor {
		color = append(color, selectionColor.Color)
		datasTitle = append(datasTitle, selectionColor.Name+":"+selectionColor.Min+"~"+selectionColor.Max)
		selectDatas[selectionColor.Name+":"+selectionColor.Min+"~"+selectionColor.Max] = [][]string{}
	}

	sbinHbinByte := []byte(fileHandle.SbinHbin)
	_ = json.Unmarshal(sbinHbinByte, &sbinHbinMap)

	passArray := selectDatas["复测Pass"].([][]string)
	failArray := selectDatas["复测Fail"].([][]string)
	failChangeArray := selectDatas["复测Fail变动"].([][]string)
	lastPassArray := selectDatas["第一次测试Pass"].([][]string)
	lastFailArray := selectDatas["第一次测试Fail"].([][]string)
	var total, pass float64
	binMap := make(map[string]int)
	sbinColorMap := make(map[string]int)
	hbinColorMap := make(map[string]int)
	selectionColorMap := make(map[string]int)
	for _, data := range datas {
		binInfoMap := sbinHbinMap[data[fieldMap["SOFT_BIN"]]]
		// 筛选Site
		var siteInclude bool
		if len(req.Site) == 0 {
			siteInclude = true
		} else {
			for _, site := range req.Site {
				if data[fieldMap["SITE_NUM"]] == site {
					siteInclude = true
					break
				}
			}
		}
		if !siteInclude {
			continue
		}
		// 筛选Soft Bin
		var sBinInclude bool
		if len(req.SBin) == 0 {
			sBinInclude = true
		} else {
			for _, bin := range req.SBin {
				if data[fieldMap["SOFT_BIN"]] == bin {
					sBinInclude = true
					break
				}
			}

		}
		if !sBinInclude {
			continue
		}
		// 筛选Hard Bin
		var hBinInclude bool
		if len(req.HBin) == 0 {
			hBinInclude = true
		} else {
			for _, bin := range req.HBin {
				if binInfoMap["HBin"] == bin {
					hBinInclude = true
					break
				}
			}

		}
		if !hBinInclude {
			continue
		}

		// 将HBin写入单行信息内
		//data = append(data, binInfoMap["HBin"])
		x := data[fieldMap["X_COORD"]]
		y := data[fieldMap["Y_COORD"]]
		data[fieldMap["PASSFG"]] = strings.ToLower(data[fieldMap["PASSFG"]])
		// 判断测试点是否通过测试
		var isPass bool
		if data[fieldMap["PASSFG"]] == "true" {
			isPass = true
		}

		// 需要显示的参数
		var field []string
		for _, selection := range selections {
			var dataValue string
			if selection == "HARD_BIN" {
				dataValue = binInfoMap["HBin"]
				field = append(field, []string{selection, dataValue}...)
				continue
			}
			if _, ok := fieldMap[selection]; !ok {
				dataValue = "0"
			} else {
				dataValue = data[fieldMap[selection]]
			}
			field = append(field, []string{selection, dataValue}...)
		}

		// 区分通过、不通过、第一次测试数据
		var isSamePoint bool
		var isFinal bool
		for _, lastPoint := range lastFailArray {
			if lastPoint[0] == x && lastPoint[1] == y {
				if isPass {
					passArray = append(passArray, append([]string{x, y}, field...))
				} else {
					var isChangeFail bool
					for lastPointFieldIndex := 2; lastPointFieldIndex < len(lastPoint); lastPointFieldIndex++ {
						if lastPoint[lastPointFieldIndex] == "SOFT_BIN" {
							for pointFieldIndex := 2; pointFieldIndex < len(field); pointFieldIndex++ {
								if field[pointFieldIndex] == "SOFT_BIN" && lastPoint[lastPointFieldIndex+1] != field[pointFieldIndex+1] {
									isChangeFail = true
								}
							}
						}
					}
					if isChangeFail {
						failArray = append(failArray, append([]string{x, y}, field...))
						failChangeArray = append(failChangeArray, append([]string{x, y}, field...))
					} else {
						failArray = append(failArray, append([]string{x, y}, field...))
					}
				}
				isFinal = true
				isSamePoint = true
				break
			}
		}
		if !isSamePoint {
			if isPass {
				lastPassArray = append(lastPassArray, append([]string{x, y}, field...))
				isFinal = true
			} else {
				lastFailArray = append(lastFailArray, append([]string{x, y}, field...))
			}
		}

		if isFinal {
			total++
			if isPass {
				pass++
			}
			binMap[data[fieldMap["SOFT_BIN"]]]++
			sbinColorMap[data[fieldMap["SOFT_BIN"]]]++
			hbinColorMap[binInfoMap["HBin"]]++
			// 根据SOFT_BIN区分颜色
			for _, sBinColor := range req.SBinColor {
				array := selectDatas[sBinColor.Name].([][]string)
				var isReplace bool
				for _, point := range array {
					if point[0] == x && point[1] == y {
						point = append([]string{x, y}, field...)
						isReplace = true
						break
					}
				}
				if !isReplace && data[fieldMap["SOFT_BIN"]] == sBinColor.Name {
					array = append(array, append([]string{x, y}, field...))
					selectDatas[sBinColor.Name] = array
					break
				}
			}

			// 根据HARD_BIN区分颜色
			for _, hBinColor := range req.HBinColor {
				array := selectDatas[hBinColor.Name].([][]string)
				var isReplace bool
				for _, point := range array {
					if point[0] == x && point[1] == y {
						point = append([]string{x, y}, field...)
						isReplace = true
						break
					}
				}
				if !isReplace && binInfoMap["HBin"] == hBinColor.Name {
					array = append(array, append([]string{x, y}, field...))
					selectDatas[hBinColor.Name] = array
					break
				}
			}

			// 根据参数范围区分颜色
			for _, selectionColor := range req.SelectionColor {
				if data[fieldMap[selectionColor.Name]] == "" {
					break
				}
				selection, _ := decimal.NewFromString(data[fieldMap[selectionColor.Name]])
				max, _ := decimal.NewFromString(selectionColor.Max)
				min, _ := decimal.NewFromString(selectionColor.Min)
				if selection.LessThanOrEqual(max) && min.LessThanOrEqual(selection) {
					s := selectionColor.Name + ":" + selectionColor.Min + "~" + selectionColor.Max
					selectionColorMap[s]++
					array := selectDatas[s].([][]string)
					var isReplace bool
					for _, point := range array {
						if point[0] == x && point[1] == y {
							point = append([]string{x, y}, field...)
							isReplace = true
							selectDatas[s] = array
							break
						}
					}
					if !isReplace {
						array = append(array, append([]string{x, y}, field...))
						selectDatas[s] = array
						break
					}
				}
				//selection, _ := strconv.ParseFloat(data[fieldMap[selectionColor.Name]], 8)
				//max, _ := strconv.ParseFloat(selectionColor.Max, 8)
				//min, _ := strconv.ParseFloat(selectionColor.Min, 8)
				//if selection <= max && min <= selection {
				//	selectionColorMap[selectionColor.Name]++
				//	s := selectionColor.Name + ":" + selectionColor.Min + "~" + selectionColor.Max
				//	array := selectDatas[s].([][]string)
				//	var isReplace bool
				//	for _, point := range array {
				//		if point[0] == x && point[1] == y {
				//			point = append([]string{x, y}, field...)
				//			isReplace = true
				//			selectDatas[s] = array
				//			break
				//		}
				//	}
				//	if !isReplace {
				//		array = append(array, append([]string{x, y}, field...))
				//		selectDatas[s] = array
				//		break
				//	}
				//}
			}
		}
	}

	selectDatas["复测Pass"] = passArray
	selectDatas["复测Fail"] = failArray
	selectDatas["复测Fail变动"] = failChangeArray

	selectDatas["第一次测试Pass"] = lastPassArray
	selectDatas["第一次测试Fail"] = lastFailArray

	// 将根据标题顺序存入数组
	for _, v := range datasTitle {
		resDatas = append(resDatas, map[string]interface{}{
			"name": v,
			"data": selectDatas[v],
		})
	}
	res["color"] = color
	res["datas_title"] = datasTitle
	res["datas"] = resDatas

	totalDecimal := decimal.NewFromFloat(total)
	passDecimal := decimal.NewFromFloat(pass)
	res["Total"] = totalDecimal.String()
	if !totalDecimal.IsZero() {
		res["PassProbability"] = passDecimal.Div(totalDecimal).Round(4).Mul(decimal.NewFromInt(100)).String() + "%"
	}
	var binArray []string
	for bin := range binMap {
		binArray = append(binArray, bin)
	}
	sort.Slice(binArray, func(i, j int) bool {
		return binMap[binArray[i]] > binMap[binArray[j]]
	})
	var binProbability [][]string
	for _, bin := range binArray {
		binDecimal := decimal.NewFromInt(int64(binMap[bin]))
		probability := "0%"
		if !totalDecimal.IsZero() {
			probability = binDecimal.Div(totalDecimal).Round(4).Mul(decimal.NewFromInt(100)).String() + "%"
		}
		binProbability = append(binProbability, []string{"BIN " + bin, probability, strconv.Itoa(binMap[bin])})
	}
	res["Bin情况"] = binProbability
	res["Sbin数量"] = sbinColorMap
	res["Hbin数量"] = hbinColorMap
	res["参数数量"] = selectionColorMap

	return res, nil
}

func LogSiteChart(req *request.LogSiteChart) *model.Histogram {
	//var fileHandle *model.FileHandled
	//global.PostGreSQL.Where("product = ? AND sub_batch = ?", req.Product, req.SubBatch).Find(&fileHandle)
	var datas [][]string
	fieldMap := make(map[string]int)
	if req.SubBatch == "" {
		datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI)
	} else {
		datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, req.SubBatch, req.Step)
	}
	var x []string
	for _, v := range req.Site {
		x = append(x, "Site"+v)
	}
	var y []string
	if req.ContentType == "数量" {
		counter := make(map[string]int)
		for _, data := range datas {
			counter[data[fieldMap["SITE_NUM"]]]++
		}
		for _, v := range req.Site {
			y = append(y, strconv.Itoa(counter[v]))
		}
		//y = append(y, strconv.Itoa(counter["Site1"]), strconv.Itoa(counter["Site2"]), strconv.Itoa(counter["Site3"]), strconv.Itoa(counter["Site4"]))
	} else if req.ContentType == "良率" {
		counter := make(map[string]int)
		passCounter := make(map[string]int)
		for _, data := range datas {
			counter[data[fieldMap["SITE_NUM"]]]++
			if data[fieldMap["PASSFG"]] == "True" {
				passCounter[data[fieldMap["SITE_NUM"]]]++
			}
		}
		for _, v := range x {
			counterDecimal := decimal.NewFromInt(int64(counter[v]))
			passCounterDecimal := decimal.NewFromInt(int64(passCounter[v]))
			s := passCounterDecimal.Div(counterDecimal).Round(4).Mul(decimal.NewFromInt(10000)).String()
			if s == "0" {
				y = append(y, "0%")
				continue
			}
			s = s[:2] + "." + s[2:] + "%"
			y = append(y, s)
		}
	} else if req.ContentType == "参数均值" {
		counter := make(map[string]int)
		sum := make(map[string]string)
		for _, data := range datas {
			if len(req.Bin) != 0 {
				var isContain bool
				for _, bin := range req.Bin {
					if data[fieldMap["SOFT_BIN"]] == bin {
						isContain = true
						break
					}
				}
				if !isContain {
					continue
				}
			}
			counter[data[fieldMap["SITE_NUM"]]]++
			if data[fieldMap[req.Selection]] == "" {
				data[fieldMap[req.Selection]] = "0"
			}
			if sum[data[fieldMap["SITE_NUM"]]] == "" {
				sum[data[fieldMap["SITE_NUM"]]] = "0"
			}
			selectionDecimal, _ := decimal.NewFromString(data[fieldMap[req.Selection]])
			sumDecimal, _ := decimal.NewFromString(sum[data[fieldMap["SITE_NUM"]]])
			sum[data[fieldMap["SITE_NUM"]]] = sumDecimal.Add(selectionDecimal).String()
		}
		for _, v := range req.Site {
			counterDecimal := decimal.NewFromInt(int64(counter[v]))
			passCounterDecimal, _ := decimal.NewFromString(sum[v])
			s := passCounterDecimal.Div(counterDecimal).Round(4).String()
			y = append(y, s)
		}
	}
	return &model.Histogram{
		X: x,
		Y: y,
	}
}
