package main

import (
	"qfw/util"
	"qfw/util/redis"
	"regexp"
	"sort"
	"strings"
	"time"

	"gopkg.in/mgo.v2/bson"
)

/**
发布时间（结合信息类型-->）
信息类型（拟建、招标(变更)、结果(成交、中标、流标、废标、变更)、其他(合同、验收、违规、变更)）
项目代码（长度）
采购单位（结合省份）
招标机构
所属省份
信息标题（含有二次、标段、包的情况，结合分包情况处理）
是否分包：
**/
type ProjectInfo struct {
	Id            string                 `json:"id"`
	IdInc         string                 `json:"_id"`        //补漏使用
	Publistime    []int64                `json:"publistime"` //多条信息的发布时间、跨度
	InfoType      [][]string             `json:"infotype"`   //多条信息内的 toptype、subtype
	Ids           []string               `json:"ids"`
	Topscopeclass []string               `json:"topscopeclass"`
	Subscopeclass []string               `json:"subscopeclass"`
	Winners       []string               `json:"winners"`
	ProjectName   string                 `json:"projectname"`
	ProjectCode   string                 `json:"projectcode"` //项目代码唯一（纯数字的权重低）
	Buyer         string                 `json:"buyer"`       //采购单位唯一
	Buyerperson   string                 `json:"buyerperson"`
	Buyertel      string                 `json:"buyertel"`
	Agency        string                 `json:"agency"`     //代理机构唯一
	Area          string                 `json:"area"`       //地区唯一
	City          string                 `json:"city"`       //地市
	HasPackage    bool                   `json:"haspackage"` //是否有分包
	Package       map[string]interface{} `json:"package"`    //分包的对比对象

	Buyerclass  string   `json:"buyerclass"`  //采购单位分类
	Bidopentime int64    `json:"bidopentime"` //开标时间
	District    string   `json:"district"`    //区县
	Winnerorder []string //中标候选人
}

type CompareOne struct {
	ProjectNameType string //项目名称对比结果分类 A相等 B包含 C不相等 Dthis存在对比不存在 Ethis不存在
	ProjectCodeType string //同上
	BuyerType       string //同上
	AreaType        string //同上
	AgencyType      string //同上
	PublistimeType  int    //1在时间范围  2不在
	PackageType     int    //1都是多包 2都不是多包 3招标 4新信息是结果
	Score           int
	Parent          *CompareInfo
	Pinfo           *ProjectInfo
	Pos             int

	Cresult string //对比结果
}

type CompareInfo struct {
	Field  string        //对比属性 pn/pc/pb
	Key    string        //存放rediskey
	Scores []*CompareOne //对比分值 pinfo索引对应分值
	Bfind  bool          //是否查找到
	IdArr  []string
	K      *Key
	KeyMap *KeyMap
}

func NewCompareInfo(field, key string, KeyMap *KeyMap) *CompareInfo {
	return &CompareInfo{
		Field:  field,
		Key:    key,
		Scores: []*CompareOne{},
		KeyMap: KeyMap,
	}

}

var numreg2 = regexp.MustCompile("^[0-9]+$")
var TitleReg = regexp.MustCompile("([一二三四五六七八九十0-9A-Za-zⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ、\\-~至]+(子|合同|分|施工|监理|标)?[包标段][号段]?[、]?)+|((子|合同|分|施工|监理|标)?[包标段][号段]?[一二三四五六七八九十0-9A-Za-zⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ、\\-~至]+[、]?)+|(子|合同|分|施工|监理|标)?[包标段][号段]?[a-zA-Z0-9]+[\\-~－至、](子|合同|分|施工|监理|标)?[包标段][号段]?[a-zA-Z0-9]+")

