Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.expressionevaluator / org.gvsig.expressionevaluator.lib / org.gvsig.expressionevaluator.lib.api / src / main / java / org / gvsig / expressionevaluator / spi / AbstractFunction.java @ 46505

History | View | Annotate | Download (30.7 KB)

1
package org.gvsig.expressionevaluator.spi;
2

    
3
import java.io.File;
4
import java.math.BigDecimal;
5
import java.net.MalformedURLException;
6
import java.net.URI;
7
import java.net.URISyntaxException;
8
import java.net.URL;
9
import java.nio.charset.StandardCharsets;
10
import java.time.LocalDate;
11
import java.time.LocalDateTime;
12
import java.time.ZoneId;
13
import java.time.ZoneOffset;
14
import java.time.temporal.TemporalAccessor;
15
import java.util.ArrayList;
16
import java.util.Date;
17
import java.util.List;
18
import java.util.Locale;
19
import java.util.Objects;
20
import java.util.regex.Matcher;
21
import java.util.regex.Pattern;
22
import javax.json.JsonArray;
23
import javax.json.JsonObject;
24
import javax.json.JsonStructure;
25
import org.apache.commons.io.FilenameUtils;
26
import org.apache.commons.io.IOUtils;
27
import org.apache.commons.lang3.BooleanUtils;
28
import org.apache.commons.lang3.Range;
29
import org.apache.commons.lang3.StringUtils;
30
import org.apache.commons.math.exception.OutOfRangeException;
31
import org.apache.commons.math.util.MathUtils;
32
import org.gvsig.expressionevaluator.Code;
33
import org.gvsig.expressionevaluator.Codes;
34
import org.gvsig.expressionevaluator.ExpressionBuilder;
35
import org.gvsig.expressionevaluator.ExpressionRuntimeException;
36
import org.gvsig.expressionevaluator.Formatter;
37
import org.gvsig.expressionevaluator.Function;
38
import org.gvsig.expressionevaluator.I18N;
39
import org.gvsig.expressionevaluator.Interpreter;
40
import org.gvsig.tools.ToolsLocator;
41
import org.gvsig.tools.dataTypes.DataTypeUtils;
42
import org.gvsig.tools.i18n.I18nManager;
43
import org.gvsig.tools.util.GetItem;
44
import org.gvsig.tools.util.GetItem64;
45
import org.gvsig.tools.util.GetItemWithSize64;
46
import org.gvsig.tools.util.Size;
47
import org.gvsig.tools.util.Size64;
48
//import org.gvsig.fmap.geom.Geometry;
49
//import org.gvsig.fmap.geom.primitive.Point;
50
import org.json.JSONArray;
51
import org.json.JSONObject;
52

    
53
@SuppressWarnings("UseSpecificCatch")
54
public abstract class AbstractFunction implements Function {
55
 
56
    private final String name;
57
    private String group;
58
    private Range argc;
59
    private String description;
60
    private String[] descriptionArgs;
61
    private List<String> alias;
62
    private String template;
63
    private String returnType;
64
    private boolean sqlCompatible;
65

    
66
    protected AbstractFunction(String group, String name, Range argc, String description, String template, String[] descriptionArgs, String returnType, boolean sqlCompatible) {
67
        this.name = name;
68
        this.group = group;
69
        this.argc = argc;
70
        this.description = description;
71
        this.template = template;
72
        this.descriptionArgs = descriptionArgs;
73
        this.returnType = returnType;
74
        this.sqlCompatible = sqlCompatible;
75
        load_from_resource();
76
    }
77
    protected AbstractFunction(String group, String name, Range argc, String description, String template, String[] descriptionArgs, String returnType) {
78
        this(group, name, argc, description, template, descriptionArgs, returnType, false);
79
    }
80
    
81
    protected AbstractFunction(String group, String name, Range argc, String description, String template, String[] descriptionArgs) {
82
        this(group, name, argc, description, template, null, null);
83
    }
84

    
85
    protected AbstractFunction(String group, String name, Range argc, String description, String template) {
86
        this(group, name, argc, description, template, null, null);
87
    }
88

    
89
    protected AbstractFunction(String group, String name, Range argc) {
90
        this(group, name, argc, null, null, null, null);
91
    }
92

    
93
    @Override
94
    public String name() {
95
        return this.name;
96
    }
97

    
98
    @Override
99
    public String returnType() {
100
        return this.returnType;
101
    }
102

    
103
    @Override
104
    public String group() {
105
        return this.group;
106
    }
107

    
108
    @Override
109
    public Range argc() {
110
        return argc;
111
    }
112

    
113
    @Override
114
    public String description() {
115
        if( StringUtils.equalsIgnoreCase(System.getProperty("ExpressionEvaluatorReloadFunctionResources"), "true")) {
116
            load_from_resource();
117
        }
118
        return description;
119
    }
120

    
121
    @Override
122
    public String[] descriptionArgs() {
123
        return descriptionArgs;
124
    }
125

    
126
    @Override
127
    public String getFullDescription() {
128
        I18nManager i18n = ToolsLocator.getI18nManager();
129

    
130
        StringBuilder html = new StringBuilder();
131
        html.append("<html>\n");
132

    
133
        // Lo primero llamamos a description() para forzar la recarga de los
134
        // recursos si fuese necesaria.
135
        String functionDescription = this.description();
136

    
137
        html.append("<b>").append(i18n.getTranslation("_Function")).append("</b> ").append(this.name()).append("<br>\n<br>\n");
138
        List<String> aliases = this.aliases();
139
        if( aliases!=null && !aliases.isEmpty() ) {
140
            html.append("<b>").append(i18n.getTranslation("_Aliases")).append(":</b> ").append("<ul>\n");
141
            for (String theAlias : aliases) {
142
                html.append("<li>").append(theAlias).append("</li>\n");
143
            }
144
            html.append("</ul>\n");
145
        }
146
        html.append("<b>").append(i18n.getTranslation("_Return")).append("</b> ");
147
        html.append(StringUtils.isEmpty(this.returnType()) ? "Objec" : this.returnType());
148
        html.append("<br>\n");
149
        html.append("<b>").append(i18n.getTranslation("_Template")).append("</b> ");
150
        html.append(StringUtils.isEmpty(this.template()) ? this.name() + "()" : this.template());
151
        html.append("<br>\n");
152

    
153
        String[] args = this.descriptionArgs();
154
        if (args != null) {
155
            html.append("<b>").append(i18n.getTranslation("_Arguments")).append(":</b> ").append("<ul>\n");
156
            for (String arg : args) {
157
                html.append("<li>").append(arg).append("</li>\n");
158
            }
159
            html.append("</ul>\n");
160
            html.append("<br>\n");
161
        }
162
        if( !StringUtils.isBlank(functionDescription) ) {
163
            html.append("<b>").append(i18n.getTranslation("_Description")).append("</b><br>\n");
164
            html.append(functionDescription.replace("\n", "<br>")).append("<br>\n");
165
        }            
166

    
167
        html.append("</html>\n");
168
        return html.toString();
169
    }
170

    
171
    @Override
172
    public void addAlias(String name) {
173
        if( StringUtils.isBlank(name) ) {
174
            return;
175
        }
176
        if( this.alias == null ) {
177
            this.alias = new ArrayList<>();
178
        }
179
        if( this.alias.contains(name) ) {
180
            return;
181
        }
182
        this.alias.add(name);
183
    }
184

    
185
    @Override
186
    public List<String> aliases() {
187
        return this.alias;
188
    }
189

    
190
    @Override
191
    public String template() {
192
        return this.template;
193
    }
194

    
195
    @Override
196
    public boolean isOperator() {
197
        return false;
198
    }
199

    
200
    @Override
201
    public boolean isHidden() {
202
      return false;
203
    }
204
    
205
    @Override
206
    public boolean useArgumentsInsteadObjects() {
207
        return false;
208
    }
209

    
210
    @Override
211
    public boolean isSQLCompatible() {
212
        return sqlCompatible;
213
    }
214

    
215
    @Override
216
    public boolean allowConstantFolding() {
217
        return false;
218
    }
219

    
220
    @Override
221
    public Object call(Interpreter interpreter, Codes args) throws Exception {
222
        return null;
223
    }
224
    
225
    protected int getInt(Object args[], int n) {
226
        if( args.length < n  ) {
227
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
228
        }
229
        return getInt(args[n],n);
230
    }
231

    
232
    protected int getInt(Object value, int n) {
233
        if( value == null ) {
234
            throw new IllegalArgumentException(I18N.Illegal_null_value_for_argument_XargnX_of_XIdentifierX_function(name(), n));
235
        }
236
        if( !(value instanceof Number) ) {
237
            String type = value.getClass().getCanonicalName();
238
            throw new IllegalArgumentException(
239
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), n) + " " +
240
                    I18N.Expected_XexpectedX_and_found_XfoundX("Number",type)
241
            );
242
        }
