/**
 *清理图片
 *取到的验证码需要先清理图片
 *去噪、滤色、二值化、中值去噪等
 *生成可以容易识别的图像，由ocr识别
**/
package spiderutil

import (
	"bytes"
	"image"
	"image/color"
	"math"
	mu "mfw/util"
	"os"
	"strings"

	"github.com/disintegration/imaging"
	"github.com/donnie4w/go-logger/logger"
)

var client *mu.Client

const (
	white, black = uint8(0xff), uint8(0x00)
)

//获取验证码
func GetEcpsCode(area string, img []byte) (code, state string) {
	defer mu.Catch()
	var err error
	var bs []byte
	area = strings.ToUpper(area)
	switch area {
	case "JX":
		bs, err = Clean4JX(img)
		code, err = Ocr4Web(bs)
		code = Math2JX(code)
	case "NX":
		bs, err = Clean4NX(img)
		code, err = Ocr4Web(bs)
		code = Math2NX(code)
	case "SC":
		bs, err = Clean4QC(img)
		code, err = Ocr4Web(bs)
		code = Math2SC(code)
	case "CQ":
		bs, err = Clean4QC(img)
		code, err = Ocr4Web(bs)
		code = Math2CQ(code)
	case "LN":
		bs, err = Clean4LN(img)
		code, err = Ocr4Web(bs)
	case "TJ":
		bs, err = Clean4TJ(img)
		code, err = Ocr4Web(bs)
		code = Math2(code)
	case "BJ":
		bs, err = Clean4BJ(img)
		code, err = Ocr4Web(bs)
	case "FJ":
		bs, err = Clean4FJ(img)
		code, err = Ocr4Web(bs)
	case "JS":
		bs, err = Clean4JS(img)
		code, err = Ocr4Web(bs)
	case "JL":
		bs, err = Clean4JL(img)
		code, err = Ocr4Web(bs)
		code = Math2JL(code)
	case "SD":
		bs, err = Clean4JL(img)
		code, err = Ocr4Web(bs)
		code = Math2JL(code)
	default: //微信验证
		code = ""
		state = "wx"
		//code, err = GetCodeByWx(img)
	}
	if err != nil {
		return "", ""
	}
	return code, state
}

//宁夏验证码清理
func Clean4NX(img []byte) ([]byte, error) {
	r := bytes.NewBuffer(img)
	//读源文件
	srcImg, err := imaging.Decode(r)
	if err != nil {
		return nil, err
	}
	//二值化图片
	dstImage := imaging.AdjustFunc(srcImg, func(c color.NRGBA) color.NRGBA {
		rgb := (int32(c.R) + int32(c.G) + int32(c.B)) / 3
		if rgb > 86 { //大于阈值全部置黑
			return color.NRGBA{white, white, white, c.A}
		} else {
			return color.NRGBA{black, black, black, c.A}
		}
	})
	buf := new(bytes.Buffer)
	imaging.Encode(buf, dstImage, imaging.JPEG)
	return buf.Bytes(), nil
}

//江西验证码清理
func Clean4JX(img []byte) ([]byte, error) {
	r := bytes.NewBuffer(img)
	//读源文件
	srcImg, err := imaging.Decode(r)
	if err != nil {
		return nil, err
	}
	//二值化图片
	dstImage := imaging.AdjustFunc(srcImg, func(c color.NRGBA) color.NRGBA {
		rgb := (int32(c.R) + int32(c.G) + int32(c.B)) / 3
		if rgb > 145 { //大于阈值全部置黑
			return color.NRGBA{white, white, white, c.A}
		} else {
			return color.NRGBA{black, black, black, c.A}
		}
	})
	buf := new(bytes.Buffer)
	imaging.Encode(buf, dstImage, imaging.JPEG)
	return buf.Bytes(), nil
}

//吉林验证码清理
func Clean4JL(img []byte) ([]byte, error) {
	r := bytes.NewBuffer(img)
	//读源文件
	srcImg, err := imaging.Decode(r)
	if err != nil {
		return nil, err
	}
	width := srcImg.Bounds().Dx()
	height := srcImg.Bounds().Dy()
	neww := int(float64(width) + float64(height)*0.375)
	newh := height
	dstImage := image.NewNRGBA(image.Rect(0, 0, neww, newh))
	for w := 0; w < width; w++ {
		for h := 0; h < height; h++ {
			//目标最接近的一个点
			_i := float64(w) + float64(h)*0.375
			_j := float64(h)
			i := int(math.Floor(_i))
			j := int(math.Floor(_j))
			t := _i - float64(i)
			//取目标点颜色
			r, g, b, a := getInt8(srcImg.At(w, h).RGBA())
			dstImage.Set(i, j, color.NRGBA{r, g, b, a})
			if t != 0 {
				r, g, b, a = getInt8(srcImg.At(i-1, j-1).RGBA())
			}
		}
	}
	dstImage = imaging.AdjustFunc(
		dstImage,
		func(c color.NRGBA) color.NRGBA {
			rgb := (int32(c.R) + int32(c.G) + int32(c.B)) / 3
			if rgb > 140 { //大于阈值全部置黑
				return color.NRGBA{white, white, white, c.A}
			} else {
				return color.NRGBA{black, black, black, c.A}
			}
		})
	buf := new(bytes.Buffer)
	imaging.Encode(buf, dstImage, imaging.PNG)
	return buf.Bytes(), nil
}

