package main

/*
#include <stdlib.h>
*/
import "C"
import (
	JsCall2 "Sunny/JsCall"
	"Sunny/SunnyProxy"
	"Sunny/src/net/http"
	_ "Sunny/src/net/http/pprof"
	"bufio"
	"bytes"
	"compress/flate"
	"compress/gzip"
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/Trisia/gosysproxy"
	"github.com/andybalholm/brotli"
	"golang.org/x/image/webp"
	"image/jpeg"
	"image/png"
	"io"
	"io/ioutil"
	"net"
	"net/url"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"
	"unsafe"
)

var scene = make(map[int]*Handlemessage)
var sceneLock = sync.Mutex{}
var callback = 0 //回调函数指针地址
var NullString = C.CString("")

type Handler struct {
}

func Getscene(MessageId int) (*Handlemessage, bool) {
	sceneLock.Lock()
	defer sceneLock.Unlock()
	k := scene[MessageId]
	if k == nil {
		return nil, false
	}
	return k, true
}

//export SetRequestHeader
func SetRequestHeader(MessageId int, name, val *C.char) {
	k, ok := Getscene(MessageId)
	if ok == false {
		return
	}
	if k.request == nil {
		return
	}
	if k.request.Request == nil {
		return
	}
	if k.request.Request.Header == nil {
		k.request.Request.Header = make(http.Header)
	}
	k.request.Request.Header[C.GoString(name)] = []string{C.GoString(val)}
	//k.request.Request.Header.Set(C.GoString(name), C.GoString(val))
}

//export SetRequestProxy
func SetRequestProxy(MessageId int, val *C.char, val1 *C.char, out int) {
	k, ok := Getscene(MessageId)
	if ok == false {
		return
	}
	if k == nil {
		return
	}
	k.ip = C.GoString(val)
	k.Auth = C.GoString(val1)
	if out < 1 {
		k.ProxyTimeout = 60
	} else {
		k.ProxyTimeout = out
	}
}

//export GetResponseStatusCode
func GetResponseStatusCode(MessageId int) int {
	k, ok := Getscene(MessageId)
	if ok == false {
		return -1
	}
	if k == nil {
		return -1
	}
	if k.request == nil {
		return -1
	}
	if k.request.Response == nil {
		return -1
	}

	return k.request.Response.StatusCode
}

//export GetRequestClientIp
func GetRequestClientIp(MessageId int) uintptr {
	k, ok := Getscene(MessageId)
	if ok == false {
		return 0
	}
	if k == nil {
		return 0
	}
	if k.request == nil {
		return 0
	}
	if k.request.ClientIp == nil {
		return 0
	}
	if len(k.request.ClientIp) < 1 {
		return 0
	}
	return uintptr(unsafe.Pointer(&k.request.ClientIp[0]))
}

//export GetResponseStatus
func GetResponseStatus(MessageId int) *C.char {
	k, ok := Getscene(MessageId)
	if ok == false {
		return NullString
	}
	if k == nil {
		return NullString
	}
	if k.request == nil {
		return NullString
	}
	if k.request.Response == nil {
		return NullString
	}
	n := C.CString(k.request.Response.Status)
	k.Handle = append(k.Handle, unsafe.Pointer(n))
	return n
}

//export SetResponseStatus
func SetResponseStatus(MessageId, code int) {
	k, ok := Getscene(MessageId)
	if ok == false {
		return
	}
	if k == nil {
		return
	}
	if k.request == nil {
		return
	}
	if k.request.Response == nil {
		return
	}
	k.request.Response.StatusCode = code
	k.request.Response.Status = strconv.Itoa(code) + " " + SunnyProxy.StatusText[code]
}

//export DelResponseHeader
func DelResponseHeader(MessageId int, name *C.char) {
	k, ok := Getscene(MessageId)
	if ok == false {
		return
	}
	if k == nil {
		return
	}
	if k.request == nil {
		return
	}
	if k.request.Response == nil {
		return
	}
	if k.request.Response.Header == nil {
		k.request.Response.Header = make(http.Header)
	}
	//k.request.Response.Header.Del(C.GoString(name))
	delete(k.request.Response.Header, C.GoString(name))
}

//export DelRequestHeader
func DelRequestHeader(MessageId int, name *C.char) {
	k, ok := Getscene(MessageId)
	if ok == false {
		return
	}
	if k == nil {
		return
	}
	if k.request == nil {
		return
	}
	if k.request.Request == nil {
		return
	}
	if k.request.Request.Header == nil {
		k.request.Request.Header = make(http.Header)
	}
	//k.request.Request.Header.Del(C.GoString(name))
	delete(k.request.Request.Header, C.GoString(name))
}

//export SetRequestUrl
func SetRequestUrl(MessageId int, URI *C.char) bool {
	f := C.GoString(URI)
	arr := strings.Split(f, "/")
	k, ok := Getscene(MessageId)
	if ok == false {
		return false
	}
	if k == nil {
		return false
	}
	if k.request == nil {
		return false
	}
	if k.request.Request == nil {
		return false
	}

	Host := k.request.Request.Host
	if len(arr) >= 3 {
		Host = arr[2]
	}

	_u, _ := url.Parse(f)
	k.request.Request.Host = Host
	k.request.Request.URL = _u
	k.request.Request.RequestURI = f
	return true
}

//export SetRequestCookie
func SetRequestCookie(MessageId int, name, val *C.char) {
	Cookie := ""
	bools := false
	sn := C.GoString(name)
	k, ok := Getscene(MessageId)
	if ok == false {
		return
	}
	if k == nil {
		return
	}
	if k.request == nil {
		return
	}
	if k.request.Request == nil {
		return
	}
	vals := k.request.Request.Cookies()
	for i := 0; i < len(vals); i++ {
		if vals[i].Name == sn {
			bools = true
			Cookie += vals[i].Name + "=" + C.GoString(val) + "; "
		} else {
			Cookie += vals[i].Name + "=" + vals[i].Value + "; "
		}
	}
	if bools == false {
		Cookie += sn + "=" + C.GoString(val) + "; "
	}

	if k.request.Request.Header == nil {
		k.request.Request.Header = make(http.Header)
	}
	k.request.Request.Header.Set("Cookie", Cookie)
}

