package staros

import (
	"bytes"
	"errors"
	"io/ioutil"
	"strconv"
	"strings"
)

func splitBy(data, sep string) map[string]string {
	res := make(map[string]string)
	lists := strings.Split(data, "\n")
	for _, v := range lists {
		list := strings.SplitN(v, sep, 2)
		if len(list) != 2 {
			continue
		}
		res[strings.TrimSpace(list[0])] = strings.TrimSpace(list[1])
	}
	return res
}

// 横向替换ASCII<9>
func ReplaceByte9(data string) string {
	return string(bytes.ReplaceAll([]byte(data), []byte{9}, []byte(" ")))
}

func splitBySpace(data string) []string {
	data = string(bytes.ReplaceAll([]byte(data), []byte{9}, []byte(" ")))
	nomorespace := func(data string) string {
		return strings.ReplaceAll(data, "  ", " ")
	}
	for strings.Index(data, "  ") >= 0 {
		data = nomorespace(data)
	}
	return strings.Split(data, " ")
}

func readAsString(path string) (string, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return "", err
	}
	return string(data), nil
}

func remainOne(data, old, new string) string {
	data = strings.TrimSpace(data)
	if !strings.Contains(data, old) {
		return data
	}
	data = strings.ReplaceAll(data, old, new)
	return remainOne(data, old, new)
}

func parseHexIpPort(str string) (string, int, error) {
	str = strings.TrimSpace(str)
	if len(str) != 13 && len(str) != 37 {
		return "", 0, errors.New("Not a valid ip:port addr:" + str)
	}
	ipPort := strings.Split(str, ":")
	if len(ipPort) != 2 {
		return "", 0, errors.New("Not a valid ip:port addr:" + str)
	}
	if len(ipPort[0]) == 8 {
		ip, err := parseHexIPv4(ipPort[0])
		if err != nil {
			return "", 0, err
		}
		port, err := parseHexPort(ipPort[1])
		return ip, port, err
	}

	if len(ipPort[0]) == 32 {
		ip, err := parseHexIPv6(ipPort[0])
		if err != nil {
			return "", 0, err
		}
		port, err := parseHexPort(ipPort[1])
		return ip, port, err
	}
	return "", 0, errors.New("Invalid ip address:" + str)
}

func parseHexPort(str string) (int, error) {
	tmpUint32, err := strconv.ParseUint(str, 16, 32)
	return int(tmpUint32), err
}

func parseHexIPv4(str string) (string, error) {
	var result string
	if len(str) != 8 {
		return "", errors.New("Not a vaild ipv4:" + str)
	}
	tmpUint64, err := strconv.ParseUint(str, 16, 32)
	if err != nil {
		return "", err
	}
	numicIp := uint32(tmpUint64)
	for i := 0; i < 4; i++ {
		result += strconv.FormatUint(uint64(uint8(numicIp>>(8*uint8(i)))), 10) + "."
	}
	return result[0 : len(result)-1], nil
}

func parseHexIPv6(str string) (string, error) {
	var result string
	if len(str) != 32 {
		return "", errors.New("Not a vaild ipv6:" + str)
	}
	for i := 0; i < 4; i++ {
		part := str[i*8 : (i+1)*8]
		tmpUint64, err := strconv.ParseUint(part, 16, 32)
		if err != nil {
			return "", err
		}
		tmpUint32 := uint32(tmpUint64)
		//07C2022A
		for i := 0; i < 4; i++ {
			tmp := strconv.FormatUint(uint64(uint8(tmpUint32>>uint8(8*i))), 16)
			if len(tmp) == 1 {
				tmp = "0" + tmp
			}
			result += tmp
			if (i+1)%2 == 0 {
				result += ":"
			}
		}
	}
	ipv6 := result[0 : len(result)-1]
	ipv6List := strings.Split(ipv6, ":")
	prepareZero := false
	alreadyZero := false
	for k, v := range ipv6List {
		if v == "0000" && !alreadyZero {
			ipv6List[k] = ""
			prepareZero = true
			continue
		}
		if v != "0000" && prepareZero {
			alreadyZero = true
		}
		var nonZero = 0
		for i := 0; i < 4; i++ {
			sig := v[i : i+1]
			if sig != "0" {
				nonZero = i
				break
			}
		}
		ipv6List[k] = v[nonZero:4]
	}
	ipv6 = strings.TrimSuffix(remainOne(strings.Join(ipv6List, ":"), ":::", "::"), "::")
	if ipv6 == "" {
		ipv6 = "::0"
	}
	return ipv6, nil
}