243
        return ((Number)value).intValue();
244
    }
245

    
246
    protected long getLong(Object args[], int n) {
247
        if( args.length < n  ) {
248
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
249
        }
250
        return getLong(args[n],n);
251
    }
252

    
253
    protected long getLong(Object value, int n) {
254
        if( value == null ) {
255
            throw new IllegalArgumentException(I18N.Illegal_null_value_for_argument_XargnX_of_XIdentifierX_function(name(), n));
256
        }
257
        if( !(value instanceof Number) ) {
258
            String type = value.getClass().getCanonicalName();
259
            throw new IllegalArgumentException(
260
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), n) + " " +
261
                    I18N.Expected_XexpectedX_and_found_XfoundX("Number",type)
262
            );
263
        }
264
        return ((Number)value).longValue();
265
    }
266

    
267
    protected double getDouble(Object args[], int n) {
268
        if( args.length < n  ) {
269
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
270
        }
271
        return getDouble(args[n],n);
272
    }
273

    
274
    protected double getDouble(Object value, int arg) {
275
        if( value == null ) {
276
            throw new IllegalArgumentException(I18N.Illegal_null_value_for_argument_XargnX_of_XIdentifierX_function(name(), arg));
277
        }
278
        if( !(value instanceof Number) ) {
279
            String type = value.getClass().getCanonicalName();
280
            throw new IllegalArgumentException(
281
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), arg) + " " +
282
                    I18N.Expected_XexpectedX_and_found_XfoundX("Number",type)
283
            );
