1//  Copieright (c) 2014 Couchbase, Inc.
2//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
3//  except in compliance with the License. You may obtain a copy of the License at
4//    http://www.apache.org/licenses/LICENSE-2.0
5//  Unless required by applicable law or agreed to in writing, software distributed under the
6//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
7//  either express or implied. See the License for the specific language governing permissions
8//  and limitations under the License.
9
10package value
11
12import (
13	"fmt"
14	json "github.com/couchbase/go_json"
15	"io"
16	"strings"
17	"unicode"
18
19	"github.com/couchbase/query/util"
20)
21
22/*
23stringValue is defined as type string.
24*/
25type stringValue string
26
27/*
28Define a value representing an empty string and
29assign it to EMPTY_STRING_VALUE.
30*/
31var EMPTY_STRING_VALUE Value = stringValue("")
32
33/*
34Use built-in JSON string marshalling, which handles special
35characters.
36*/
37func (this stringValue) String() string {
38	bytes, err := json.MarshalNoEscape(string(this))
39	if err != nil {
40		// We should not get here.
41		panic(fmt.Sprintf("Error marshaling Value %v: %v", this, err))
42	}
43	return string(bytes)
44}
45
46/*
47Use built-in JSON string marshalling, which handles special
48characters.
49*/
50func (this stringValue) MarshalJSON() ([]byte, error) {
51	return json.MarshalNoEscape(string(this))
52}
53
54func (this stringValue) WriteJSON(w io.Writer, prefix, indent string) error {
55	b, err := json.MarshalNoEscape(string(this))
56	if err != nil {
57		return err
58	}
59	_, err = w.Write(b)
60	return err
61}
62
63/*
64Type STRING.
65*/
66func (this stringValue) Type() Type {
67	return STRING
68}
69
70func (this stringValue) Actual() interface{} {
71	return string(this)
72}
73
74func (this stringValue) ActualForIndex() interface{} {
75	return string(this)
76}
77
78/*
79If other is type stringValue and is the same as the receiver
80return true.
81*/
82func (this stringValue) Equals(other Value) Value {
83	other = other.unwrap()
84	switch other := other.(type) {
85	case missingValue:
86		return other
87	case *nullValue:
88		return other
89	case stringValue:
90		if this == other {
91			return TRUE_VALUE
92		}
93	}
94
95	return FALSE_VALUE
96}
97
98func (this stringValue) EquivalentTo(other Value) bool {
99	other = other.unwrap()
100	switch other := other.(type) {
101	case stringValue:
102		return this == other
103	default:
104		return false
105	}
106}
107
108/*
109If other is type stringValue, compare with receiver,
110if its less than (string comparison) return -1, greater
111than return 1, otherwise return 0. For value of type
112parsedValue and annotated value call collate again with the
113value. The default behavior is to return the position wrt
114others type.
115*/
116func (this stringValue) Collate(other Value) int {
117	other = other.unwrap()
118	switch other := other.(type) {
119	case stringValue:
120		if this < other {
121			return -1
122		} else if this > other {
123			return 1
124		} else {
125			return 0
126		}
127	default:
128		return int(STRING - other.Type())
129	}
130}
131
132func (this stringValue) Compare(other Value) Value {
133	other = other.unwrap()
134	switch other := other.(type) {
135	case missingValue:
136		return other
137	case *nullValue:
138		return other
139	default:
140		return intValue(this.Collate(other))
141	}
142}
143
144/*
145If length of string greater than 0, its a valid string.
146Return true.
147*/
148func (this stringValue) Truth() bool {
149	return len(this) > 0
150}
151
152/*
153Return receiver.
154*/
155func (this stringValue) Copy() Value {
156	return this
157}
158
159/*
160Return receiver.
161*/
162func (this stringValue) CopyForUpdate() Value {
163	return this
164}
165
166/*
167Calls missingField.
168*/
169func (this stringValue) Field(field string) (Value, bool) {
170	return missingField(field), false
171}
172
173/*
174Not valid for string.
175*/
176func (this stringValue) SetField(field string, val interface{}) error {
177	return Unsettable(field)
178}
179
180/*
181Not valid for string.
182*/
183func (this stringValue) UnsetField(field string) error {
184	return Unsettable(field)
185}
186
187/*
188Calls missingIndex.
189*/
190func (this stringValue) Index(index int) (Value, bool) {
191	return missingIndex(index), false
192}
193
194/*
195Not valid for string.
196*/
197func (this stringValue) SetIndex(index int, val interface{}) error {
198	return Unsettable(index)
199}
200
201/*
202Returns NULL_VALUE
203*/
204func (this stringValue) Slice(start, end int) (Value, bool) {
205	return NULL_VALUE, false
206}
207
208/*
209Returns NULL_VALUE
210*/
211func (this stringValue) SliceTail(start int) (Value, bool) {
212	return NULL_VALUE, false
213}
214
215/*
216Returns the input buffer as is.
217*/
218func (this stringValue) Descendants(buffer []interface{}) []interface{} {
219	return buffer
220}
221
222/*
223No fields to list. Hence return nil.
224*/
225func (this stringValue) Fields() map[string]interface{} {
226	return nil
227}
228
229func (this stringValue) FieldNames(buffer []string) []string {
230	return nil
231}
232
233/*
234Returns the input buffer as is.
235*/
236func (this stringValue) DescendantPairs(buffer []util.IPair) []util.IPair {
237	return buffer
238}
239
240/*
241Append a low-valued byte to string.
242*/
243func (this stringValue) Successor() Value {
244	return stringValue(string(this) + " ")
245}
246
247func (this stringValue) Recycle() {
248}
249
250func (this stringValue) Tokens(set *Set, options Value) *Set {
251	tokens := _STRING_TOKENS_POOL.Get()
252	defer _STRING_TOKENS_POOL.Put(tokens)
253
254	this.tokens(tokens, options, "", nil)
255	for t, _ := range tokens {
256		set.Add(stringValue(t))
257	}
258
259	return set
260}
261
262func (this stringValue) ContainsToken(token, options Value) bool {
263	if token.Type() != STRING {
264		return false
265	}
266
267	tokens := _STRING_TOKENS_POOL.Get()
268	defer _STRING_TOKENS_POOL.Put(tokens)
269
270	str := token.Actual().(string)
271	return this.tokens(tokens, options, str, nil)
272}
273
274func (this stringValue) ContainsMatchingToken(matcher MatchFunc, options Value) bool {
275	tokens := _STRING_TOKENS_POOL.Get()
276	defer _STRING_TOKENS_POOL.Put(tokens)
277
278	return this.tokens(tokens, options, "", matcher)
279}
280
281func (this stringValue) unwrap() Value {
282	return this
283}
284
285func (this stringValue) tokens(set map[string]bool, options Value,
286	token string, matcher MatchFunc) bool {
287
288	// Set case folding function, if specified.
289	caseFunc := func(s string) string { return s }
290	if caseOption, ok := options.Field("case"); ok && caseOption.Type() == STRING {
291		caseStr := caseOption.Actual().(string)
292		switch strings.ToLower(caseStr) {
293		case "lower":
294			caseFunc = strings.ToLower
295		case "upper":
296			caseFunc = strings.ToUpper
297		}
298	}
299
300	var fields []string
301	split := true
302
303	// To split or not to split.
304	if splitOption, ok := options.Field("split"); ok &&
305		splitOption.Type() == BOOLEAN && !splitOption.Truth() {
306
307		split = false
308
309		// To trim or not to trim.
310		if trimOption, ok := options.Field("trim"); ok &&
311			trimOption.Type() == BOOLEAN && !trimOption.Truth() {
312			fields = []string{string(this)}
313		} else {
314			fields = []string{strings.TrimSpace(string(this))}
315		}
316	}
317
318	// Tokenize alphanumerics.
319	if split {
320		fields = strings.FieldsFunc(string(this),
321			func(c rune) bool {
322				return !unicode.IsLetter(c) && !unicode.IsNumber(c)
323			})
324	}
325
326	for _, field := range fields {
327		f := caseFunc(field)
328		if f == token || (matcher != nil && matcher(f)) {
329			return true
330		}
331
332		set[f] = true
333	}
334
335	if !split {
336		return false
337	}
338
339	// Return if not tokenizing specials.
340	if specialsOption, ok := options.Field("specials"); !(ok &&
341		specialsOption.Type() == BOOLEAN && specialsOption.Truth()) {
342		return false
343	}
344
345	// Tokenize specials. Specials can be used to preserve email
346	// addresses, URLs, hyphenated phone numbers, etc.
347
348	// First tokenize on whitespace and parentheses only.
349	fields = strings.FieldsFunc(string(this),
350		func(c rune) bool {
351			return unicode.IsSpace(c) ||
352				c == '(' || c == ')' ||
353				c == '[' || c == ']' ||
354				c == '{' || c == '}'
355		})
356
357	// Right trim special characters.
358	for _, field := range fields {
359		f := strings.TrimRightFunc(field,
360			func(c rune) bool {
361				return !unicode.IsLetter(c) && !unicode.IsNumber(c)
362			})
363
364		if f != "" {
365			f = caseFunc(f)
366			if f == token || (matcher != nil && matcher(f)) {
367				return true
368			}
369
370			set[f] = true
371		}
372	}
373
374	return false
375}
376
377var _STRING_TOKENS_POOL = util.NewStringBoolPool(64)
378