package util

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

var rc *regexp.Regexp
var REG_A_RULE = regexp.MustCompile(`([\\+\\|\\(\\)\\^])`)
var REG_NUM = regexp.MustCompile(`[0-9]+`)

const (
	SPLIT = "___"
)

//规则或者正则识别
func RecogAnalyRules(text string, rules []interface{}) (bool, []string) {
	var arr []string
	ok := false
	for _, r := range rules {
		switch r.(type) {
		case string: //规则
			//fmt.Println("规则---", r.(string))
			strRuleArr := AnalyRule(r.(string)) //解析规则
			ok, arr = Compute(text, strRuleArr, 1)
			if ok {
				return ok, arr
			}
		case *regexp.Regexp: //正则
			ruleReg := r.(*regexp.Regexp)
			textArr := ruleReg.FindAllString(text, -1)
			//fmt.Println("正则---", ruleReg)
			if len(textArr) > 0 {
				regStr := []string{ruleReg.String()}
				return true, regStr
			}
		default:
			continue
		}
	}
	return ok, arr
}

//前置过滤
func PreFilter(text, prerule string) string {
	if len(prerule) > 0 {
		taskPreruleArr := strings.Split(prerule, "\n")
		for _, r := range taskPreruleArr {
			rClearArr := strings.Split(r, "__")
			if len(rClearArr) == 2 {
				rc = regexp.MustCompile(rClearArr[0])
				text = rc.ReplaceAllString(text, rClearArr[1])
			}
		}
	}
	return text
}

//测试任务 分离正则和规则
func AnalyRules(rules []string) [][]string {
	res := [][]string{}
	for i := 0; i < len(rules); i++ {
		if strings.HasPrefix(rules[i], "'") && strings.HasSuffix(rules[i], "'") { //正则
			res = append(res, []string{rules[i]})
		} else { //规则
			res = append(res, AnalyRule(rules[i]))
		}
	}
	return res
}

//解析规则
func AnalyRule(rule string) []string {
	res := []string{}
	ruleNew := REG_A_RULE.ReplaceAllString(rule, fmt.Sprintf("%s${1}%s", SPLIT, SPLIT))
	ruleNewArr := strings.Split(ruleNew, SPLIT)
	for _, key := range ruleNewArr {
		if key != "" {
			res = append(res, key)
		}
	}
	return res
}

//分类，支持多条规则，返回文本！！！！只提供单条测试
func ClassificationText(text string, rules [][]string) (t string, rs [][]string, rulepos int, res bool) {
	rs = rules
	for n, rule := range rs {
		if len(rule) == 0 || len(rule) > 1 { //规则
			t, rs[n], res = ComputeText(text, rule, 1)
			if res {
				return t, rs, n, res
			}
		} else if len(rule) == 1 { //正则
			r := rule[0]
			rss := []rune(r)
			ru := string(rss[1 : len(rss)-1])
			rulereg, err := regexp.Compile(ru)
			if err != nil {
				continue
			}
			textArr := rulereg.FindAllString(text, -1)
			rs[n] = []string{fmt.Sprintf("<r class='_rf'>%s</r>", ru)}
			if len(textArr) > 0 {
				rs[n] = []string{fmt.Sprintf("<r class='_rt'>%s</r>", ru)}
				text = strings.Replace(text, textArr[0], fmt.Sprintf("<r class='_and'>%s</r>", textArr[0]), 1)
				return text, rules, n, true
			}
		}
	}
	return
}