284
        }
285
        return ((Number)value).doubleValue();
286
    }
287
    
288
    protected BigDecimal getBigDecimal(Object value, int arg) {
289
        if( value == null ) {
290
            throw new IllegalArgumentException(I18N.Illegal_null_value_for_argument_XargnX_of_XIdentifierX_function(name(), arg));
291
        }
292
        if( !(value instanceof Number) ) {
293
            String type = value.getClass().getCanonicalName();
294
            throw new IllegalArgumentException(
295
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), arg) + " " +
296
                    I18N.Expected_XexpectedX_and_found_XfoundX("Number",type)
297
            );
298
        }
299
        if(value instanceof Long || value instanceof Integer || value instanceof Short || value instanceof Byte) {
300
            return BigDecimal.valueOf(((Number) value).longValue());
301
        }
302
        return BigDecimal.valueOf(((Number) value).doubleValue());
303
    }
304
    
305
    protected float getFloat(Object args[], int n) {
306
        if( args.length < n  ) {
307
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
308
        }
309
        return getFloat(args[n],n);
310
    }
311

    
312
    protected float getFloat(Object value, int arg) {
313
        if( value == null ) {
314
            throw new IllegalArgumentException(I18N.Illegal_null_value_for_argument_XargnX_of_XIdentifierX_function(name(), arg));
315
        }
316
        if( !(value instanceof Number) ) {
317
            String type = value.getClass().getCanonicalName();
318
            throw new IllegalArgumentException(
319
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), arg) + " " +
320
                    I18N.Expected_XexpectedX_and_found_XfoundX("Number",type)
321
            );
322
        }
323
        return ((Number)value).floatValue();
324
    }
325
    
326
    protected String getStr(Object args[], int n) {
327
        if( args.length < n  ) {
328
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
329
        }
330
        return getStr(args[n],n);
331
    }
332
    
333
    protected String getStr(Object value, int n) {
334
        return Objects.toString(value, "");
335
    }
336
    
337
    protected File getFile(Object args[], int n) {
338
        if( args.length < n  ) {
339
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
340
        }
341
        return getFile(args[n],n);
342
    }
343
    
344
    protected File getFile(Object value, int n) {
345
        if( value == null ) {
346
            return null;
347
        }
348
        if( value instanceof File ) {
349
            return (File)value;
350
        }
351
        if( value instanceof URL ) {
352
            try {
353
                return new File(((URL)value).toURI());
354
            } catch (URISyntaxException ex) {
355
                return null;
356
            }
357
        }
358
        if( value instanceof URI ) {
359
            return new File(((URI)value));
360
        }
361
        String s = Objects.toString(value, null);
362
        if( s == null ) {
363
            return null;
364
        }
365
        File f = new File(s);
366
        return f;
367
    }
