Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extWMS / src / com / iver / cit / gvsig / fmap / layers / TimeDimension.java @ 4578

History | View | Annotate | Download (26.5 KB)

1
/* gvSIG. Sistema de Informaci�n Geogr�fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2005 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib��ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   IVER T.I. S.A
34
 *   Salamanca 50
35
 *   46005 Valencia
36
 *   Spain
37
 *
38
 *   +34 963163400
39
 *   dac@iver.es
40
 */
41

    
42
/* CVS MESSAGES:
43
*
44
* $Id: TimeDimension.java 4222 2006-02-28 15:26:59Z jaume $
45
* $Log$
46
* Revision 1.5  2006-02-28 15:25:14  jaume
47
* *** empty log message ***
48
*
49
* Revision 1.3.2.6  2006/02/28 12:54:12  jaume
50
* *** empty log message ***
51
*
52
* Revision 1.3.2.5  2006/02/23 10:36:30  jaume
53
* *** empty log message ***
54
*
55
* Revision 1.3.2.4  2006/02/10 13:22:35  jaume
56
* now analyzes dimensions on demand
57
*
58
* Revision 1.3.2.3  2006/01/31 16:25:24  jaume
59
* correcciones de bugs
60
*
61
* Revision 1.4  2006/01/26 16:07:14  jaume
62
* *** empty log message ***
63
*
64
* Revision 1.3.2.1  2006/01/26 12:59:32  jaume
65
* 0.5
66
*
67
* Revision 1.3  2006/01/24 18:01:17  jaume
68
* *** empty log message ***
69
*
70
* Revision 1.2  2006/01/24 14:36:33  jaume
71
* This is the new version
72
*
73
* Revision 1.1.2.11  2006/01/20 15:59:13  jaume
74
* *** empty log message ***
75
*
76
* Revision 1.1.2.10  2006/01/20 15:22:46  jaume
77
* *** empty log message ***
78
*
79
* Revision 1.1.2.9  2006/01/20 08:50:52  jaume
80
* handles time dimension for the NASA Jet Propulsion Laboratory WMS
81
*
82
* Revision 1.1.2.8  2006/01/19 16:09:30  jaume
83
* *** empty log message ***
84
*
85
* Revision 1.1.2.7  2006/01/11 12:20:30  jaume
86
* *** empty log message ***
87
*
88
* Revision 1.1.2.6  2006/01/10 11:33:31  jaume
89
* Time dimension working against Jet Propulsion Laboratory's WMS server
90
*
91
* Revision 1.1.2.5  2006/01/09 18:10:38  jaume
92
* casi con el time dimension
93
*
94
* Revision 1.1.2.4  2006/01/05 23:15:53  jaume
95
* *** empty log message ***
96
*
97
* Revision 1.1.2.3  2006/01/04 18:09:02  jaume
98
* Time dimension
99
*
100
* Revision 1.1.2.2  2006/01/04 16:49:44  jaume
101
* Time dimensios
102
*
103
* Revision 1.1.2.1  2006/01/03 18:08:40  jaume
104
* *** empty log message ***
105
*
106
*
107
*/
108
/**
109
 * 
110
 */
111
package com.iver.cit.gvsig.fmap.layers;
112

    
113
import java.util.ArrayList;
114
import java.util.GregorianCalendar;
115

    
116
import com.iver.andami.PluginServices;
117

    
118
/**
119
 * Class for WMS TIME dimension from a WMS. It allows you to handle the correct
120
 * values for this kind of dimension.
121
 * <br>
122
 * <p>
123
 * At the moment this class was written the WMS TIME dimension is defined as the
124
 * ISO8601 standard for expressing times.
125
 * </p>
126
 * <br>
127
 * <p>
128
 * As far as this class implements IFMapWMSDimension it uses the same interface
129
 * and documentation.
130
 * </p>
131
 * 
132
 * @author jaume dominguez faus - jaume.dominguez@iver.es
133
 */