//export SetRequestAllCookie
func SetRequestAllCookie(MessageId int, val *C.char) {
	k, ok := Getscene(MessageId)
	if ok == false {
		return
	}
	if k == nil {
		return
	}
	if k.request == nil {
		return
	}
	if k.request.Request == nil {
		return
	}
	if k.request.Request.Header == nil {
		k.request.Request.Header = make(http.Header)
	}
	k.request.Request.Header.Set("Cookie", C.GoString(val))
}

//export GetRequestHeader
func GetRequestHeader(MessageId int, name *C.char) *C.char {
	k, ok := Getscene(MessageId)
	if ok == false {
		return NullString
	}
	if k == nil {
		return NullString
	}
	if k.request == nil {
		return NullString
	}
	if k.request.Request == nil {
		return NullString
	}
	if k.request.Request.Header == nil {
		k.request.Request.Header = make(http.Header)
	}
	//val := k.request.Request.Header.Get(C.GoString(name))
	val := k.request.Request.Header[C.GoString(name)]
	if len(val) < 1 {
		return NullString
	}
	n := C.CString(val[0])
	k.Handle = append(k.Handle, unsafe.Pointer(n))
	return n
}

//export SetResponseHeader
func SetResponseHeader(MessageId int, name *C.char, val *C.char) {
	k, ok := Getscene(MessageId)
	if ok == false {
		return
	}
	if k == nil {
		return
	}
	if k.request == nil {
		return
	}
	if k.request.Response == nil {
		k.request.Response = new(http.Response)
		k.request.Response.Header = make(http.Header)
		k.request.Response.Header.Set("Server", "Sunny")
		k.request.Response.Header.Set("Accept-Ranges", "bytes")
		k.request.Response.Header.Set("Connection", "Close")
		k.request.Response.ContentLength = 0
		k.ResponseFile = true
	}
	if k.request.Response.Header == nil {
		k.request.Response.Header = make(http.Header)
	}
	k.request.Response.Header[C.GoString(name)] = []string{C.GoString(val)}
	//k.request.Response.Header.Set(C.GoString(name), C.GoString(val))
}

//export SetResponseAllHeader
func SetResponseAllHeader(MessageId int, value *C.char) {
	k, ok := Getscene(MessageId)
	if ok == false {
		return
	}
	if k == nil {
		return
	}
	if k.request == nil {
		return
	}
	if k.request.Response == nil {
		k.request.Response = new(http.Response)
		k.request.Response.Header = make(http.Header)
		k.request.Response.Header.Set("Server", "Sunny")
		k.request.Response.Header.Set("Accept-Ranges", "bytes")
		k.request.Response.Header.Set("Connection", "Close")
		k.request.Response.ContentLength = 0
		k.ResponseFile = true
	}
	if k.request.Response.Header == nil {
		k.request.Response.Header = make(http.Header)
	}
	s1 := C.GoString(value)
	arr := strings.Split(s1, "\r\n")
	if len(arr) > 0 {
		k.request.Response.Header = make(http.Header)
		for _, v := range arr {
			arr2 := strings.Split(v, ": ")
			if len(arr2) >= 1 {
				if len(v) >= len(arr2[0])+1 {
					data := strings.TrimSpace(v[len(arr2[0])+1:])
					if len(k.request.Response.Header[arr2[0]]) > 0 {
						k.request.Response.Header[arr2[0]] = append(k.request.Response.Header[arr2[0]], data)
					} else {
						k.request.Response.Header[arr2[0]] = []string{data}
					}
				}
			}
		}
	}
}

//export GetRequestCookie
func GetRequestCookie(MessageId int, name *C.char) *C.char {
	k, ok := Getscene(MessageId)
	if ok == false {
		return NullString
	}
	if k == nil {
		return NullString
	}
	if k.request == nil {
		return NullString
	}
	if k.request.Request == nil {
		return NullString
	}

	val, E := k.request.Request.Cookie(C.GoString(name))
	if E != nil {
		n := C.CString("")
		k.Handle = append(k.Handle, unsafe.Pointer(n))
		return n
	}
	n := C.CString(val.Name + "=" + val.Value + "; ")
	k.Handle = append(k.Handle, unsafe.Pointer(n))
	return n
}

//export GetRequestData
func GetRequestData(MessageId int) *C.char {
	k, ok := Getscene(MessageId)
	if ok == false {
		return NullString
	}
	if k.request == nil {
		return NullString
	}
	if k.request.Request == nil {
		return NullString
	}
	if k.request.Request.Body != nil {
		bodyBytes, e := ioutil.ReadAll(k.request.Request.Body)
		if e != nil {
			n := C.CString("")
			k.Handle = append(k.Handle, unsafe.Pointer(n))
			return n
		}
		k.request.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
		n := C.CString(string(bodyBytes))
		k.Handle = append(k.Handle, unsafe.Pointer(n))
		return n
	}
	n := C.CString("")
	k.Handle = append(k.Handle, unsafe.Pointer(n))
	return n
}

//export SetResponseData
func SetResponseData(MessageId int, data uintptr, datalen int) int {
	n := CStringToBytesMap(data, datalen)
	k, ok := Getscene(MessageId)
	if ok == false {
		return 0
	}
	if k == nil {
		return 0
	}
	if k.request == nil {
		return 0
	}
	if k.request.Response == nil {
		k.request.Response = new(http.Response)
		k.request.Response.Header = make(http.Header)
		k.request.Response.Header.Set("Server", "Sunny")
		k.request.Response.Header.Set("Accept-Ranges", "bytes")
		k.request.Response.Header.Set("Connection", "Close")
		k.ResponseFile = true
	}

	if k.request.Response.Header == nil {
		k.request.Response.Header = make(http.Header)
	}
	k.request.Response.Header.Set("Content-Length", strconv.Itoa(len(n)))
	k.request.Response.ContentLength = int64(len(n))
	k.request.Response.Body = ioutil.NopCloser(bytes.NewBuffer(n))
	return 1
}