368

    
369
    protected boolean isNull(Object args[], int n) {
370
        return getObject(args, n)==null;
371
    }
372
    
373
    protected Object getObject(Object args[], int n) {
374
        if( args.length < n  ) {
375
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
376
        }
377
        return args[n];
378
    }
379
    
380
    protected JsonObject getJsonObject(Object args[], int n) {
381
        if( args.length < n  ) {
382
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
383
        }
384
        return getJsonObject(args[n],n);
385
    }
386

    
387
    protected JsonObject getJsonObject(Object value, int n) {
388
        if( value == null ) {
389
            throw new IllegalArgumentException(I18N.Illegal_null_value_for_argument_XargnX_of_XIdentifierX_function(name(), n));
390
        }
391
        if( !(value instanceof JSONObject) ) {
392
            try {
393
                value = JsonUtils.toJsonObject(value);
394
            } catch(Throwable th) {
395
                String type = value.getClass().getCanonicalName();
396
                throw new IllegalArgumentException(
397
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), n) + " " +
398
                    I18N.Expected_XexpectedX_and_found_XfoundX("JsonObject",type),
399
                    th
400
                );
401
            }
402
        }
403
        return (JsonObject) value;
404
    }
405

    
406
    protected JsonArray getJsonArray(Object args[], int n) {
407
        if( args.length < n  ) {
408
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
409
        }
410
        return getJsonArray(args[n],n);
411
    }
412

    
413
    protected JsonArray getJsonArray(Object value, int n) {
414
        if( value == null ) {
415
            throw new IllegalArgumentException(I18N.Illegal_null_value_for_argument_XargnX_of_XIdentifierX_function(name(), n));
416
        }
417
        if( !(value instanceof JsonArray) ) {
418
            try {
419
                value = JsonUtils.toJsonArray(value);
420
            } catch(Throwable th) {
421
                String type = value.getClass().getCanonicalName();
422
                throw new IllegalArgumentException(
423
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), n) + " " +
424
                    I18N.Expected_XexpectedX_and_found_XfoundX("JsonObject",type),
425
                    th
426
                );
427
            }
428
        }
429
        return (JsonArray) value;
430
    }
431

    
432
    protected JsonStructure getJsonStructure(Object args[], int n) {
433
        if( args.length < n  ) {
434
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
435
        }
436
        return getJsonStructure(args[n],n);
437
    }
438

    
439
    protected JsonStructure getJsonStructure(Object value, int n) {
440
        if( value == null ) {
441
            throw new IllegalArgumentException(I18N.Illegal_null_value_for_argument_XargnX_of_XIdentifierX_function(name(), n));
442
        }
443
        if( !(value instanceof JsonStructure) ) {
444
            try {
445
                value = JsonUtils.toJson(value);
446
            } catch(Throwable th) {
447
                String type = value.getClass().getCanonicalName();
448
                throw new IllegalArgumentException(
449
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), n) + " " +
450
                    I18N.Expected_XexpectedX_and_found_XfoundX("JsonObject",type),
451
                    th
452
                );
453
            }
454
        }
455
        return (JsonStructure) value;
456
    }
457

    
458
    protected Object getObject(Interpreter interpreter, Codes args, int n) {
459
        if( args.size() < n  ) {
460
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.size(), n));
461
        }
462
        Code arg = args.get(n);
463
        if( arg==null ) {
464
            return null;
465
        }
466
        Object value = interpreter.run(arg);
467
        return value;
468
    }
469
    
470
    protected Comparable getComparable(Object[] args, int n) {
471
        if( args.length < n  ) {
472
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
473
        }
474
        return getComparable(args[n],n);
475
    }
476
    
477
    protected Comparable getComparable(Object value, int n) {
478
        if( value == null ) {
479
            return null;
480
        }
481
        if( !(value instanceof Comparable) ) {
482
            String type = value.getClass().getCanonicalName();
483
            throw new IllegalArgumentException(
484
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), n) + " " +
485
                    I18N.Expected_XexpectedX_and_found_XfoundX("Comparable",type)
486
            );
487
        }
