package jccommon

import (
	"q5"
	"fmt"
	"strings"
	"errors"
)

/*
  max(uint64): 18446744073709551615 = len(20)
  max(uint256): 115792089237316195423570985008687907853269984665640564039457584007913129639935 = len(78)
  max(int32): 2147483648 = len(10)
  len(tokenid) = 16
  transHead: funcId(2)|time(9)|seqId(7) = len(18)
 */

type TransId struct {
	funcId int32
	time int32
	seqId int32
	params [3]int64
}

func (this *TransId) Init(funcId int32, time int32, seqId int32, params [3]int64) {
	this.funcId = funcId
	this.time = time - TRANS_ID_EPOCH
	this.seqId = seqId
	this.params = params
}

func (this *TransId) ToString() (string, error) {
	if !this.IsValid() {
		return "", errors.New("isvalid transId")
	}
	idStr := fmt.Sprintf("%2d%9d%7d%20d%20d%20d",
		this.funcId,
		this.time,
		this.seqId,
		this.params[0],
		this.params[1],
		this.params[2])
	idStr = strings.TrimLeft(idStr, " ")
	idStr = strings.ReplaceAll(idStr, " ", "0")
	if !IsValidTransId(idStr) {
		return "", errors.New("transId len error")
	}
	return idStr, nil
}

func (this *TransId) ParseString(idStr string) error {
	if !IsValidTransId(idStr) {
		return errors.New("transId len error")
	}
	eleLens := []int{2,9,7,20,20,20}
	if len(idStr) == TRANS_ID_MIN_LEN {
		eleLens[0] = 1
	}
	offset := 0
	for index, eleLen := range eleLens {
		tmpStr := idStr[offset: offset + eleLen]
		offset += eleLen
		switch index {
		case 0:
			{
				this.funcId = q5.ToInt32(tmpStr)
			}
		case 1:
			{
				this.time = q5.ToInt32(tmpStr)
			}
		case 2:
			{
				this.seqId = q5.ToInt32(tmpStr)
			}
		default:
			{
				this.params[index - 3] = q5.ToInt64(tmpStr)
			}
			break;
		}
	}
	return nil
}

func (this *TransId) IsValid() bool {
	if this.funcId < 0 || this.funcId > TRANS_ID_MAX_FUNC_ID {
		return false
	}
	if this.time < 0 || this.time > TRANS_ID_MAX_TIME {
		return false
	}
	if this.seqId < 0 || this.seqId > TRANS_ID_MAX_SEQ_ID {
		return false
	}
	for _, val := range this.params {
		if val < 0 {
			return false
		}
	}
	return true
}

func NewTransId() *TransId {
	return new(TransId)
}

func IsValidTransId(idStr string) bool {
	return q5.IsPureNumber(idStr) && len(idStr) >= TRANS_ID_MIN_LEN && len(idStr) <= TRANS_ID_MAX_LEN
}