//没有在redis中查找到，新增项目
func InsertProject(new_pn string, tmp, mess map[string]interface{}, pici int64, thisinfo *Info) string {
	e := InitEL("")
	set := map[string]interface{}{
		"pici": pici,
	}
	set["s_projectname"] = new_pn
	e.fieldpriority(&tmp, nil, &set)
	set["extractpos"] = e.GetVal()
	set["createtime"] = time.Now().Unix()
	set["sourceinfoid"] = util.BsonIdToSId(tmp["_id"])
	set["sourceinfourl"] = tmp["href"]
	set["topscopeclass"] = thisinfo.Topscopeclass
	set["subscopeclass"] = thisinfo.Subscopeclass
	if thisinfo.Buyerperson != "" {
		set["buyerperson"] = thisinfo.Buyerperson
	}
	if thisinfo.Buyertel != "" {
		set["buyertel"] = thisinfo.Buyertel
	}
	if thisinfo.Buyerclass != "" {
		set["buyertel"] = thisinfo.Buyerclass
	}
	if thisinfo.District != "" {
		set["district"] = thisinfo.District
	}
	if thisinfo.Bidopentime > 0 {
		set["bidopentime"] = thisinfo.Bidopentime
	}
	if len(thisinfo.Winnerorder) > 0 {
		set["winnerorder"] = thisinfo.Winnerorder
	}
	s_subscopeclass := strings.Join(thisinfo.Subscopeclass, ",")
	set["s_subscopeclass"] = s_subscopeclass
	s_winner := strings.Join(thisinfo.Winners, ",")
	set["s_winner"] = s_winner
	if tmp["package"] != nil {
		set["package"] = tmp["package"] //没定义优先级
	}
	push := NewPushInfo(tmp)
	for tkey, _ := range extractpos {
		if tmp[tkey] != nil {
			push[tkey] = tmp[tkey]
		}
	}
	set["list"] = []bson.M{
		push,
	}
	if mess != nil { //项目标识
		for k, v := range mess {
			set[k] = v
		}
	}
	return MQFW.Save(projectColl, set)
}

//生成存放在redis数组中的对象
func NewPinfo(id string, thisinfo *Info) ProjectInfo {
	p1 := ProjectInfo{
		Publistime:    []int64{thisinfo.Publishtime},
		InfoType:      [][]string{[]string{thisinfo.TopType, thisinfo.SubType}},
		Id:            id,
		Ids:           []string{thisinfo.Id},
		Topscopeclass: thisinfo.Topscopeclass,
		Subscopeclass: thisinfo.Subscopeclass,
		Winners:       thisinfo.Winners,
		ProjectName:   thisinfo.ProjectName,
		ProjectCode:   thisinfo.ProjectCode,
		Buyer:         thisinfo.Buyer,
		Agency:        thisinfo.Agency,
		Area:          thisinfo.Area,
		HasPackage:    thisinfo.HasPackage,
		Package:       map[string]interface{}{},
		Buyerclass:    thisinfo.Buyerclass,
		Bidopentime:   thisinfo.Bidopentime,
		District:      thisinfo.District,
		Winnerorder:   thisinfo.Winnerorder,
	}
	for k4, _ := range thisinfo.Package {
		p1.Package[k4] = ""
	}
	return p1
}

//每一个字段的打分map,获取最高分
func GetMaxScore(scoremap map[int]int) (find bool, index int) {
	ks := []int{}
	vs := []int{}
	for k, v := range scoremap {
		mk, mv := -1, -100
		bf := false
		for mk, mv = range vs {
			if mv > v {
				bf = true
				break
			}
		}
		if mk == -1 || !bf {
			vs = append(vs, v)
			ks = append(ks, k)
		} else {
			vs = append(append(vs[:mk], v), vs[mk:]...)
			ks = append(append(ks[:mk], k), ks[mk:]...)
		}
	}
	if len(ks) > 0 {
		index = ks[len(ks)-1]
		find = true
	}
	return
}