//四川验证码清理
func Clean4SC(img []byte) ([]byte, error) {
	r := bytes.NewBuffer(img)
	//读源文件
	srcImg, err := imaging.Decode(r)
	if err != nil {
		return nil, err
	}
	//二值化图片
	dstImage := imaging.AdjustFunc(srcImg, func(c color.NRGBA) color.NRGBA {
		rgb := (int32(c.R) + int32(c.G) + int32(c.B)) / 3
		if rgb > 128 { //大于阈值全部置黑
			return color.NRGBA{white, white, white, c.A}
		} else {
			return color.NRGBA{black, black, black, c.A}
		}
	})
	buf := new(bytes.Buffer)
	imaging.Encode(buf, dstImage, imaging.JPEG)
	return buf.Bytes(), nil
}

//江苏验证码清理
func Clean4JS(img []byte) ([]byte, error) {
	r := bytes.NewBuffer(img)
	//读源文件
	srcImg, err := imaging.Decode(r)
	if err != nil {
		return nil, err
	}
	//二值化图片
	dstImage := imaging.AdjustFunc(srcImg, func(c color.NRGBA) color.NRGBA {
		rgb := (int32(c.R) + int32(c.G) + int32(c.B)) / 3
		if rgb > 190 { //大于阈值全部置黑
			return color.NRGBA{black, black, black, black}
		} else {
			return color.NRGBA{white, white, white, white}
		}

	})
	//去除0<20 40<Y中的椭圆线
	x := dstImage.Bounds().Dx()
	y := dstImage.Bounds().Dy()
	for i := 0; i < y; i++ {
		for k := 0; k < x; k++ {
			if i < 20 {
				dstImage.SetNRGBA(k, i, color.NRGBA{black, black, black, black})
			} else if i > 40 {
				dstImage.SetNRGBA(k, i, color.NRGBA{black, black, black, black})
			}
		}
	}
	for i := 0; i < x; i++ {
		for k := 0; k < y; k++ {
			mer, _, _, _ := dstImage.At(i, k).RGBA()
			if mer != 0 {
				flag := 0
				leftx, lefty := i-1, k-1
				top_bottom := make([]int, 0)
				left_right := make([]int, 0)
				for lx := 0; lx < 3; lx++ {
					for ly := 0; ly < 3; ly++ {
						colorr, _, _, _ := dstImage.At(leftx+lx, lefty+ly).RGBA()
						if leftx+lx == i && lefty+ly == y-1 || lefty+ly == y+1 {
							dstImage.SetNRGBA(i, k, color.NRGBA{0, 0, 0, 0})
							top_bottom = append(top_bottom, 1)
						}
						if lefty+ly == k && leftx+lx == x-1 || leftx+lx == x+1 {
							dstImage.SetNRGBA(i, k, color.NRGBA{0, 0, 0, 0})
							left_right = append(left_right, 1)
						}
						if colorr == 65535 {
							flag = flag + 1
						}
					}
				}
				if flag < 4 || len(top_bottom) == 2 || len(top_bottom) == 2 {
					dstImage.SetNRGBA(i, k, color.NRGBA{0, 0, 0, 0})
				}
			}

		}
	}
	buf := new(bytes.Buffer)
	imaging.Encode(buf, dstImage, imaging.JPEG)
	return buf.Bytes(), nil
}

//重庆验证码清理
func Clean4QC(img []byte) ([]byte, error) {
	r := bytes.NewBuffer(img)
	//读源文件
	srcimg, err := imaging.Decode(r)
	if err != nil {
		return nil, err
	}
	dstimage := imaging.AdjustFunc(
		srcimg,
		func(c color.NRGBA) color.NRGBA {
			if c.R < uint8(70) && c.G < uint8(70) && c.B < uint8(70) {
				return color.NRGBA{black, black, black, white}
			} else {
				return color.NRGBA{white, white, white, white}
			}
		})
	buf := new(bytes.Buffer)
	subimg := dstimage.SubImage(image.Rect(0, 924, 1024, 1024)).(*image.NRGBA)
	imaging.Encode(buf, subimg, imaging.JPEG)
	return buf.Bytes(), nil
}

//辽宁验证码清理
func Clean4LN(img []byte) ([]byte, error) {
	r := bytes.NewBuffer(img)
	//读源文件
	srcimg, err := imaging.Decode(r)
	if err != nil {
		return nil, err
	}
	rang := uint8(30)
	dstimage := imaging.AdjustFunc(
		srcimg,
		func(c color.NRGBA) color.NRGBA {
			if white-c.R < rang && white-c.G < rang && white-c.B < rang {
				return color.NRGBA{black, black, black, white}
			} else {
				return color.NRGBA{white, white, white, white}
			}
		})
	buf := new(bytes.Buffer)
	imaging.Encode(buf, dstimage, imaging.JPEG)
	return buf.Bytes(), nil
}