488
        return (Comparable)value;
489
    }
490

    
491
    protected Comparable getDate(Object[] args, int n) {
492
        if( args.length < n  ) {
493
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
494
        }
495
        return getDate(args[n],n);
496
    }
497
    
498
    protected Date getDate(Object value, int n) {
499
        if( value == null ) {
500
            return null;
501
        }
502
        if( !(value instanceof Date) ) {
503
            String type = value.getClass().getCanonicalName();
504
            throw new IllegalArgumentException(
505
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), n) + " " +
506
                    I18N.Expected_XexpectedX_and_found_XfoundX("Date",type)
507
            );
508
        }
509
        return (Date)value;
510
    }
511
    
512
    protected LocalDateTime getLocalDateTime(Object[] args, int n) {
513
        if( args.length < n  ) {
514
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
515
        }
516
        return getLocalDateTime(args[n],n);
517
    }
518
    
519
    protected LocalDateTime getLocalDateTime(Object value, int n) {
520
        if( value == null ) {
521
            return null;
522
        }
523
        if( value instanceof java.sql.Date) {
524
            java.sql.Date sqlDate = (java.sql.Date) value;
525
            // TODO
526
            //sqlDate.getTime() construir date
527
            LocalDate date = sqlDate.toLocalDate();
528
            return date.atStartOfDay(ZoneOffset.UTC).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
529
        } else if( value instanceof Date ) {
530
            Date date = ((Date)value); //dataTypeUtils
531
            return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
532
        }
533
        if( value instanceof LocalDateTime ) {
534
            return (LocalDateTime) value;
535
        }
536
        if( value instanceof TemporalAccessor ) {
537
            return LocalDateTime.from(((TemporalAccessor)value));
538
        }
539
        String type = value.getClass().getCanonicalName();
540
        throw new IllegalArgumentException(
541
                I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), n) + " " +
542
                I18N.Expected_XexpectedX_and_found_XfoundX("Temporal/Date",type)
543
        );
544
    }
545

    
546
    public URL getURL(Object[] args, int index) throws MalformedURLException {
547
        Object obj = getObject(args, index);
548
        if( obj == null ) {
549
            return null;
550
        }  
551
        URL url;
552
        if( obj instanceof URL ) {
553
            url = (URL) obj;        } else if( obj instanceof CharSequence ) {
554
            url = new URL(((CharSequence)obj).toString());
555
        } else if( obj instanceof File ) {
556
            url = ((File)obj).toURI().toURL();
557
        } else if( obj instanceof URI ) {
558
            url = ((URI)obj).toURL();
559
        } else {
560
            throw new ExpressionRuntimeException("The "+this.name()+" function require a File, URI or a String and a received a '"+obj.getClass().getSimpleName()+"'.");
561
        }  
562
        return url;
563
    }
564
    
565
    protected boolean getBoolean(Object args[], int n, Double accuracy) {
566
        if( args.length < n  ) {
567
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
568
        }
569
        return getBoolean(args[n], n, accuracy);
570
    }
571

    
572
    protected boolean getBoolean(Object value, int n) {
573
        return getBoolean(value, n, MathUtils.EPSILON);
574
    }
575

    
576
    protected boolean getBoolean(Object value, int n, Double accuracy) {
577
        return toBoolean(value, accuracy);
578
    }
579

    
580
    protected boolean getBoolean(Interpreter interpreter, Codes args, int n) {
581
        Object value = getObject(interpreter, args, n);
582
        return toBoolean(value, interpreter.getAccuracy());
583
    }
584

    
585
    protected boolean toBoolean(Object value, Double accuracy) {
586
        if( value == null ) {
587
            return false;
588
        }
589
        if( value instanceof Boolean ) {
590
            return (Boolean)value;
591
        }        
592
        if( value instanceof Number ) {
593
            return MathUtils.compareTo(
594
                ((Number) value).doubleValue(), 
595
                0,
596
                accuracy==null? MathUtils.EPSILON:accuracy
597
            ) == 0;
598
        }
599
        return BooleanUtils.toBoolean(value.toString());
600
    } 
601
    