//往对应redis中更新信息
func updateinfo(thisinfo *Info, tmp map[string]interface{}, pInfo *ProjectInfo, pici int64) string {
	updateid := pInfo.Id
	if BinarySearch(pInfo.Ids, thisinfo.Id) > -1 {
		return updateid
	}
	set := map[string]interface{}{
		"pici": pici,
	}
	res, bres := MQFW.FindById(projectColl, pInfo.Id, `{"list":0}`)
	EqInfoUpdate(thisinfo, pInfo)
	if bres && res != nil && *res != nil {
		set["topscopeclass"] = pInfo.Topscopeclass
		set["subscopeclass"] = pInfo.Subscopeclass
		s_subscopeclass := strings.Join(pInfo.Subscopeclass, ",")
		if len(s_subscopeclass) > 0 {
			s_subscopeclass = "," + s_subscopeclass + ","
		}
		set["s_subscopeclass"] = s_subscopeclass
		s_winner := strings.Join(pInfo.Winners, ",")
		if len(s_winner) > 0 {
			s_winner = "," + s_winner + ","
		}
		set["s_winner"] = s_winner
		if pInfo.Buyerperson != "" && pInfo.Buyertel != "" {
			set["buyerperson"] = pInfo.Buyerperson
			set["buyertel"] = pInfo.Buyertel
		}
		if pInfo.Buyerclass != "" {
			set["buyerclass"] = pInfo.Buyerclass
		}
		if pInfo.District != "" {
			set["district"] = pInfo.District
		}
		if pInfo.Bidopentime > 0 {
			set["bidopentime"] = pInfo.Bidopentime
		}
		if len(pInfo.Winnerorder) > 0 {
			set["winnerorder"] = pInfo.Winnerorder
		}
		if thisinfo.HasPackage {
			set["multipackage"] = 1
		} else {
			set["multipackage"] = 0
		}
		e := InitEL(util.ObjToString((*res)["extractpos"]))
		if thisinfo.dealtype == 1 {
			var sonpackage map[string]interface{}
			for _, obj := range tmp["package"].(map[string]interface{}) {
				sonpackage, _ = obj.(map[string]interface{})
			}
			for _, v2 := range []string{"budget", "budget_w", "winner", "winner_w", "bidstatus", "bidstatus_w"} {
				if sonpackage[v2] != nil {
					tmp[v2] = sonpackage[v2]
				}
			}
		}
		e.fieldpriority(&tmp, res, &set)
		set["extractpos"] = e.GetVal()
		if thisinfo.HasPackage { //多包处理
			p1, _ := (*res)["package"].(map[string]interface{})
			p2, _ := tmp["package"].(map[string]interface{})
			if p2 != nil {
				if p1 != nil {
					for pk2, pv2 := range p2 {
						if p1[pk2] != nil { //合并
							item1, _ := p1[pk2].(map[string]interface{})
							item2, _ := pv2.(map[string]interface{})
							if item1 != nil && item2 != nil { //原始项
								for ik1, iv1 := range item2 {
									if item1[ik1] == nil {
										item1[ik1] = iv1
									}
								}
							}
						} else {
							p1[pk2] = pv2
						}
					}
				} else {
					p1 = p2
				}
			}
			set["package"] = p1
		}
		//中标候选人合并

		update := map[string]interface{}{}
		if len(set) > 0 {
			update["$set"] = set
		}
		//保留原数据吧
		push := NewPushInfo(tmp)
		for tkey, _ := range extractpos {
			if tmp[tkey] != nil {
				push[tkey] = tmp[tkey]
			}
		}
		update["$push"] = map[string]interface{}{
			"list": push,
		}
		if len(update) > 0 {
			MQFW.Update(projectColl, map[string]interface{}{
				"_id": util.StringTOBsonId(pInfo.Id),
			}, &update, false, false)
		}
	}
	//再往redis中放 index
	//往队列中增加时间 -------------->start
	redis.Put(REDISIDS, updateid, pInfo, 0)
	return updateid
}