//export SetIpProxy
func SetIpProxy(ip *C.char) {
	SunnyProxy.GlobalLock.Lock()
	defer SunnyProxy.GlobalLock.Unlock()
	SunnyProxy.GlobalProxyIp = C.GoString(ip)
}

//export SetIpAuth
func SetIpAuth(Auth *C.char) {
	SunnyProxy.GlobalLock.Lock()
	defer SunnyProxy.GlobalLock.Unlock()
	SunnyProxy.GlobalProxyAuth = C.GoString(Auth)
}

//export SetProxyTimeout
func SetProxyTimeout(Timeout int) {
	SunnyProxy.GlobalLock.Lock()
	defer SunnyProxy.GlobalLock.Unlock()
	SunnyProxy.GlobalProxyProxyTimeout = Timeout
}

//export GetResponseData
func GetResponseData(MessageId int) *C.char {
	k, ok := Getscene(MessageId)
	if ok == false {
		return NullString
	}
	if k == nil {
		return NullString
	}
	if k.request == nil {
		return NullString
	}
	if k.request.Response == nil {
		return NullString
	}
	if k.request.Response.Body != nil {
		bodyBytes, e := ioutil.ReadAll(k.request.Response.Body)
		if e != nil {
			n := C.CString("")
			k.Handle = append(k.Handle, unsafe.Pointer(n))
			return n
		}
		k.request.Response.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
		n := C.CString(string(bodyBytes))
		k.Handle = append(k.Handle, unsafe.Pointer(n))
		return n
	}
	n := C.CString("")
	k.Handle = append(k.Handle, unsafe.Pointer(n))
	return n
}

//export GetRequestBodyLen
func GetRequestBodyLen(MessageId int) int {
	k, ok := Getscene(MessageId)
	if ok == false {
		return 0
	}
	if k == nil {
		return 0
	}
	if k.request == nil {
		return 0
	}
	if k.request.Request == nil {
		return 0
	}
	if k.request.Request.Body != nil {
		bodyBytes, e := ioutil.ReadAll(k.request.Request.Body)
		k.request.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
		if e != nil {
			return 0
		}
		return len(bodyBytes)
	}
	return 0
}

//export GetResponseBodyLen
func GetResponseBodyLen(MessageId int) int {
	k, ok := Getscene(MessageId)
	if ok == false {
		return 0
	}
	if k == nil {
		return 0
	}
	if k.request == nil {
		return 0
	}
	if k.request.Response == nil {
		return 0
	}
	if k.request.Response.Body != nil {
		bodyBytes, e := ioutil.ReadAll(k.request.Response.Body)
		k.request.Response.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
		if e != nil {
			return 0
		}
		return len(bodyBytes)
	}
	return 0
}

//export SetRequestData
func SetRequestData(MessageId int, data uintptr, datalen int) int {
	n := CStringToBytesMap(data, datalen)
	k, ok := Getscene(MessageId)
	if ok == false {
		return 0
	}
	if k == nil {
		return 0
	}
	if k.request == nil {
		return 0
	}
	if k.request.Request == nil {
		return 0
	}
	k.request.Request.ContentLength = int64(len(n))
	k.request.Request.Body = ioutil.NopCloser(bytes.NewBuffer(n))
	return 1
}

//export GetRequestBody
func GetRequestBody(MessageId int) uintptr {
	k, ok := Getscene(MessageId)
	if ok == false {
		return uintptr(unsafe.Pointer(NullString))
	}
	if k == nil {
		return uintptr(unsafe.Pointer(NullString))
	}
	if k.request == nil {
		return uintptr(unsafe.Pointer(NullString))
	}
	if k.request.Request == nil {
		return uintptr(unsafe.Pointer(NullString))
	}
	if k.request.Request.Body != nil {
		bodyBytes, _ := ioutil.ReadAll(k.request.Request.Body)
		k.request.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
		n := C.CString(string(bodyBytes))
		k.Handle = append(k.Handle, unsafe.Pointer(n))
		return uintptr(unsafe.Pointer(n))
	}
	return 0
}

//export GetResponseBody
func GetResponseBody(MessageId int) uintptr {
	k, ok := Getscene(MessageId)
	if ok == false {
		return uintptr(unsafe.Pointer(NullString))
	}
	if k == nil {
		return uintptr(unsafe.Pointer(NullString))
	}
	if k.request == nil {
		return uintptr(unsafe.Pointer(NullString))
	}
	if k.request.Response == nil {
		return uintptr(unsafe.Pointer(NullString))
	}
	if k.request.Response.Body != nil {
		bodyBytes, _ := ioutil.ReadAll(k.request.Response.Body)
		k.request.Response.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
		n := C.CString(string(bodyBytes))
		k.Handle = append(k.Handle, unsafe.Pointer(n))
		return uintptr(unsafe.Pointer(n))
	}
	return 0
}

//export GetWebsocketBodyLen
func GetWebsocketBodyLen(MessageId int) int {
	k, ok := Getscene(MessageId)
	if ok == false {
		return 0
	}
	if k == nil {
		return 0
	}
	if k.msg == nil {
		return 0
	}
	return len(k.msg.As)
}

//export GetWebsocketBody
func GetWebsocketBody(MessageId int) uintptr {
	k, ok := Getscene(MessageId)
	if ok == false {
		return uintptr(unsafe.Pointer(NullString))
	}
	if k == nil {
		return uintptr(unsafe.Pointer(NullString))
	}
	n := C.CString(string(k.msg.As))
	k.Handle = append(k.Handle, unsafe.Pointer(n))
	return uintptr(unsafe.Pointer(n))
}

//export SetWebsocketBody
func SetWebsocketBody(MessageId int, data uintptr, datalen int) bool {
	n := CStringToBytesMap(data, datalen)
	k, ok := Getscene(MessageId)
	if ok == false {
		return false
	}
	if k == nil {
		return false
	}

	if k.msg == nil {
		return false
	}
	k.msg.As = n
	return true
}