602
    protected GetItemWithSize64 getList(Object[] args, int index)  {
603
        Object value = getObject(args, index);
604
        if( value == null ) {
605
            return null;
606
        }  
607
        GetItemWithSize64 list = null;
608
        if (value instanceof List) {
609
            list = new GetItemWithSize64<Object>() {
610
                @Override
611
                public long size64() {
612
                    return ((List) value).size();
613
                }
614

    
615
                @Override
616
                public Object get64(long index) {
617
                    return ((List) value).get((int) index);
618
                }
619
            };
620
        } else if (value instanceof Object[]) {
621
            list = new GetItemWithSize64<Object>() {
622
                @Override
623
                public long size64() {
624
                    return ((Object[]) value).length;
625
                }
626

    
627
                @Override
628
                public Object get64(long index) {
629
                    return ((Object[]) value)[(int) index];
630
                }
631
            };
632
        } else if (value instanceof GetItemWithSize64 ) {
633
            list = (GetItemWithSize64) value;
634
            
635
        } else if (value instanceof GetItem && value instanceof Size) {
636
            list = new GetItemWithSize64<Object>() {
637
                @Override
638
                public long size64() {
639
                    return ((Size) value).size();
640
                }
641

    
642
                @Override
643
                public Object get64(long index) {
644
                    return ((GetItem) value).get((int) index);
645
                }
646
            };
647
        } else if (value instanceof GetItem64 && value instanceof Size64) {
648
            list = new GetItemWithSize64<Object>() {
649
                @Override
650
                public long size64() {
651
                    return ((Size64) value).size64();
652
                }
653

    
654
                @Override
655
                public Object get64(long index) {
656
                    return ((GetItem64) value).get64((int) index);
657
                }
658
            };
659
        }
660
        return list;
661
    }
662
    
663

    
664
    private void load_from_resource() {
665
        String lang = Locale.getDefault().getLanguage();
666
        URL url = this.getClass().getResource("/org/gvsig/expressionevaluator/functions/"+lang+"/"+this.name()+".json");
667
        if( url == null ) {
668
            url = this.getClass().getResource("/org/gvsig/expressionevaluator/functions/en/"+this.name()+".json");
669
            if( url == null ) {
670
                return;
671
            }
672
        }
673
        JSONObject json;
674
        try {
675
            json = new JSONObject(IOUtils.toString(url, StandardCharsets.UTF_8));
676
        } catch (Exception ex) {
677
            return;
678
        }
679
        
680
        if( json.has("group") ) {
681
            this.group = json.getString("group");
682
        }
683
        if( json.has("description") ) {
684
            Object x = json.get("description");
685
            if( x instanceof String ) {
686
                this.description = (String) x;
687
            } else if( x instanceof JSONArray ) {
688
                StringBuilder builder = new StringBuilder();
689
                for (int i = 0; i < ((JSONArray)x).length(); i++) {
690
                    if( i>0 ) {
691
                        builder.append(" ");
692
                    }
693
                    builder.append(((JSONArray)x).getString(i));
694
                }
695
                this.description = builder.toString();
696
            } else {
697
                this.description = Objects.toString(x, null);
698
            }
699
            this.description = process_includes(url, this.description);
700
            this.description = StringUtils.replace(
701
                    this.description, 
702
                    "@@@", 
703
                    url.toString()
704
            );
705
        }
706
        if( json.has("template") ) {
707
            this.template = json.getString("template");
708
        }
709
        if( json.has("returnType") ) {
710
            this.returnType = json.getString("returnType");
711
        }
712
        if( json.has("sqlCompatible") ) {
713
            this.sqlCompatible = json.getBoolean("sqlCompatible");
714
        }
715
        if( json.has("args") ) {
716
            JSONArray x = json.getJSONArray("args");
717
            String[] args = new String[x.length()];
718
            for (int i = 0; i < x.length(); i++) {
719
                args[i] = x.getString(i);
720
            }
721
            this.descriptionArgs = args;
722
        }
723
        if( json.has("alias") ) {
724
            JSONArray x = json.getJSONArray("alias");
725
            for (int i = 0; i < x.length(); i++) {
726
                this.addAlias(x.getString(i));
727
            }
728
        }
729
    }
730
    