func EqInfoUpdate(thisinfo *Info, pInfo *ProjectInfo) {
	var tk int
	bf1 := false
	for _k, tv := range pInfo.Publistime {
		tk = _k
		if tv > thisinfo.Publishtime {
			bf1 = true
			break
		}
	}
	if bf1 {
		pInfo.Publistime = append(append(pInfo.Publistime[:tk], thisinfo.Publishtime), pInfo.Publistime[tk:]...)
		pInfo.InfoType = append(append(pInfo.InfoType[:tk], []string{thisinfo.TopType, thisinfo.SubType}), pInfo.InfoType[tk:]...)
		pInfo.Ids = append(append(pInfo.Ids[:tk], thisinfo.Id), pInfo.Ids[tk:]...)
	} else {
		pInfo.Publistime = append(pInfo.Publistime, thisinfo.Publishtime)
		pInfo.InfoType = append(pInfo.InfoType, []string{thisinfo.TopType, thisinfo.SubType})
		pInfo.Ids = append(pInfo.Ids, thisinfo.Id)
	}
	//增加发布时间结束----------------->end

	if (pInfo.Buyer == "" && thisinfo.Buyer != "") || (len([]rune(pInfo.Buyer)) < 5 && len([]rune(thisinfo.Buyer)) > 5) {
		pInfo.Buyer = thisinfo.Buyer
	}
	if (pInfo.Agency == "" && thisinfo.Agency != "") || (len([]rune(pInfo.Agency)) < 5 && len([]rune(thisinfo.Agency)) > 5) {
		pInfo.Agency = thisinfo.Agency
	}
	if (pInfo.ProjectCode == "" && thisinfo.ProjectCode != "") || (len([]rune(pInfo.ProjectCode)) < 6 && len([]rune(thisinfo.ProjectCode)) > 6) {
		pInfo.ProjectCode = thisinfo.ProjectCode
	}

	if thisinfo.Buyerperson != "" && thisinfo.Buyertel != "" && len([]rune(thisinfo.Buyertel)) > 6 {
		pInfo.Buyerperson = thisinfo.Buyerperson
		pInfo.Buyertel = thisinfo.Buyertel
	}
	if thisinfo.Buyerclass != "" {
		pInfo.Buyerclass = thisinfo.Buyerclass
	}
	if thisinfo.District != "" {
		pInfo.District = thisinfo.District
	}
	if thisinfo.Bidopentime > 0 {
		pInfo.Bidopentime = thisinfo.Bidopentime
	}
	if len(thisinfo.Topscopeclass) > 0 {
		sort.Strings(pInfo.Topscopeclass)
		for _, k := range thisinfo.Topscopeclass {
			if BinarySearch(pInfo.Topscopeclass, k) == -1 {
				pInfo.Topscopeclass = append(pInfo.Topscopeclass, k)
				sort.Strings(pInfo.Topscopeclass)
			}
		}
	}

	if len(thisinfo.Subscopeclass) > 0 {
		sort.Strings(pInfo.Subscopeclass)
		for _, k := range thisinfo.Subscopeclass {
			if BinarySearch(pInfo.Subscopeclass, k) == -1 {
				pInfo.Subscopeclass = append(pInfo.Subscopeclass, k)
				sort.Strings(pInfo.Subscopeclass)
			}
		}
	}
	//winner
	if len(thisinfo.Winners) > 0 {
		sort.Strings(pInfo.Winners)
		for _, k := range thisinfo.Winners {
			if BinarySearch(pInfo.Winners, k) == -1 {
				pInfo.Winners = append(pInfo.Winners, k)
				sort.Strings(pInfo.Winners)
			}
		}
	}
	//winnerorder
	if len(thisinfo.Winnerorder) > 0 {
		sort.Strings(pInfo.Winnerorder)
		for _, k := range thisinfo.Winnerorder {
			if BinarySearch(pInfo.Winnerorder, k) == -1 {
				pInfo.Winnerorder = append(pInfo.Winnerorder, k)
				sort.Strings(pInfo.Winnerorder)
			}
		}
	}
	//return pInfo
}

//二分字符串查找
func BinarySearch(s []string, k string) int {
	sort.Strings(s)
	lo, hi := 0, len(s)-1
	for lo <= hi {
		m := (lo + hi) >> 1
		if s[m] < k {
			lo = m + 1
		} else if s[m] > k {
			hi = m - 1
		} else {
			return m
		}
	}
	return -1
}

//移除数组中重复的元素
func RemoveDup(arr []string) (newarr []string) {
	m1 := map[string]bool{}
	newarr = []string{}
	for _, k := range arr {
		if !m1[k] {
			m1[k] = true
			newarr = append(newarr, k)
		}
	}
	return
}