//export SendWebsocketBody
func SendWebsocketBody(MessageId, MessageTpye int, data uintptr, datalen int) bool {
	n := CStringToBytesMap(data, datalen)
	k, ok := Getscene(MessageId)
	if ok == false {
		return false
	}
	if k == nil {
		return false
	}
	if k.msg == nil {
		return false
	}
	if k.msg.This == nil {
		return false
	}
	e := k.msg.This.WriteMessage(MessageTpye, n)
	if e != nil {
		return false
	}
	return true
}

//export GetRequestALLCookie
func GetRequestALLCookie(MessageId int) *C.char {
	k, ok := Getscene(MessageId)
	if ok == false {
		return NullString
	}
	if k == nil {
		return NullString
	}
	if k.request == nil {
		return NullString
	}
	if k.request.Request == nil {
		return NullString
	}
	val := k.request.Request.Cookies()
	Cookie := ""
	for i := 0; i < len(val); i++ {
		Cookie += val[i].Name + "=" + val[i].Value + "; "
	}
	n := C.CString(Cookie)
	k.Handle = append(k.Handle, unsafe.Pointer(n))
	return n
}

//export GetResponseAllHeader
func GetResponseAllHeader(MessageId int) *C.char {
	k, ok := Getscene(MessageId)
	if ok == false {
		return NullString
	}
	if k == nil {
		return NullString
	}
	if k.request == nil {
		return NullString
	}
	if k.request.Response == nil {
		return NullString
	}
	if k.request.Response.Header == nil {
		return NullString
	}
	Head := ""
	for name, values := range k.request.Response.Header {
		for _, value := range values {
			Head += name + ": " + value + "\r\n"
		}
	}
	n := C.CString(Head)
	k.Handle = append(k.Handle, unsafe.Pointer(n))
	return n
}

//export GetResponseHeader
func GetResponseHeader(MessageId int, name *C.char) *C.char {
	k, ok := Getscene(MessageId)
	if ok == false {
		return NullString
	}
	if k == nil {
		return nil
	}
	if k.request == nil {
		return NullString
	}
	if k.request.Response == nil {
		return NullString
	}
	if k.request.Response.Header == nil {
		return NullString
	}
	//Head := k.request.Response.Header.Get(C.GoString(name))
	Head := k.request.Response.Header[C.GoString(name)]
	if len(Head) < 1 {
		return NullString
	}
	n := C.CString(Head[0])
	k.Handle = append(k.Handle, unsafe.Pointer(n))
	return n
}

//export GetRequestAllHeader
func GetRequestAllHeader(MessageId int) *C.char {
	k, ok := Getscene(MessageId)
	if ok == false {
		return NullString
	}
	if k == nil {
		return NullString
	}
	if k.request == nil {
		return NullString
	}
	if k.request.Request == nil {
		return NullString
	}
	if k.request.Request.Header == nil {
		return NullString
	}
	Head := ""
	for name, values := range k.request.Request.Header {
		for _, value := range values {
			Head += name + ": " + value + "\r\n"
		}
	}
	n := C.CString(Head)
	k.Handle = append(k.Handle, unsafe.Pointer(n))
	return n
}

//export SetTcpBody
func SetTcpBody(MessageId, MsgType int, data uintptr, datalen int) bool {
	n := CStringToBytesMap(data, datalen)
	k, ok := Getscene(MessageId)
	if ok == false {
		return false
	}
	if k == nil {
		return false
	}
	if MsgType == 1 {
		if k.msg == nil {
			return false
		}
		k.msg.As = n
	}
	if MsgType == 2 {
		if k.msg2 == nil {
			return false
		}
		k.msg2.As = n
	}
	return true
}

//export SetTcpAgent
func SetTcpAgent(MessageId int, ip, user, pass *C.char) bool {
	k, ok := Getscene(MessageId)
	if ok == false {
		return false
	}
	if k == nil {
		return false
	}
	if k.msg == nil {
		return false
	}
	k.msg.TcpIp = C.GoString(ip)
	k.msg.TcpUser = C.GoString(user)
	k.msg.TcpPass = C.GoString(pass)
	return true
}

//export TcpCloseClient
func TcpCloseClient(Theonly int) bool {
	k := SunnyProxy.ConnList[int64(Theonly)]
	if k == nil {
		return false
	}
	_ = k.Close()
	return true
}

//export SetTcpConnectionIP
func SetTcpConnectionIP(MessageId int, data *C.char) bool {
	k, ok := Getscene(MessageId)
	if ok == false {
		return false
	}
	if k == nil {
		return false
	}
	if k.msg == nil {
		return false
	}
	k.msg.As = []byte(C.GoString(data))
	return true
}

//export TcpSendMsg
func TcpSendMsg(MessageId int, data uintptr, datalen int) int {
	n := CStringToBytesMap(data, datalen)
	defer func() {
		if err := recover(); err != nil {
			switch x := err.(type) {
			case string:
				fmt.Println("TcpSendMsg 出了错："+x, "./TcpSendMsg.txt")
			case error:
				fmt.Println("TcpSendMsg 出了错："+x.Error(), "./TcpSendMsg.txt")
			default:
				fmt.Println("TcpSendMsg 出了错："+"Unknow panic", "./TcpSendMsg.txt")
			}

		}
	}()

	SunnyProxy.TcpSceneLock.Lock()
	w := SunnyProxy.TcpScenes[MessageId]
	SunnyProxy.TcpSceneLock.Unlock()
	if w == nil {
		return 0
	}
	bw := w.(*SunnyProxy.Brw)
	if bw == nil {
		return 0
	}
	if bw.B == nil {
		return 0
	}
	bw.L.Lock()
	defer bw.L.Unlock()
	if len(n) > 0 {
		x, e := bw.B.Write(n)
		if e == nil {
			_ = bw.B.Flush()
		}
		return x
	}
	return 0
}

