package odbcmql

import (
	"fmt"
	"sort"
	"strconv"
	"strings"
)

type MQLRequest struct {
	// params
	OriginQueryString                  string
	FilePath                           string
	Fromline, Toline, Fromchar, Tochar int
	// init values
	Key                 string
	StaticActionExprs   map[int]*Action
	StaticActions       *StaticActions
	FormatedQueryString string
	//
	WaitMQLRequest *MQLRequest // 等待上一语句完成
}

type MQLRequestInstance struct {
	*MQLRequest
	PreparedQueryString string
}

type MQLGroupRequest struct {
	mqrn int             // 一个文件中的mql计数
	mqrs [][]*MQLRequest // 并发MQLRequest序列, mqrs[0]为主序列
	curn int             // 当前序列
}

func NewMQLGroupRequest() (mqg *MQLGroupRequest) {
	mqg = &MQLGroupRequest{
		mqrn: 0,
		mqrs: [][]*MQLRequest{{}},
		curn: 0,
	}
	return
}

// 加入请求组，并初始化，提取动作信息
func (mqg *MQLGroupRequest) Append(mqr *MQLRequest) error {
	mqr, e := mqr.init(mqg.mqrn + 1)
	if e != nil {
		return e
	}
	if mqr != nil {
		if mqr.StaticActions.ForkName != nil {
			// fork新线程
			if len(mqg.mqrs[0]) > 0 {
				// 等待上一语句完成
				mqr.WaitMQLRequest = mqg.mqrs[0][len(mqg.mqrs[0])-1]
			} else {
				// 第一句就开始fork新线程
			}
			mqg.mqrs = append(mqg.mqrs, []*MQLRequest{})
			mqg.curn = len(mqg.mqrs) - 1
		}
		if mqr.StaticActions.ForkName == nil && mqr.StaticActions.WaitName != nil {
			// 主线程等待指定线程
			mqg.curn = 0
		}
		mqg.mqrs[mqg.curn] = append(mqg.mqrs[mqg.curn], mqr)
		mqg.mqrn++
	}
	return nil
}

func (mqr *MQLRequest) init(n int) (*MQLRequest, error) {
	mqr.OriginQueryString = strings.TrimSpace(mqr.OriginQueryString)
	if mqr.OriginQueryString == "" {
		return nil, nil
	}
	mqr.Key = fmt.Sprint(mqr.FilePath, ".", n, "[", mqr.Fromline, "-", mqr.Toline, "]")

	staticactionexprs := map[int]*Action{}

	str := mqr.OriginQueryString
	idxs := refmtvar.FindAllStringSubmatchIndex(str, -1)
	if len(idxs) > 0 {
		nstr := ""
		is := 0
		for _, idx := range idxs {
			if len(idx) == 6 {
				// 标记前内容
				ie := idx[0]
				nstr += str[is:ie]
				nstr += strings.Repeat("0", idx[1]-ie)
				is = idx[1]
			}
		}
		nstr += str[is:]
		str = nstr
	}
	actionexprs, e := getActionExprs(str, staticactionexprs)
	if e != nil {
		return nil, e
	}
	staticactions, e := ToStaticActions(actionexprs)
	if e != nil {
		return nil, e
	}
	if staticactions.Skip {
		return nil, nil
	}
	xmqlstr := ""
	if len(staticactionexprs) == 0 {
		xmqlstr = strings.ReplaceAll(mqr.OriginQueryString, "[", "[[]")
	} else {
		mqlrunes := []rune(mqr.OriginQueryString)
		istart := 0
		keys := []int{}
		for k := range staticactionexprs {
			keys = append(keys, k)
		}
		sort.Ints(keys)
		for _, k := range keys {
			sat := staticactionexprs[k]
			if sat.SourceText != "" {
				xmqlstr += strings.ReplaceAll(string(mqlrunes[istart:sat.SourceFromIndex]), "[", "[[]")
				xmqlstr += "[" + strconv.Itoa(k) + "]"
				istart = sat.SourceToIndex
			}
		}
		xmqlstr += strings.ReplaceAll(string(mqlrunes[istart:]), "[", "[[]")
	}
	mqr.StaticActionExprs = staticactionexprs
	mqr.StaticActions = staticactions
	mqr.FormatedQueryString = xmqlstr

	return mqr, nil
}