//天津
func Clean4TJ(img []byte) ([]byte, error) {
	var max, min uint8 = 0x70, 0x00
	var tan float64 = 0.1405
	srcimg, err := imaging.Decode(bytes.NewBuffer(img))
	if err != nil {
		return nil, err
	}
	dstimg := imaging.Grayscale(srcimg)
	dstimg = imaging.AdjustFunc(
		dstimg,
		func(c color.NRGBA) color.NRGBA {
			if c.R > min && c.R < max && c.B > min && c.B < max && c.G > min && c.G < max {
				return color.NRGBA{black, black, black, white}
			} else {
				return color.NRGBA{white, white, white, white}
			}
		})
	dstimg = imaging.CropCenter(dstimg, 195, 25)
	w, h := 195, 25 //目标图像的宽高
	for x := 0; x < h; x++ {
		pos := int(float64(h-x) * tan)
		for y := 0; y < w; y++ {
			if y+pos < w {
				dstimg.SetNRGBA(y, x, dstimg.NRGBAAt(y+pos, x))
			} else {
				dstimg.SetNRGBA(y, x, color.NRGBA{R: white, G: white, B: white, A: white})
			}
		}
	}
	buf := new(bytes.Buffer)
	imaging.Encode(buf, dstimg, imaging.JPEG)
	f, _ := os.Create("d:/tj.jpg")
	imaging.Encode(f, dstimg, imaging.JPEG)
	logger.Debug("保存成功")
	return buf.Bytes(), nil
}

//北京验证码清理
var valve uint8 = 0x10

func Clean4BJ(img []byte) ([]byte, error) {
	srcImg, err := imaging.Decode(bytes.NewBuffer(img))
	if err != nil {
		return nil, err
	}
	//imaging.Save(srcImg, "/Users/smallow/Downloads/bj.jpg")
	//log.Print("下载北京原图片成功...")
	destImg := imaging.AdjustFunc(srcImg, func(c color.NRGBA) color.NRGBA {
		if c.R < valve && c.G < valve && c.B < valve {
			return color.NRGBA{white, white, white, white}
		} else if c.R > 0xe0 && c.G > 0xe0 && c.G > 0xe0 {
			return color.NRGBA{white, white, white, white}
		} else {
			return color.NRGBA{black, black, black, white}
		}
	})

	//imaging.Save(destImg, "/Users/smallow/Downloads/bj2.jpg")
	//log.Print("图片置黑成功")
	w, h := 200, 50
	for y := 1; y < h-1; y++ {
		for x := 1; x < w-1; x++ {
			tmp := [2][2]color.Color{
				{destImg.At(x, y), destImg.At(x+1, y)},
				{destImg.At(x, y+1), destImg.At(x+1, y+1)},
			}
			if !isWhiteColor(&tmp[0][0]) {
				if isWhiteColor(&tmp[0][1]) && isWhiteColor(&tmp[1][0]) && isWhiteColor(&tmp[1][1]) {
					destImg.SetNRGBA(x, y, color.NRGBA{white, white, white, white})

				}
			}
		}
	}

	//imaging.Save(destImg, "/Users/smallow/Downloads/bj3.jpg")
	//裁掉外边
	destImg = imaging.CropCenter(destImg, w-2, h-2)
	buf := new(bytes.Buffer)
	imaging.Encode(buf, destImg, imaging.JPEG)
	return buf.Bytes(), nil

}

var dstimg *image.NRGBA

//福建验证码清理
func Clean4FJ(img []byte) ([]byte, error) {
	srcimg, err := imaging.Decode(bytes.NewBuffer(img))
	if err != nil {
		return nil, err
	}
	imaging.Save(srcimg, "/Users/smallow/Downloads/fj_bj.jpg")
	//滤色加强，强化对比度
	dstimg = imaging.AdjustFunc(
		srcimg,
		func(c color.NRGBA) color.NRGBA {
			if c.R < 0xe0 && c.G < 0xe0 && c.B < 0xe0 {
				return color.NRGBA{black, black, black, white}
			} else {
				return color.NRGBA{white, white, white, white}
			}
		})
	imaging.Save(dstimg, "/Users/smallow/Downloads/fj_bj1.jpg")
	//	w, h := 160, 53
	return nil, nil
}

func getInt8(r, g, b, a uint32) (uint8, uint8, uint8, uint8) {
	return uint8(r / 256), uint8(g / 256), uint8(b / 256), uint8(a / 256)
}

func isWhiteColor(c *color.Color) bool {
	r, g, b, _ := (*c).RGBA()
	return r > 0x30 && g > 0x30 && b > 0x30
}