//export TcpSendMsgClient
func TcpSendMsgClient(MessageId int, data uintptr, datalen int) int {
	n := CStringToBytesMap(data, datalen)
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("TcpSendMsgClient 出了错：", err)
		}
	}()
	SunnyProxy.TcpSceneLock.Lock()
	w := SunnyProxy.TcpScenes[MessageId]
	SunnyProxy.TcpSceneLock.Unlock()
	if w == nil {
		return 0
	}
	bw := w.(*SunnyProxy.Brw)
	if bw == nil {
		return 0
	}
	if len(n) > 0 {
		bw.L.Lock()
		defer bw.L.Unlock()
		x, e := bw.C.Write(n)
		if e == nil {
			bw.C.Flush()
		}
		return x
	}
	return 0
}

var MessageIdLock sync.Mutex
var MessageM = 10000

func NewMessageId() int {
	MessageIdLock.Lock()
	MessageM = MessageM + 1
	t := MessageM
	MessageIdLock.Unlock()
	return t
}

func (handler *Handler) BeforeRequest(entity *SunnyProxy.Entity, TheonlyId int64) int {
	/*
		Mod := entity.Request.Method
		Url := entity.Request.URL.String()
		fmt.Println(Mod, Url)
	*/
	//fmt.Println(entity.Request.Header)
	//请求前
	ox := 0
	if callback != 0 {
		MessageId := NewMessageId()

		Mod := entity.Request.Method
		Url := entity.Request.URL.String()
		Url = strings.Replace(Url, ":80/", "/", 1)
		Url = strings.Replace(Url, ":443/", "/", 1)
		_, ok := Getscene(MessageId)
		if ok == false {
			F := &Handlemessage{request: entity}
			sceneLock.Lock()
			scene[MessageId] = F
			sceneLock.Unlock()
		}
		pid, _ := strconv.Atoi(entity.Pid)
		SunnyProxy.Call(callback, uintptr(MessageId), 1, Mod, Url, TheonlyId, 0, "", pid, 255)
		k, ok := Getscene(MessageId)
		if ok == false {
			k, ok = Getscene(MessageId)
		}
		if ok {
			if k.ip != "" {
				entity.Ip = k.ip
				entity.Auth = k.Auth
				entity.ProxyTimeout = k.ProxyTimeout
			}
			if k.ResponseFile {
				ox = 1
			}
			for i := 0; i < len(k.Handle); i++ {
				C.free(k.Handle[i])
			}
			sceneLock.Lock()
			delete(scene, MessageId)
			sceneLock.Unlock()
		}
	}
	return ox
}
func (handler *Handler) TCPRequest(sname, hostname string, tcpcallType int, msgid int64, msg *SunnyProxy.WebsocketMsg, spid string) {

	if OpenTcpcallback < 10 {
		return
	}
	pid, _ := strconv.Atoi(spid)
	if tcpcallType != 1 && tcpcallType != 2 && tcpcallType != 4 {
		SunnyProxy.Call(OpenTcpcallback, sname, hostname, tcpcallType, msgid, []byte{}, 0, msgid, pid)
		return
	}
	if msg == nil {
		SunnyProxy.Call(OpenTcpcallback, sname, hostname, tcpcallType, msgid, []byte{}, 0, msgid, pid)
		return
	}

	MessageId := NewMessageId()
	c, ok := Getscene(MessageId)
	if ok == false {
		if tcpcallType == 1 || tcpcallType == 4 {
			F := &Handlemessage{msg: msg}
			sceneLock.Lock()
			scene[MessageId] = F
			sceneLock.Unlock()
		} else {
			F := &Handlemessage{msg2: msg}
			sceneLock.Lock()
			scene[MessageId] = F
			sceneLock.Unlock()
		}

	} else {
		if tcpcallType == 1 || tcpcallType == 4 {
			c.msg = msg
		} else {
			c.msg2 = msg
		}
	}
	SunnyProxy.Call(OpenTcpcallback, sname, hostname, tcpcallType, MessageId, msg.As, len(msg.As), msgid, pid)
	k, ok := Getscene(MessageId)
	if ok {
		for i := 0; i < len(k.Handle); i++ {
			C.free(k.Handle[i])
		}
		sceneLock.Lock()
		delete(scene, MessageId)
		sceneLock.Unlock()
	}

}
func (handler *Handler) BeforeResponse(entity *SunnyProxy.Entity, TheonlyId int64, i int) int {
	//请求后
	if callback != 0 {
		MessageId := NewMessageId()
		Mod := entity.Request.Method
		Url := entity.Request.URL.String()
		Url = strings.Replace(Url, ":80/", "/", 1)
		Url = strings.Replace(Url, ":443/", "/", 1)
		_, ok := Getscene(MessageId)
		if ok == false {
			F := &Handlemessage{request: entity}
			sceneLock.Lock()
			scene[MessageId] = F
			sceneLock.Unlock()
		}
		pid, _ := strconv.Atoi(entity.Pid)
		ox := 0

		ox = SunnyProxy.Call(callback, uintptr(MessageId), 2, Mod, Url, TheonlyId, i, "", pid, 255)

		k, ok := Getscene(MessageId)
		if ok {
			for i := 0; i < len(k.Handle); i++ {
				C.free(k.Handle[i])
			}
			sceneLock.Lock()
			delete(scene, MessageId)
			sceneLock.Unlock()
		}
		return ox
	}
	return 0
}
func (handler *Handler) WssRequest(entity *SunnyProxy.Entity, flag int, msg *SunnyProxy.WebsocketMsg, ThenId int64, pid int) {
	//Websocket消息
	if callback != 0 {
		MessageId := SunnyProxy.GetContextID(int(uintptr(unsafe.Pointer(msg))))
		Mod := "wss"
		Url := entity.Request.URL.String()
		if strings.Index(Url, "net://") != -1 {
			Mod = "ws"
		}
		Url = strings.Replace(Url, ":80/", "/", 1)
		Url = strings.Replace(Url, ":443/", "/", 1)
		_, ok := Getscene(MessageId)
		if ok == false {
			F := &Handlemessage{request: entity, msg: msg}
			sceneLock.Lock()
			scene[MessageId] = F
			sceneLock.Unlock()
		}
		SunnyProxy.Call(callback, uintptr(MessageId), flag, Mod, Url, ThenId, 0, "", pid, msg.Mt)
		k, ok := Getscene(MessageId)
		if ok {
			for i := 0; i < len(k.Handle); i++ {
				C.free(k.Handle[i])
			}
			k.Handle = make([]unsafe.Pointer, 0)
			if flag == 6 || flag == 10 {
				//WS 断开。或 wss 断开时
				sceneLock.Lock()
				delete(scene, MessageId)
				sceneLock.Unlock()
				return
			}
		}
	}
}
func (handler *Handler) ErrorLog(entity *SunnyProxy.Entity, err error, TheonlyId int64) {
	//请求失败
	if callback != 0 {
		MessageId := NewMessageId()
		Mod := entity.Request.Method
		Url := entity.Request.URL.String()

		Url = strings.Replace(Url, ":80/", "/", 1)
		Url = strings.Replace(Url, ":443/", "/", 1)

		_, ok := Getscene(MessageId)
		if ok == false {
			F := &Handlemessage{request: entity}
			sceneLock.Lock()
			scene[MessageId] = F
			sceneLock.Unlock()
		}
		pid, _ := strconv.Atoi(entity.Pid)
		SunnyProxy.Call(callback, uintptr(MessageId), 11, Mod, Url, TheonlyId, 0, err.Error(), pid, 0)
		k, ok := Getscene(MessageId)
		if ok {
			for i := 0; i < len(k.Handle); i++ {
				C.free(k.Handle[i])
			}
			sceneLock.Lock()
			delete(scene, MessageId)
			sceneLock.Unlock()
		}
	}

}