731
    private String process_includes(URL pathname, String text) {
732
        Pattern p1 = Pattern.compile("[<][%]include (?<fname>[a-zA-Z0-9_$.]+)[%][>]", Pattern.DOTALL);
733
        while(true) {
734
            Matcher m = p1.matcher(text);
735
            if( m==null || !m.find()) {
736
                return text;
737
            }
738
            String path = FilenameUtils.getPathNoEndSeparator(pathname.toString());
739
            String fname = m.group("fname");
740
            URL url;
741
            String replacement;
742
            try {
743
                url = new URL(path+"/"+fname);
744
                replacement = IOUtils.toString(url);
745
//                text = m.replaceAll(replacement);
746
                StringBuilder builder = new StringBuilder(text.length()+replacement.length());
747
                builder.append(text.substring(0, m.start()));
748
                builder.append(replacement);
749
                builder.append(text.substring(m.end()));
750
                text = builder.toString();
751
            } catch (Exception ex) {
752
                return text;
753
            }
754
        }
755
    }
756
    
757
    protected static final int TYPE_INT =        0b000000001;
758
    protected static final int TYPE_LONG =       0b000000010;
759
    protected static final int TYPE_FLOAT =      0b000000100;
760
    protected static final int TYPE_DOUBLE =     0b000001000;
761
    protected static final int TYPE_BOOLEAN =    0b000010000;
762
    protected static final int TYPE_STRING =     0b000100000;
763
    protected static final int TYPE_DATE =       0b001000000;
764
    protected static final int TYPE_NULL =       0b010000000;
765
    protected static final int TYPE_BIGDECIMAL = 0b100000000;
766
    
767
    protected int getType(Object op1, Object op2) {
768
        int r = 0;
769
        if( op1 == null ) {
770
            r |= TYPE_NULL;
771
        } else if( op1 instanceof BigDecimal ) {
772
            r |= TYPE_BIGDECIMAL;
773
        } else if( op1 instanceof Double ) {
774
            r |= TYPE_DOUBLE;
775
        } else if( op1 instanceof Float ) {
776
            r |= TYPE_FLOAT;
777
        } else if( op1 instanceof Long ) {
778
            r |= TYPE_LONG;
779
        } else if( op1 instanceof Integer ) {
780
            r |= TYPE_INT;
781
        } else if( op1 instanceof Boolean ) {
782
            r |= TYPE_BOOLEAN;
783
        } else if( op1 instanceof String ) {
784
            r |= TYPE_STRING;
785
        } else if( op1 instanceof Date ) {
786
            r |= TYPE_DATE;
787
        }
788
        if( op2 == null ) {
789
            r |= TYPE_NULL;
790
        } else if( op2 instanceof BigDecimal ) {
791
            r |= TYPE_BIGDECIMAL;
792
        } else if( op2 instanceof Double ) {
793
            r |= TYPE_DOUBLE;
794
        } else if( op2 instanceof Float ) {
795
            r |= TYPE_FLOAT;
796
        } else if( op2 instanceof Long ) {
797
            r |= TYPE_LONG;
798
        } else if( op2 instanceof Integer ) {
799
            r |= TYPE_INT;
800
        } else if( op2 instanceof Boolean ) {
801
            r |= TYPE_BOOLEAN;
802
        } else if( op2 instanceof String ) {
803
            r |= TYPE_STRING;
804
        } else if( op2 instanceof Date ) {
805
            r |= TYPE_DATE;
806
        }
807
        return r;
808
    }
809

    
810
    @Override
811
    public String toString(Codes args, Formatter<Code> formatter) {
812
        return null;
813
    }
814

    
815
    @Override
816
    public String toString() {
817
        return this.name;
818
    }
819
    
820
    protected void checkDoubleValue(double value) {
821
        if (Double.isInfinite(value)) {
822
            throw new OutOfRangeException(value, Double.MIN_VALUE, Double.MAX_VALUE);
823
        }
824

    
825
    }
826

    
827
    protected void checkFloatValue(float value) {
828
        if (Float.isInfinite(value)) {
829
            throw new OutOfRangeException(value, Float.MIN_VALUE, Float.MAX_VALUE);
830
        }
831

    
832
    }
833

    
834
    @Override
835
    public ExpressionBuilder.Value toValue(ExpressionBuilder builder, Codes parameters) {
836
        ExpressionBuilder.Function f = builder.function(this.name());
837
        if (parameters!= null) {
838
            for (Code parameter : parameters) {
839
                if (parameter == null) {
840
                    f.parameter(null);
841
                } else {
842
                    f.parameter(parameter.toValue(builder));
843
                }
844
            }
845
        }
846
        return f;
847

    
848
    }
849
    
850
    
851
}