134
public class TimeDimension implements IFMapWMSDimension {
135
        static private final byte YEAR_FORMAT          = 1;
136
        static private final byte YEAR_TO_MONTH_FORMAT = 2;
137
        static private final byte YEAR_TO_DAY_FORMAT   = 3;
138
        static private final byte FULL_FORMAT          = 4;
139
        
140
    static private final long millisXsec    = 1000;
141
    static private final long millisXminute = 60 * millisXsec;
142
    static private final long millisXhour   = 60 * millisXminute;
143
    static private final long millisXday    = 24 * millisXhour;
144
    static private final long millisXmonth  = 30 * millisXday;
145
    // according on the Wikipedia (1 year = 365 days 6 hours 9 minutes 9,7 seconds)
146
    static private final long millisXyear   = (365*millisXday) + (6*millisXhour) + (9*millisXminute) + 9700; 
147
    
148
    static private final String digit = "[0-9]";
149
    static private final String nonZeroDigit = "[1-9]";
150
    static private final String seconds = "([0-5]"+digit+"((\\.|,)"+digit+digit+")?)";
151
    static private final String minutes = "([0-5]"+digit+")";
152
    static private final String hours = "(0"+digit+"|1"+digit+"|2[0-3])";
153
    static private final String time = hours+":"+minutes+"(:"+seconds+")?";
154
    static private final String days = "(0?"+nonZeroDigit+"|1"+digit+"|2"+digit+"|30|31)";
155
    static private final String months = "(0?"+nonZeroDigit+"|10|11|12)";
156
    static private final String year = "("+digit+digit+")";
157
    static private final String century = "("+digit+digit+")";
158
    static private final String floatingPointNumber = "("+digit+"+(\\."+digit+"+)?)";
159
    
160
    private String name = PluginServices.getText(this, "time");
161
        private String unit;
162
        private String unitSymbol;
163
        private ArrayList valueList;
164
        private boolean compiled;
165
        private boolean isGeologic;
166
        private String expression;
167
        private int type;
168
        private byte format = 0;
169

    
170
    static private final String regexDateExtendedForBCE1 = "B?"+century+year+"-";
171
    static private final String regexDateExtendedForBCE2 = "B?"+century+year+"-"+months;
172
    static private final String regexDateExtendedForBCE3 = "B?"+century+year+"-"+months+"-"+days;
173
    static private final String regexDateExtendedForBCE4 = "B?"+century+year+"-"+months+"-"+days+"(T| )"+time+"Z";
174
    // Note: in WMS 1.1.0 the suffix Z is optional
175
    
176
    static private final String regexDateExtendedForBCE = 
177
        "(" +  regexDateExtendedForBCE1  + "|"
178
            +  regexDateExtendedForBCE2  + "|"
179
            +  regexDateExtendedForBCE3  + "|"
180
            +  regexDateExtendedForBCE4  +      ")";
181
    
182
    static private final String periodMagnitude = "(Y|M|D)";
183
    static private final String p1 = "(("+digit+")+"+periodMagnitude+")";
184
    
185
    static private final String timeMagnitude = "(H|M|S)";
186
    static private final String p2 = "("+floatingPointNumber+timeMagnitude+")";
187
    static private final String regexPeriod = "P(("+p1+"+"+"(T"+p2+")*)|("+p1+"*"+"(T"+p2+")+))"; 
188
    
189
    static private final String regexIntervalTimeDimension =
190
        "("+regexDateExtendedForBCE+")/("+regexDateExtendedForBCE+")/("+regexPeriod+")";
191
    
192
    static private final String geologicDatasets = "(K|M|G)";
193
    static private final String regexDateForGeologicDatasets = geologicDatasets+floatingPointNumber;
194
    
195
    /**
196
     * Creates a new instance of TimeDimension.
197
     * @param units
198
     * @param unitSymbol
199
     * @param expression
200
     */
201
    public TimeDimension(String _units, String _unitSymbol, String _dimensionExpression) {
202
        this.unit = _units;
203
        this.unitSymbol = _unitSymbol;
204
        setExpression(_dimensionExpression);
205
    }
206
        
207
        public String getName() {
208
        return name;
209
    }
210
    
211
    public String getUnit() {
212
        return unit;
213
    }
214

    
215
    public String getUnitSymbol() {
216
        return unitSymbol;
217
    }
218

    
219
        public String getLowLimit() {
220
                return (String) valueList.get(0);
221
        }
222

    
223
        public String getHighLimit() {
224
                return (String) valueList.get(valueList.size()-1);
225
        }
226

    
227
        
228
        public String getResolution() {
229
                return null;
230
        }
231

    
232
        public boolean isValidValue(String value) {
233
                return (value.matches(regexDateForGeologicDatasets) || value.matches(regexDateExtendedForBCE));
234
        }
235

    
236
        public Object valueOf(String value) throws IllegalArgumentException {
237
                if (compiled) {
238
                    // TODO Missing geological dates
239
                    String myValue = value.toUpperCase();
240
                    if (isValidValue(myValue)) {
241
                            Object val = null;
242
                            if (!isGeologic){
243
                                    // This is a normal date
244
                                    int myYear;
245
                                    int myMonth;
246
                                    int myDay;
247
                                    int myHour;
248
                                    int myMinute;
249
                                    float mySecond;
250
                                    String[] s = myValue.split("-");
251
                                    myYear = (s[0].charAt(0)=='B') ? -Integer.parseInt(s[0].substring(1, 5)) : Integer.parseInt(s[0].substring(0, 4));
252
                                    myMonth = (s.length>1) ? Integer.parseInt(s[1])-1 : 0; 
253
                                    if (myValue.matches(regexDateExtendedForBCE4)){
254
                                            if (s[2].endsWith("Z"))
255
                                                    s[2] = s[2].substring(0,s[2].length()-1);
256
                                            s = (s[2].indexOf('T')!=-1) ? s[2].split("T") : s[2].split(" ");
257
                                            myDay = Integer.parseInt(s[0]);
258
                                            
259
                                            // Go with the time
260
                                            s = s[1].split(":");
261
                                            myHour = Integer.parseInt(s[0]);
262
                                            myMinute = (s.length>1) ? Integer.parseInt(s[1]) : 0;
263
                                            mySecond = (s.length>2) ? Float.parseFloat(s[2]) : 0;
264
                                    } else {
265
                                            myDay = (s.length>2) ? Integer.parseInt(s[2]) : 1;
266
                                            
267
                                            myHour = 0;
268
                                            myMinute = 0;
269
                                            mySecond = 0;
270
                                    }
271
                                    GregorianCalendar cal = new GregorianCalendar(myYear, myMonth, myDay, myHour, myMinute, (int)mySecond);
272
                                    val = cal;
273
                            } else{
274
                                    // this is a geological date >:-(
275
                            }
276
                            return val;    
277
                    } else throw new IllegalArgumentException(myValue);
278
            }
279
            return null;
280
        }
281

    
282
        public String valueAt(int pos) throws ArrayIndexOutOfBoundsException {
283
                return toString((GregorianCalendar) valueList.get(pos));
284
        }
285

    
286
        public int valueCount() {
287
                return valueList.size();
288
        }
289

    
290
        public String getExpression() {
291
                return expression;
292
        }
293

    
294
        public void setExpression(String expr) {
295
                this.expression = expr;
296
        }
297

    
298
        public int getType() {
299
                return type;
300
        }
301

    
302
        public void compile() throws IllegalArgumentException {
303
                compiled = true;
304
                valueList = new ArrayList();
305
                String[] items = expression.split(",");
306
                for (int i = 0; i < items.length; i++) {
307
                        // Each iteration is a value of a comma-separated list
308
                        // which can be a single date or even an expression defining
309
                        // an interval.
310
                        if (items[i].matches(regexDateExtendedForBCE1)) {
311
                                upgradeFormat(YEAR_FORMAT);
312
                                valueList.add(valueOf(items[i]));
313
                        } else if (items[i].matches(regexDateExtendedForBCE2)) {
314
                                upgradeFormat(YEAR_TO_MONTH_FORMAT);
315
                                valueList.add(valueOf(items[i]));
316
                        } else if (items[i].matches(regexDateExtendedForBCE3)) {
317
                                upgradeFormat(YEAR_TO_DAY_FORMAT);
318
                                valueList.add(valueOf(items[i]));
319
                        } else if (items[i].matches(regexDateExtendedForBCE4)) { 
320
                                upgradeFormat(FULL_FORMAT);
321
                                valueList.add(valueOf(items[i]));
322
                        } else if (items[i].matches(regexIntervalTimeDimension)) {
323
                                // Analyze and transform this interval expression to a list
324
                                // of values.
325
                                
326
                                // min value
327
                                String[] s = items[i].split("/");
328
                                if (s[0].matches(regexDateExtendedForBCE1)) {
329
                                        upgradeFormat(YEAR_FORMAT);
330
                                } else if (s[0].matches(regexDateExtendedForBCE2)) {
331
                                        upgradeFormat(YEAR_TO_MONTH_FORMAT);
332
                                } else if (s[0].matches(regexDateExtendedForBCE3)) {
333
                                        upgradeFormat(YEAR_TO_DAY_FORMAT);
334
                                } else if (s[0].matches(regexDateExtendedForBCE4)) { 
335
                                        upgradeFormat(FULL_FORMAT);
336
                                }
337
                                Object minValue = valueOf(s[0]);
338
                                
339
                                // max value
340
                                if (s[0].matches(regexDateExtendedForBCE1)) {
341
                                        upgradeFormat(YEAR_FORMAT);
342
                                } else if (s[1].matches(regexDateExtendedForBCE2)) {
343
                                        upgradeFormat(YEAR_TO_MONTH_FORMAT);
344
                                } else if (s[1].matches(regexDateExtendedForBCE3)) {
345
                                        upgradeFormat(YEAR_TO_DAY_FORMAT);
346
                                } else if (s[1].matches(regexDateExtendedForBCE4)) { 
347
                                        upgradeFormat(FULL_FORMAT);
348
                                }
349
                                Object maxValue = valueOf(s[1]);
350
                                
351
                                String period = s[2];
352
                                        
353
                                if (period == null) {
354
                                        valueList.add(minValue);
355
                                        valueList.add(maxValue);
356
                                        continue;
357
                                }
358
                                
359
                                long x1 = ((GregorianCalendar) maxValue).getTimeInMillis();
360
                                long x0 = ((GregorianCalendar) minValue).getTimeInMillis();
361
                                long distance = x1-x0;
362
                                long step = 0;
363
                                
364
                                boolean isTimeField = false;
365
                                String val = "";
366
                                
367
                                for (int j = 0; j < period.length(); j++) {
368
                                        if (period.charAt(j) == 'P')
369
                                                continue;
370
                                        if (period.charAt(j) == 'T') {
371
                                                isTimeField = true;
372
                                                continue;
373
                                        }
374
                                        switch (period.charAt(j)) {
375
                                        case 'Y':
376
                                                step += Integer.parseInt(val) * millisXyear;
377
                                                val = "";
378
                                                break;
379
                                        case 'M':
380
                                                if (isTimeField)
381
                                                        step += Integer.parseInt(val) * millisXminute;
382
                                                else
383
                                                        step += Integer.parseInt(val) * millisXmonth;
384
                                                val = "";
385
                                                break;
386
                                        case 'D':
387
                                                step += Integer.parseInt(val) * millisXday;
388
                                                val = "";
389
                                                break;
390
                                        case 'H':
391
                                                step += Integer.parseInt(val) * millisXhour;
392
                                                val = "";
393
                                                break;
394
                                        case 'S':
395
                                                step += Integer.parseInt(val) * 1000;
396
                                                val = "";
397
                                                break;
398
                                        default:
399
                                                val += period.charAt(j);
400
                                                break;
401
                                        }                       
402
                                }
403
                                // Now that we know the earliest and the latest date and the period
404
                                // between two dates, I'm going to populate the list of values
405
                                // considering these values.
406
                                int valueCount = (int)(distance/step) + 1; // + 1 for the initial point
407
                                valueList.add(minValue);
408
                                for (int pos = 1; pos < valueCount; pos++) {
409
                                        long newTime = ((GregorianCalendar) minValue).getTimeInMillis();
410
                                    newTime += (step*pos);
411
                                    GregorianCalendar cal = new GregorianCalendar();
412
                                    cal.setTimeInMillis(newTime);
413
                                    if (cal.after(maxValue) || cal.before(minValue))
414
                                            continue;
415

    
416
                                    valueList.add(cal);
417
                                }
418
                                valueList.add(maxValue);
419
                        } else {
420
                                compiled = false;
421
                                throw new IllegalArgumentException();
422
                        }
423
                }
424
    }
425
        
426
        /**
427
         * Prints a GregorianCalendar value in WMS1.1.1 format.
428
         * @param cal
429
         * @return
430
         */
431
        private String toString(GregorianCalendar cal) {
432
                int iYear   = cal.get(cal.YEAR);
433
                int iMonth  = cal.get(cal.MONTH) + 1;
434
                int iDay    = cal.get(cal.DAY_OF_MONTH);
435
                int iHour   = cal.get(cal.HOUR_OF_DAY);
436
                int iMinute = cal.get(cal.MINUTE);
437
                int iSecond = cal.get(cal.SECOND);
438
                String myYear;
439
                if (iYear<10)
440
                        myYear = "200"+iYear;
441
                else if (iYear<100)
442
                        myYear = "20"+iYear;
443
                else if (iYear<1000)
444
                        myYear = "2"+iYear;
445
                else
446
                        myYear = ""+iYear;
447
                String myMonth       = (iMonth<10) ? "0"+iMonth  : ""+iMonth;
448
                String myDay         = (iDay<10)   ? "0"+iDay    : ""+iDay;
449
                String myHour        = (iHour<10)  ? "0"+iHour   : ""+iHour;
450
                String myMinute      = (iMinute<10)? "0"+iMinute : ""+iMinute;
451
                String mySecond      = (iSecond<10)? "0"+iSecond : ""+iSecond;
452
                int myMilliSecond = cal.get(cal.MILLISECOND);
453
                
454
                
455
                String s = null;
456
                if (format == YEAR_FORMAT)
457
                        s = myYear+"";
458
                else if (format == YEAR_TO_MONTH_FORMAT)
459
                        s = myYear+"-"+myMonth;
460
                else if (format == YEAR_TO_DAY_FORMAT)
461
                        s = myYear+"-"+myMonth+"-"+myDay;
462
                else if (format == FULL_FORMAT)
463
                        s = myYear+"-"+myMonth+"-"+myDay+"T"+myHour+":"+myMinute+":"+mySecond+"."+(myMilliSecond/10)+"Z";
464
                if (iYear<0)
465
                        s = "B"+s;
466
                return s;
467
        }
468

    
469
        private void upgradeFormat(byte sFormat) {
470
                switch (sFormat) {
471
                case YEAR_FORMAT:
472
                        if (format < YEAR_FORMAT)
473
                                format = YEAR_FORMAT;
474
                        break;
475
                case YEAR_TO_MONTH_FORMAT:
476
                        if (format < YEAR_TO_MONTH_FORMAT)
477
                                format = YEAR_TO_MONTH_FORMAT;
478
                        break;
479
                case YEAR_TO_DAY_FORMAT:
480
                        if (format < YEAR_TO_DAY_FORMAT)
481
                                format = YEAR_TO_DAY_FORMAT;
482
                        break;
483
                case FULL_FORMAT:
484
                        if (format < FULL_FORMAT)
485
                                format = FULL_FORMAT;
486
                        break;
487
                }
488
        }
489
}
490

    
491

    
492
/*
493
  
494
 // an old (and good one) version. However, the new version is a bit better.
495
 
496
 public class TimeDimension implements IFMapWMSDimension {
497
    static private final long millisXsec    = 1000;
498
    static private final long millisXminute = 60 * millisXsec;
499
    static private final long millisXhour   = 60 * millisXminute;
500
    static private final long millisXday    = 24 * millisXhour;
501
    static private final long millisXmonth  = 30 * millisXday;
502
    // according on the Wikipedia (1 year = 365 days 6 hours 9 minutes 9,7 seconds)
503
    static private final long millisXyear   = (365*millisXday) + (6*millisXhour) + (9*millisXminute) + 9700; 
504
    
505
    static private final String digit = "[0-9]";
506
    static private final String nonZeroDigit = "[1-9]";
507
    static private final String letter = "[a-zA-Z]";
508
    static private final String seconds = "([0-5]"+digit+"((\\.|,)"+digit+digit+")?)";
509
    static private final String minutes = "([0-5]"+digit+")";
510
    static private final String hours = "(0"+digit+"|1"+digit+"|2[0-3])";
511
    static private final String time = hours+":"+minutes+"(:"+seconds+")?";
512
    static private final String days = "(0?"+nonZeroDigit+"|1"+digit+"|2"+digit+"|30|31)";
513
    static private final String months = "(0?"+nonZeroDigit+"|10|11|12)";
514
    static private final String year = "("+digit+digit+")";
515
    static private final String century = "("+digit+digit+")";
516
    
517
    static private final String geologicDatasets = "(K|M|G)";
518
    static private final String floatingPointNumber = "("+digit+"+(\\."+digit+"+)?)";
519
    
520
    
521
    static private final String regexDateExtendedForBCE1 = "B?"+century+year+"-";
522
    static private final String regexDateExtendedForBCE2 = "B?"+century+year+"-"+months;
523
    static private final String regexDateExtendedForBCE3 = "B?"+century+year+"-"+months+"-"+days;
524
    static private final String regexDateExtendedForBCE4 = "B?"+century+year+"-"+months+"-"+days+"(T| )"+time+"Z";
525
    // Note: in WMS 1.1.0 the suffix Z is optional
526
    // TODO truncated values not yet allowed
527
    
528
    static private final String regexDateExtendedForBCE = 
529
        "(" +  regexDateExtendedForBCE1  + "|"
530
            +  regexDateExtendedForBCE2  + "|"
531
            +  regexDateExtendedForBCE3  + "|"
532
            +  regexDateExtendedForBCE4  +      ")";
533
    
534
    
535
    static private final String regexDateForGeologicDatasets = geologicDatasets+floatingPointNumber;
536
    
537
    static private final String periodMagnitude = "(Y|M|D)";
538
    static private final String p1 = "(("+digit+")+"+periodMagnitude+")";
539
    
540
    static private final String timeMagnitude = "(H|M|S)";
541
    static private final String p2 = "("+floatingPointNumber+timeMagnitude+")";
542
    static private final String regexPeriod = "P(("+p1+"+"+"(T"+p2+")*)|("+p1+"*"+"(T"+p2+")+))"; 
543
    
544
    static private final String regexTimeDimension =
545
        "("+regexDateExtendedForBCE+"(,"+regexDateExtendedForBCE+")*|("+regexDateExtendedForBCE+")/("+regexDateExtendedForBCE+")/("+regexPeriod+"))";
546
    
547
    private String name = "TIME";
548
    private String unit;
549
    private String unitSymbol;
550
    private String expression;
551
    private Object minValue;
552
    private Object maxValue;
553
    private boolean isGeologic = false;
554
    private Integer valueCount;
555
    private String period;
556
    private long step; // Distance between two points in milliseconds.
557
    private int type;
558
    private boolean compiled = false;
559
    
560
    /**
561
     * Creates a new instance of TimeDimension.
562
     * @param units
563
     * @param unitSymbol
564
     * @param expression
565
     * /
566
    public TimeDimension(String _units, String _unitSymbol, String _dimensionExpression) {
567
        this.unit = _units;
568
        this.unitSymbol = _unitSymbol;
569
        setExpression(_dimensionExpression);
570
    }
571

572
    public String getName() {
573
        return name;
574
    }
575
    
576
    public String getUnit() {
577
        return unit;
578
    }
579

580
    public String getUnitSymbol() {
581
        return unitSymbol;
582
    }
583

584

585
    public String getLowLimit() {
586
            String separator = (type == INTERVAL) ? "/" : ",";
587
        return expression.split(separator)[0];
588
    }
589

590
    public String getHighLimit() {
591
            if (type == INTERVAL) {
592
                    String[] s = expression.split("/");
593
                    return (s.length > 1) ? s[1] : s[0];
594
            } else if (type == MULTIPLE_VALUE) {
595
                    String[] s = expression.split(",");
596
                    return s[s.length-1];
597
            } else {
598
                    return expression;
599
            }
600
                    
601
    }
602

603
    public String getResolution() {
604
            if (type == INTERVAL) {
605
                    String[] s = expression.split("/");
606
                    return (s.length == 1) ? s[3] : null;
607
            } else return null;
608
    }
609

610
    public boolean isValidValue(String value) {
611
        return (value.matches(regexDateForGeologicDatasets) || value.matches(regexDateExtendedForBCE));
612
    }
613
    
614
    public Object valueOf(String value) throws IllegalArgumentException {
615
            if (compiled) {
616
                    // TODO Missing geological dates
617
                    String myValue = value.toUpperCase();
618
                    if (isValidValue(myValue)) {
619
                            Object val = null;
620
                            if (!isGeologic){
621
                                    // This is a normal date
622
                                    int myYear;
623
                                    int myMonth;
624
                                    int myDay;
625
                                    int myHour;
626
                                    int myMinute;
627
                                    float mySecond;
628
                                    String[] s = myValue.split("-");
629
                                    myYear = (s[0].charAt(0)=='B')? -Integer.parseInt(s[0].substring(1, 5)) : Integer.parseInt(s[0].substring(0, 4));
630
                                    myMonth = (s.length>1) ? Integer.parseInt(s[1])-1 : 0; 
631
                                    if (myValue.matches(regexDateExtendedForBCE4)){
632
                                            if (s[2].endsWith("Z"))
633
                                                    s[2] = s[2].substring(0,s[2].length()-1);
634
                                            s = (s[2].indexOf('T')!=-1) ? s[2].split("T") : s[2].split(" ");
635
                                            myDay = Integer.parseInt(s[0]);
636
                                            
637
                                            // Go with the time
638
                                            s = s[1].split(":");
639
                                            myHour = Integer.parseInt(s[0]);
640
                                            myMinute = (s.length>1) ? Integer.parseInt(s[1]) : 0;
641
                                            mySecond = (s.length>2) ? Float.parseFloat(s[2]) : 0;
642
                                    } else {
643
                                            myDay = (s.length>2) ? Integer.parseInt(s[2]) : 1;
644
                                            
645
                                            myHour = 0;
646
                                            myMinute = 0;
647
                                            mySecond = 0;
648
                                    }
649
                                    GregorianCalendar cal = new GregorianCalendar(myYear, myMonth, myDay, myHour, myMinute, (int)mySecond);
650
                                    val = cal;
651
                            } else{
652
                                    // this is a geological date >:-(
653
                            }
654
                            return val;    
655
                    } else throw new IllegalArgumentException(myValue);
656
            }
657
            return null;
658
    }
659
 
660
    public String valueAt(int pos) throws ArrayIndexOutOfBoundsException {
661
            if (compiled) { 
662
                    if (pos<0 || pos>valueCount())
663
                            throw new ArrayIndexOutOfBoundsException(pos+"(must be >= 0 and <="+valueCount()+")");
664
                    
665
                    if (type == SINGLE_VALUE)
666
                            return expression;
667
                    
668
                    if (type == MULTIPLE_VALUE)
669
                            return expression.split(",")[pos];
670
                    
671
                    if (!isGeologic){
672
                            long newTime = ((GregorianCalendar) minValue).getTimeInMillis();
673
                            newTime += (step*pos);
674
                            GregorianCalendar cal = new GregorianCalendar();
675
                            cal.setTimeInMillis(newTime);
676
                            if (cal.after(maxValue))
677
                                    return toString((GregorianCalendar) maxValue);
678
                            else if (cal.before(minValue))
679
                                    return toString((GregorianCalendar) minValue);
680
                            else
681
                                    return toString(cal);
682
                    }
683
            }
684
        return null;
685
    }
686

687
    /**
688
     * Prints a GregorianCalendar value in WMS1.1.1 format.
689
     * @param cal
690
     * @return
691
     * /
692
    private String toString(GregorianCalendar cal) {
693
        int iYear   = cal.get(cal.YEAR);
694
        int iMonth  = cal.get(cal.MONTH) + 1;
695
        int iDay    = cal.get(cal.DAY_OF_MONTH);
696
        int iHour   = cal.get(cal.HOUR_OF_DAY);
697
        int iMinute = cal.get(cal.MINUTE);
698
        int iSecond = cal.get(cal.SECOND);
699
        String myYear;
700
        if (iYear<10)
701
            myYear = "200"+iYear;
702
        else if (iYear<100)
703
            myYear = "20"+iYear;
704
        else if (iYear<1000)
705
            myYear = "2"+iYear;
706
        else
707
            myYear = ""+iYear;
708
        String myMonth       = (iMonth<10) ? "0"+iMonth  : ""+iMonth;
709
        String myDay         = (iDay<10)   ? "0"+iDay    : ""+iDay;
710
        String myHour        = (iHour<10)  ? "0"+iHour   : ""+iHour;
711
        String myMinute      = (iMinute<10)? "0"+iMinute : ""+iMinute;
712
        String mySecond      = (iSecond<10)? "0"+iSecond : ""+iSecond;
713
        int myMilliSecond = cal.get(cal.MILLISECOND);
714
        
715
        
716
        String s = myYear+"-"+myMonth+"-"+myDay+"T"+myHour+":"+myMinute+":"+mySecond+"."+(myMilliSecond/10)+"Z";
717
        if (iYear<0)
718
            s = "B"+s;
719
        return s;
720
    }
721

722
    public int valueCount() {
723
            if (compiled) {
724
                    if (valueCount==null){
725
                            if (type == MULTIPLE_VALUE) {
726
                                    return expression.split(",").length;
727
                            } else if (type == INTERVAL) {
728
                                    if (period == null) {
729
                                            valueCount = new Integer(0);
730
                                            return valueCount.intValue();
731
                                    }
732
                                    
733
                                    if (!isGeologic){
734
                                            
735
                                            long x1 = ((GregorianCalendar) maxValue).getTimeInMillis();
736
                                            long x0 = ((GregorianCalendar) minValue).getTimeInMillis();
737
                                            long distance = x1-x0;
738
                                            step = 0;
739
                                            
740
                                            boolean isTimeField = false;
741
                                            String val = "";
742
                                            
743
                                            for (int i = 0; i < period.length(); i++) {
744
                                                    if (period.charAt(i) == 'P')
745
                                                            continue;
746
                                                    if (period.charAt(i) == 'T'){
747
                                                            isTimeField = true;
748
                                                            continue;
749
                                                    }
750
                                                    switch (period.charAt(i)){
751
                                                    case 'Y':
752
                                                            step += Integer.parseInt(val) * millisXyear;
753
                                                            val = "";
754
                                                            break;
755
                                                    case 'M':
756
                                                            if (isTimeField)
757
                                                                    step += Integer.parseInt(val) * millisXminute;
758
                                                            else
759
                                                                    step += Integer.parseInt(val) * millisXmonth;
760
                                                            val = "";
761
                                                            break;
762
                                                    case 'D':
763
                                                            step += Integer.parseInt(val) * millisXday;
764
                                                            val = "";
765
                                                            break;
766
                                                    case 'H':
767
                                                            step += Integer.parseInt(val) * millisXhour;
768
                                                            val = "";
769
                                                            break;
770
                                                    case 'S':
771
                                                            step += Integer.parseInt(val) * 1000;
772
                                                            val = "";
773
                                                            break;
774
                                                    default:
775
                                                            val += period.charAt(i);
776
                                                    break;
777
                                                    }                       
778
                                            }
779
                                            valueCount = new Integer((int)(distance/step) + 1); // + 1 for the initial point
780
                                    }
781
                            } else {
782
                                    // this is a single value expression
783
                                    valueCount = new Integer(1);
784
                                    return valueCount.intValue();
785
                            }
786
                    }
787
                    
788
                    return valueCount.intValue();
789
            }
790
            return -1;
791
    }
792

793
    public void setExpression(String expr) {
794
        expression = expr.toUpperCase();
795
    }
796

797
        public String getExpression() {
798
                return expression;
799
        }
800

801
        public int getType() {
802
                return type;
803
        }
804

805
        public void compile() {
806
                if (expression.matches(regexTimeDimension)){
807
            isGeologic = false;
808
        } else if (expression.matches(regexDateExtendedForBCE)) {
809
            isGeologic = false;
810
        } else if (expression.matches(regexDateForGeologicDatasets)){
811
            isGeologic = true;
812
        } else  {
813
            throw new IllegalArgumentException();
814
        }
815
                String separator;        
816
        
817
        if (expression.indexOf("/")!=-1) {
818
                separator = "/";
819
                type = INTERVAL;
820
        } else if (expression.indexOf(",")!=-1) {
821
                separator = ",";
822
                type = MULTIPLE_VALUE;
823
        } else {
824
                separator = ",";
825
                type = SINGLE_VALUE;
826
        }
827
                
828
        compiled = true;
829
        String[] s = expression.split(separator);
830
        minValue = valueOf(s[0]);
831
        if (type == INTERVAL) {
832
                maxValue = (s.length>1) ? valueOf(s[1]) : valueOf(s[0]);
833
                period = (s.length>2 && s[2].matches(regexPeriod)) ? s[2] : null;
834
        } else if (type == MULTIPLE_VALUE) {
835
                maxValue = valueOf(s[s.length-1]);
836
        } else {
837
                maxValue = valueOf(s[0]);
838
        }
839
        }
840
}*/
841

    
842