var RootcaManager = 0

//export SetCa
func SetCa(ca int) {
	RootcaManager = ca
}

//export HexDump
func HexDump(data uintptr, datalen int) *C.char {
	bin := CStringToBytesMap(data, datalen)
	hexs := strings.ReplaceAll(hex.Dump(bin), "\n", "\r\n")
	prt_ := C.CString(hexs)
	//请确保该指针及时使用 5秒后释放该指针
	go ReleasePrt(unsafe.Pointer(prt_))
	return prt_
}
func ReleasePrt(prt unsafe.Pointer) {
	//5秒后释放该指针
	time.Sleep(5 * time.Second)
	if uintptr(prt) > 0 {
		C.free(prt)
	}
}

func Stat_proxt(port int) {
	Processportstr = strconv.Itoa(port + 1)
	SunnyProxy.Stat(port, &Handler{}, _ExportCA(RootcaManager), _ExportKEY(RootcaManager), OpenTcpcallback)
}

var errprt unsafe.Pointer

//export Geterr
func Geterr() *C.char {
	if uintptr(errprt) != 0 {
		C.free(errprt) //释放上次信息的内存
	}
	s := ""
	if SunnyProxy.RunErr != nil {
		s = SunnyProxy.RunErr.Error()
	}
	c := C.CString(s)
	errprt = unsafe.Pointer(c) //将错误信息放入全局，下次调用本函数时释放
	return c
}

var Ieprooxy int

//export SetIeProxy
func SetIeProxy(del bool) bool {
	//"github.com/Trisia/gosysproxy"

	if runtime.GOOS == "windows" {
		if del {
			gosysproxy.Off()
			return true
		}
		gosysproxy.SetGlobalProxy("127.0.0.1:" + strconv.Itoa(Ieprooxy))
		return true
	}

	return false
}

//export PInit
func PInit(port, _callback, IsInstall, SetIEproxy int) bool {
	Ieprooxy = port
	callback = _callback
	go Stat_proxt(port)
	time.Sleep(1 * time.Second) //等待1秒
	if SunnyProxy.IsRun {
		if IsInstall > 0 {
			s := InstallCert()
			ss := errors.New(s)
			SunnyProxy.RunErr = ss
		}
		if SetIEproxy > 0 {
			SetIeProxy(false)
		}
		return true
	}
	return false
}
func InstallCert() string {
	if runtime.GOOS == "windows" {
		path, err := os.Getwd()
		if err != nil {
			return err.Error()
		}
		WriteStringtoFile(SunnyProxy.InstallCa, path+"\\ca.crt")
		var args []string
		args = append(args, "-addstore")
		args = append(args, "root")
		args = append(args, path+"\\ca.crt")
		defer RemoveFile(path + "\\ca.crt")
		return execCommand("certutil", args)
	}
	return "The certificate is not automatically installed"
}
func WriteStringtoFile(Text, Filename string) error {
	return WriteBytestoFile([]byte(Text), Filename)
}
func CheckFileIsExist(filename string) bool {
	var exist = true
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		exist = false
	}
	return exist
}

// RemoveFile
//
// 删除文件
func RemoveFile(Filename string) error {
	return os.Remove(Filename)
}

// WriteBytestoFile
//
// 写[]byte到文件
func WriteBytestoFile(bytes []byte, Filename string) error {
	var f *os.File
	var err error
	//文件是否存在
	if CheckFileIsExist(Filename) {
		//存在 删除
		err = RemoveFile(Filename)
		if err != nil {
			return err
		}
	}
	//创建文件
	f, err = os.Create(Filename)
	if err != nil {
		return err
	}
	defer f.Close()
	// 写入
	_, err = f.Write(bytes)
	if err != nil {
		return err
	}
	return nil
}

func execCommand(commandName string, params []string) string {
	cmd := exec.Command(commandName, params...)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err.Error()
	}
	if runtime.GOOS == "windows" {
		cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
	}
	cmd.Start()
	s := []byte{}
	reader := bufio.NewReader(stdout)
	for {
		line, err2 := reader.ReadBytes('\n')
		if err2 != nil || io.EOF == err2 {
			break
		}
		s = BytesCombine(s, line)
	}
	//v, _ := GbkToUtf8(s)
	return string(s)
}

var CStringToBytes = func(r uintptr) []byte {
	data := make([]byte, 0)
	i := 0
	for {
		v := *(*byte)(unsafe.Pointer(r + uintptr(i)))
		if v == 0 {
			break
		}
		data = append(data, v)
		i++
	}

	return data
}

