1package jid
2
3import (
4	"regexp"
5	"strings"
6
7	runewidth "github.com/mattn/go-runewidth"
8)
9
10type QueryInterface interface {
11	Get() []rune
12	Set(query []rune) []rune
13	Insert(query []rune, idx int) []rune
14	Add(query []rune) []rune
15	Delete(i int) []rune
16	Clear() []rune
17	Length() int
18	IndexOffset(int) int
19	GetChar(int) rune
20	GetKeywords() [][]rune
21	GetLastKeyword() []rune
22	PopKeyword() ([]rune, []rune)
23	StringGet() string
24	StringSet(query string) string
25	StringInsert(query string, idx int) string
26	StringAdd(query string) string
27	StringGetKeywords() []string
28	StringGetLastKeyword() string
29	StringPopKeyword() (string, []rune)
30}
31
32type Query struct {
33	query    *[]rune
34	complete *[]rune
35}
36
37func NewQuery(query []rune) *Query {
38	q := &Query{
39		query:    &[]rune{},
40		complete: &[]rune{},
41	}
42	_ = q.Set(query)
43	return q
44}
45func NewQueryWithString(query string) *Query {
46	return NewQuery([]rune(query))
47}
48
49func (q *Query) Get() []rune {
50	return *q.query
51}
52
53func (q *Query) GetChar(idx int) rune {
54	var r rune = 0
55	qq := q.Get()
56	if l := len(qq); l > idx && idx >= 0 {
57		r = qq[idx]
58	}
59	return r
60}
61
62func (q *Query) Length() int {
63	return len(q.Get())
64}
65
66func (q *Query) IndexOffset(i int) int {
67	o := 0
68	if l := q.Length(); i >= l {
69		o = runewidth.StringWidth(q.StringGet())
70	} else if i >= 0 && i < l {
71		o = runewidth.StringWidth(string(q.Get()[:i]))
72	}
73	return o
74}
75
76func (q *Query) Set(query []rune) []rune {
77	if validate(query) {
78		q.query = &query
79	}
80	return q.Get()
81}
82
83func (q *Query) Insert(query []rune, idx int) []rune {
84	qq := q.Get()
85	if idx == 0 {
86		qq = append(query, qq...)
87	} else if idx > 0 && len(qq) >= idx {
88		_q := make([]rune, idx+len(query)-1)
89		copy(_q, qq[:idx])
90		qq = append(append(_q, query...), qq[idx:]...)
91	}
92	return q.Set(qq)
93}
94
95func (q *Query) StringInsert(query string, idx int) string {
96	return string(q.Insert([]rune(query), idx))
97}
98
99func (q *Query) Add(query []rune) []rune {
100	return q.Set(append(q.Get(), query...))
101}
102
103func (q *Query) Delete(i int) []rune {
104	var d []rune
105	qq := q.Get()
106	lastIdx := len(qq)
107	if i < 0 {
108		if lastIdx+i >= 0 {
109			d = qq[lastIdx+i:]
110			qq = qq[0 : lastIdx+i]
111		} else {
112			d = qq
113			qq = qq[0:0]
114		}
115	} else if i == 0 {
116		d = []rune{}
117		qq = qq[1:]
118	} else if i > 0 && i < lastIdx {
119		d = []rune{qq[i]}
120		qq = append(qq[:i], qq[i+1:]...)
121	}
122	_ = q.Set(qq)
123	return d
124}
125
126func (q *Query) Clear() []rune {
127	return q.Set([]rune(""))
128}
129
130func (q *Query) GetKeywords() [][]rune {
131	qq := *q.query
132
133	if qq == nil || string(qq) == "" {
134		return [][]rune{}
135	}
136
137	splitQuery := []string{}
138	rr := []rune{}
139	enclosed := true
140	ql := len(*q.query)
141	for i := 0; i < ql; i++ {
142		r := qq[i]
143		if ii := i + 1; r == '\\' && ql > ii && qq[ii] == '"' {
144			enclosed = !enclosed
145			i++ // skip '"(double quortation)'
146			continue
147		}
148		if enclosed && r == '.' {
149			splitQuery = append(splitQuery, string(rr))
150			rr = []rune{}
151		} else {
152			rr = append(rr, r)
153		}
154	}
155	if rr != nil {
156		v := []string{string(rr)}
157		if !enclosed {
158			v = strings.Split(string(rr), ".")
159		}
160		splitQuery = append(splitQuery, v...)
161	}
162	lastIdx := len(splitQuery) - 1
163
164	keywords := [][]rune{}
165	for i, keyword := range splitQuery {
166		if keyword != "" || i == lastIdx {
167			re := regexp.MustCompile(`\[[0-9]*\]?`)
168			matchIndexes := re.FindAllStringIndex(keyword, -1)
169			if len(matchIndexes) < 1 {
170				keywords = append(keywords, []rune(keyword))
171			} else {
172				if matchIndexes[0][0] > 0 {
173					keywords = append(keywords, []rune(keyword[0:matchIndexes[0][0]]))
174				}
175				for _, matchIndex := range matchIndexes {
176					k := keyword[matchIndex[0]:matchIndex[1]]
177					keywords = append(keywords, []rune(k))
178				}
179			}
180		}
181	}
182	return keywords
183}
184
185func (q *Query) GetLastKeyword() []rune {
186	keywords := q.GetKeywords()
187	if l := len(keywords); l > 0 {
188		return keywords[l-1]
189	}
190	return []rune("")
191}
192
193func (q *Query) StringGetLastKeyword() string {
194	return string(q.GetLastKeyword())
195}
196
197func (q *Query) PopKeyword() ([]rune, []rune) {
198	keyword := q.GetLastKeyword()
199	nq := string(keyword)
200	qq := q.StringGet()
201
202	for _, r := range keyword {
203		if r == '.' {
204			nq = `\"` + string(keyword) + `\"`
205			break
206		}
207	}
208	re := regexp.MustCompile(`(\.)?(\\")?` + regexp.QuoteMeta(nq) + "$")
209
210	qq = re.ReplaceAllString(qq, "")
211
212	query := q.Set([]rune(qq))
213	return keyword, query
214}
215
216func (q *Query) StringGet() string {
217	return string(q.Get())
218}
219
220func (q *Query) StringSet(query string) string {
221	return string(q.Set([]rune(query)))
222}
223
224func (q *Query) StringAdd(query string) string {
225	return string(q.Add([]rune(query)))
226}
227
228func (q *Query) StringGetKeywords() []string {
229	var keywords []string
230	for _, keyword := range q.GetKeywords() {
231		keywords = append(keywords, string(keyword))
232	}
233	return keywords
234}
235
236func (q *Query) StringPopKeyword() (string, []rune) {
237	keyword, query := q.PopKeyword()
238	return string(keyword), query
239}
240
241func validate(r []rune) bool {
242	s := string(r)
243	if s == "" {
244		return true
245	}
246	if regexp.MustCompile(`^[^.]`).MatchString(s) {
247		return false
248	}
249	if regexp.MustCompile(`\.{2,}`).MatchString(s) {
250		return false
251	}
252	if regexp.MustCompile(`\[[0-9]*\][^\.\[]`).MatchString(s) {
253		return false
254	}
255	if regexp.MustCompile(`\[{2,}|\]{2,}`).MatchString(s) {
256		return false
257	}
258	if regexp.MustCompile(`.\.\[`).MatchString(s) {
259		return false
260	}
261	return true
262}
263