func ComputeText(text string, rule []string, num int) (string, []string, bool) {
	var andB, orB, oB []bool
	op := ""
	for pos := 0; pos < len(rule); pos++ {
		tmp := rule[pos]
		if tmp == "+" || tmp == "^" || tmp == "|" {
			op = tmp
			continue
		} else if REG_NUM.MatchString(tmp) && len(tmp) == 1 {
			continue
		} else {
			tmpresult := false
			if tmp == "(" { //找出子表达式，仅限一层,现在修改为多层逻辑
				tmpexp := []string{}
				pos++
				isRight := 0
				thispos := pos
				for ; pos < len(rule); pos++ {
					if rule[pos] == "(" {
						isRight++
						tmpexp = append(tmpexp, rule[pos])
					} else if rule[pos] == ")" {
						if isRight > 0 {
							isRight--
							tmpexp = append(tmpexp, rule[pos])
						} else {
							num = 1
							if (pos + 1) < len(rule) {
								t := rule[pos+1]
								if REG_NUM.MatchString(t) {
									num, _ = strconv.Atoi(t)
								}
							}
							break
						}
					} else {
						tmpexp = append(tmpexp, rule[pos])
					}
				}
				text, tmpexp, tmpresult = ComputeText(text, tmpexp, num)
				for tmpos, tmprule := range tmpexp {
					rule[thispos+tmpos] = tmprule
				}
			} else {
				tmpresult = strings.Index(text, tmp) > -1
				sclass := "f"
				if tmpresult {
					sclass = "t"
				}
				rule[pos] = fmt.Sprintf("<r class='_r%s'>%s</r>", sclass, tmp)
			}
			if op == "" {
				if (pos+1) < len(rule) && rule[pos+1] == "|" {
					op = "|"
				} else {
					op = "+"
				}
			}
			tclass := ""
			if op == "+" {
				if andB == nil {
					andB = []bool{}
				}
				andB = append(andB, tmpresult)
				tclass = "_and"

			} else if op == "|" {
				if orB == nil {
					orB = []bool{}
				}
				orB = append(orB, tmpresult)
				tclass = "_or"

			} else if op == "^" {
				if oB == nil {
					oB = []bool{}
				}
				oB = append(oB, tmpresult)
				tclass = "_opp"
			}
			if tclass != "" && tmp != "(" && tmp != ")" {
				text = strings.Replace(text, tmp, fmt.Sprintf("<r class='_and'>%s</r>", tmp), 1)
			}
		}
	}
	tres := CheckBool(andB, "+", 0) && CheckBool(orB, "|", num) && !CheckBool(oB, "^", 0)
	return text, rule, tres
}

//计算
func Compute(text string, rule []string, num int) (bool, []string) {
	var andB, orB, oB []bool
	op := ""
	arr := []string{}
	for pos := 0; pos < len(rule); pos++ {
		tmp := rule[pos]
		if tmp == "+" || tmp == "^" || tmp == "|" {
			op = tmp
			continue
		} else if REG_NUM.MatchString(tmp) && len(tmp) == 1 {
			continue
		} else {
			tmpresult := false
			if tmp == "(" { //找出子表达式，仅限一层,现在修改为多层逻辑
				tmpexp := []string{}
				pos++
				isRight := 0
				for ; pos < len(rule); pos++ {
					if rule[pos] == "(" {
						isRight++
						tmpexp = append(tmpexp, rule[pos])
					} else if rule[pos] == ")" {
						if isRight > 0 {
							isRight--
							tmpexp = append(tmpexp, rule[pos])
						} else {
							num = 1
							if (pos + 1) < len(rule) {
								t := rule[pos+1]
								if REG_NUM.MatchString(t) {
									num, _ = strconv.Atoi(t)
								}
							}
							break
						}
					} else {
						tmpexp = append(tmpexp, rule[pos])
					}
				}
				var arr1 []string
				tmpresult, arr1 = Compute(text, tmpexp, num)
				if len(arr1) > 0 {
					arr = append(arr, arr1...)
				}
			} else {
				tmpresult = strings.Index(text, tmp) > -1
				if op != "^" && tmpresult {
					arr = append(arr, tmp)
				}
			}
			if op == "" {
				if (pos+1) < len(rule) && rule[pos+1] == "|" {
					op = "|"
				} else {
					op = "+"
				}
			}
			if op == "+" {
				if andB == nil {
					andB = []bool{}
				}
				andB = append(andB, tmpresult)

			} else if op == "|" {
				if orB == nil {
					orB = []bool{}
				}
				orB = append(orB, tmpresult)
			} else if op == "^" {
				if oB == nil {
					oB = []bool{}
				}
				oB = append(oB, tmpresult)
			}
		}
	}
	tres := CheckBool(andB, "+", 0) && CheckBool(orB, "|", num) && !CheckBool(oB, "^", 0)
	if !tres {
		arr = []string{}
	}
	return tres, arr
}

func CheckBool(bs []bool, flag string, num int) bool {
	if flag == "+" {
		if bs == nil {
			return true
		} else if len(bs) == 0 {
			return false
		} else {
			b1 := bs[0]
			i := 0
			for _, v := range bs {
				if i > 0 {
					b1 = b1 && v
				}
				i++
			}
			return b1
		}
	} else if flag == "|" {
		if bs == nil {
			return true
		} else if len(bs) == 0 {
			return false
		} else {
			i := 0
			for _, v := range bs {
				if v {
					i++
				}
			}
			return i >= num
		}
	} else {
		if bs == nil {
			return false
		} else if len(bs) == 0 {
			return false
		} else {
			b1 := bs[0]
			i := 0
			for _, v := range bs {
				if i > 0 {
					b1 = b1 || v
				}
				i++
			}
			return b1
		}
	}
}