func BytesCombine(pBytes ...[]byte) []byte {
	len := len(pBytes)
	s := make([][]byte, len)
	for index := 0; index < len; index++ {
		s[index] = pBytes[index]
	}
	sep := []byte("")
	return bytes.Join(s, sep)
}

var OpenTcpcallback int

//export OpenTcp
func OpenTcp(s int) {
	OpenTcpcallback = s
}

//export Stop
func Stop() {
	SunnyProxy.Stop()
}

//export BrUnCompress
func BrUnCompress(val uintptr, vallen int) uintptr {
	bin := CToBytes(val, vallen)
	if len(bin) < 1 {
		return 0
	}
	b, _ := ioutil.ReadAll(brotli.NewReader(ioutil.NopCloser(bytes.NewBuffer(bin))))
	b = BytesCombine(IntToBytes(len(b)), b)
	n := C.CString(string(b))
	return uintptr(unsafe.Pointer(n))
}

//export GzipUnCompress
func GzipUnCompress(val uintptr, vallen int) uintptr {
	bin := CToBytes(val, vallen)
	if len(bin) < 1 {
		return 0
	}
	gr, err := gzip.NewReader(ioutil.NopCloser(bytes.NewBuffer(bin)))
	if err != nil {
		return 0
	}
	b, _ := ioutil.ReadAll(gr)
	b = BytesCombine(IntToBytes(len(b)), b)
	n := C.CString(string(b))
	return uintptr(unsafe.Pointer(n))
}

//export DeflateUnCompress
func DeflateUnCompress(val uintptr, vallen int) uintptr {
	bin := CToBytes(val, vallen)
	if len(bin) < 1 {
		return 0
	}
	zr := flate.NewReader(ioutil.NopCloser(bytes.NewBuffer(bin)))
	defer zr.Close()
	b, _ := ioutil.ReadAll(zr)
	b = BytesCombine(IntToBytes(len(b)), b)
	n := C.CString(string(b))
	return uintptr(unsafe.Pointer(n))
}

//export BytesToInt
func BytesToInt(val uintptr, vallen int) int {
	bys := CToBytes(val, vallen)
	buff := bytes.NewBuffer(bys)
	var data int64
	binary.Read(buff, binary.BigEndian, &data)
	return int(data)
}

func IntToBytes(n int) []byte {
	data := int64(n)
	bytebuf := bytes.NewBuffer([]byte{})
	binary.Write(bytebuf, binary.BigEndian, data)
	return bytebuf.Bytes()
}

//export Cfree
func Cfree(s uintptr) {
	C.free(unsafe.Pointer(s))
}

var CToBytes = func(r uintptr, datalen int) []byte {
	var b bytes.Buffer
	if r != 0 && datalen > 0 {
		for i := 0; i < datalen; i++ {
			p := *(*byte)(unsafe.Pointer(r + uintptr(i)))
			b.WriteByte(p)
		}
	}

	return b.Bytes()
}

type Handlemessage struct {
	request      *SunnyProxy.Entity
	Handle       []unsafe.Pointer
	msg          *SunnyProxy.WebsocketMsg
	msg2         *SunnyProxy.WebsocketMsg
	ip           string
	Auth         string
	ProxyTimeout int
	ResponseFile bool
}

type ProcessPidOperation struct {
	Pid  int    `json:"pid"`
	Type string `json:"type"`
}

var Processportstr string
var ProcessTCP net.Conn
var ProcessLock sync.Mutex

//export StartProcess
func StartProcess() bool {
	ProcessLock.Lock()
	defer ProcessLock.Unlock()
	var err error
	SunnyProxy.Process(SunnyProxy.ProcessPort)
	time.Sleep(3 * time.Second)
	ProcessTCP, err = net.Dial("tcp", "127.0.0.1:"+Processportstr)
	if err != nil {
		return false
	}
	return true
}

//export ProcessAddPID
func ProcessAddPID(s int) bool {
	ProcessLock.Lock()
	defer ProcessLock.Unlock()
	pid := new(ProcessPidOperation)
	pid.Pid = s
	pid.Type = "Add"
	b, _ := json.Marshal(pid)
	ProcessTCP.Write(b)
	var buf [10]byte
	n, _ := ProcessTCP.Read(buf[0:])
	if n >= 2 {
		if buf[0] == 1 && buf[1] == 0 {
			return true
		}
	}
	return false
}

//export ProcessStart
func ProcessStart() bool {
	ProcessLock.Lock()
	defer ProcessLock.Unlock()
	pid := new(ProcessPidOperation)
	pid.Pid = 0
	pid.Type = "start"
	b, _ := json.Marshal(pid)
	ProcessTCP.Write(b)
	var buf [10]byte
	n, _ := ProcessTCP.Read(buf[0:])

	if n >= 2 {
		if buf[0] == 1 && buf[1] == 0 {
			return true
		}
	}
	return false
}

//export ProcessCancelAll
func ProcessCancelAll() bool {
	ProcessLock.Lock()
	defer ProcessLock.Unlock()
	pid := new(ProcessPidOperation)
	pid.Pid = 0
	pid.Type = "CancelAll"
	b, _ := json.Marshal(pid)
	ProcessTCP.Write(b)
	var buf [10]byte
	n, _ := ProcessTCP.Read(buf[0:])
	if n >= 2 {
		if buf[0] == 1 && buf[1] == 0 {
			return true
		}
	}
	return false
}

//export ProcessDelPID
func ProcessDelPID(s int) bool {
	ProcessLock.Lock()
	defer ProcessLock.Unlock()
	pid := new(ProcessPidOperation)
	pid.Pid = s
	pid.Type = "Del"
	b, _ := json.Marshal(pid)
	ProcessTCP.Write(b)
	var buf [10]byte
	n, _ := ProcessTCP.Read(buf[0:])
	if n >= 2 {
		if buf[0] == 1 && buf[1] == 0 {
			return true
		}
	}
	return false
}

//export DelP12Certificate
func DelP12Certificate(HostName *C.char) {
	SunnyProxy.DelP12Certificate(C.GoString(HostName))
}

