Statistics
| Revision:

root / branches / v05 / extensions / extWMS / src / com / iver / cit / gvsig / fmap / layers / TimeDimension.java @ 4221

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

    
110
import java.util.ArrayList;
111
import java.util.GregorianCalendar;
112

    
113
import com.iver.andami.PluginServices;
114

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

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

    
212
    public String getUnitSymbol() {
213
        return unitSymbol;
214
    }
215

    
216
        public String getLowLimit() {
217
                return (String) valueList.get(0);
218
        }
219

    
220
        public String getHighLimit() {
221
                return (String) valueList.get(valueList.size()-1);
222
        }
223

    
224
        
225
        public String getResolution() {
226
                return null;
227
        }
228

    
229
        public boolean isValidValue(String value) {
230
                return (value.matches(regexDateForGeologicDatasets) || value.matches(regexDateExtendedForBCE));
231
        }
232

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

    
279
        public String valueAt(int pos) throws ArrayIndexOutOfBoundsException {
280
                return toString((GregorianCalendar) valueList.get(pos));
281
        }
282

    
283
        public int valueCount() {
284
                return valueList.size();
285
        }
286

    
287
        public String getExpression() {
288
                return expression;
289
        }
290

    
291
        public void setExpression(String expr) {
292
                this.expression = expr;
293
        }
294

    
295
        public int getType() {
296
                return type;
297
        }
298

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

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

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

    
488

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

569
    public String getName() {
570
        return name;
571
    }
572
    
573
    public String getUnit() {
574
        return unit;
575
    }
576

577
    public String getUnitSymbol() {
578
        return unitSymbol;
579
    }
580

581

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

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

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

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

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

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

790
    public void setExpression(String expr) {
791
        expression = expr.toUpperCase();
792
    }
793

794
        public String getExpression() {
795
                return expression;
796
        }
797

798
        public int getType() {
799
                return type;
800
        }
801

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

    
839