//export AddP12Certificate
func AddP12Certificate(HostName, privateKeyName, privatePassword *C.char, cerType int) bool {
	return SunnyProxy.AddP12Certificate(C.GoString(HostName), C.GoString(privateKeyName), C.GoString(privatePassword), cerType)
}

//export WebpToPng
func WebpToPng(webpPath, savePath *C.char) bool {
	webpName := C.GoString(webpPath)
	save := C.GoString(savePath)
	f0, err := os.Open(webpName)
	if err != nil {
		return false
	}
	defer func() {
		_ = f0.Close()
	}()
	img0, err := webp.Decode(f0)
	if err != nil {
		return false
	}
	pngFile, err := os.Create(save)
	if err != nil {
		return false
	}
	defer func() {
		_ = pngFile.Close()
	}()
	err = png.Encode(pngFile, img0)
	if err != nil {
		return false
	}
	return true
}

//export WebpToJpeg
func WebpToJpeg(webpPath, savePath *C.char, SaveQuality int) bool {
	webpName := C.GoString(webpPath)
	save := C.GoString(savePath)
	f0, err := os.Open(webpName)
	if err != nil {
		return false
	}
	defer func() {
		_ = f0.Close()
	}()
	img0, err := webp.Decode(f0)
	if err != nil {
		return false
	}
	pngFile, err := os.Create(save)
	if err != nil {
		return false
	}
	defer func() {
		_ = pngFile.Close()
	}()
	_SaveQuality := SaveQuality
	if _SaveQuality < 1 {
		SaveQuality = 75
	}
	err = jpeg.Encode(pngFile, img0, &jpeg.Options{Quality: _SaveQuality})
	if err != nil {
		return false
	}
	return true
}

//export WebpToPngBytes
func WebpToPngBytes(val uintptr, vallen int) uintptr {
	_webp := CToBytes(val, vallen)
	var b bytes.Buffer
	b.Write(_webp)
	defer func() {
		b.Reset()
	}()
	img0, err := webp.Decode(&b)
	if err != nil {
		return 0
	}
	var bs bytes.Buffer
	defer func() {
		bs.Reset()
	}()
	err = png.Encode(&bs, img0)
	if bs.Len() < 1 || err != nil {
		return 0
	}
	bn := bs.Bytes()
	bn = BytesCombine(IntToBytes(len(bn)), bn)
	return uintptr(unsafe.Pointer(&bn[0]))
}

//export WebpToJpegBytes
func WebpToJpegBytes(val uintptr, vallen int, SaveQuality int) uintptr {
	_webp := CToBytes(val, vallen)
	var b bytes.Buffer
	b.Write(_webp)
	defer func() {
		b.Reset()
	}()
	img0, err := webp.Decode(&b)
	if err != nil {
		return 0
	}
	var bs bytes.Buffer
	defer func() {
		bs.Reset()
	}()
	_SaveQuality := SaveQuality
	if _SaveQuality < 1 {
		SaveQuality = 75
	}
	err = jpeg.Encode(&bs, img0, &jpeg.Options{Quality: _SaveQuality})
	if bs.Len() < 1 || err != nil {
		return 0
	}
	bn := bs.Bytes()
	bn = BytesCombine(IntToBytes(len(bn)), bn)
	return uintptr(unsafe.Pointer(&bn[0]))
}

//export MustTcp
func MustTcp(i bool) {
	SunnyProxy.MustTcp = i
}

//export VerifyUser
func VerifyUser(i bool) {
	SunnyProxy.VerifyUser = i
}

//export AddVerifyUser
func AddVerifyUser(u *C.char, p *C.char) bool {
	user := C.GoString(u)
	pass := C.GoString(p)
	if len(user) == 0 || len(pass) == 0 {
		return false
	}
	SunnyProxy.VerifyUserLock.Lock()
	SunnyProxy.VerifyUserList[user] = pass
	SunnyProxy.VerifyUserLock.Unlock()
	return true
}

//export DelVerifyUser
func DelVerifyUser(u *C.char) bool {
	user := C.GoString(u)
	if len(user) == 0 {
		return false
	}
	SunnyProxy.VerifyUserLock.Lock()
	delete(SunnyProxy.VerifyUserList, user)
	SunnyProxy.VerifyUserLock.Unlock()
	return true
}

//export ScriptCall
func ScriptCall(i int, Request *C.char) uintptr {
	b := C.CString(JsCall2.JsCall(int32(i), C.GoString(Request)))
	return uintptr(unsafe.Pointer(b))
}

//export SetScript
func SetScript(Request *C.char) {
	JsCall2.JSinit(C.GoString(Request))
}

//export SetScriptLogCallAddress
func SetScriptLogCallAddress(i int) {
	JsCall2.ConsoleLogCall = i
}

//export GoCall
//适配火山PC CALL 火山直接CALL X64没有问题，X86环境下有问题，所以搞了这个命令
func GoCall(arrd, a1, a2, a3, a4, a5, a6, a7, a8, a9 int) int {
	if a1 == -1 {
		return SunnyProxy.Call(arrd)
	}
	if a2 == -1 {
		return SunnyProxy.Call(arrd, a1)
	}
	if a3 == -1 {
		return SunnyProxy.Call(arrd, a1, a2)
	}
	if a4 == -1 {
		return SunnyProxy.Call(arrd, a1, a2, a3)
	}
	if a5 == -1 {
		return SunnyProxy.Call(arrd, a1, a2, a3, a4)
	}
	if a6 == -1 {
		return SunnyProxy.Call(arrd, a1, a2, a3, a4, a5)
	}
	if a7 == -1 {
		return SunnyProxy.Call(arrd, a1, a2, a3, a4, a5, a6)
	}
	if a8 == -1 {
		return SunnyProxy.Call(arrd, a1, a2, a3, a4, a5, a6, a7)
	}
	if a9 == -1 {
		return SunnyProxy.Call(arrd, a1, a2, a3, a4, a5, a6, a7, a8)
	}
	return SunnyProxy.Call(arrd, a1, a2, a3, a4, a5, a6, a7, a8, a9)
}
