001/*-
002 * Copyright 2015, 2016 Diamond Light Source Ltd.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 */
009
010package org.eclipse.january.dataset;
011
012import java.text.ParseException;
013import java.text.SimpleDateFormat;
014import java.util.Date;
015
016import org.slf4j.Logger;
017import org.slf4j.LoggerFactory;
018
019public class DateDatasetImpl extends StringDataset implements DateDataset {
020        // pin UID to base class
021        private static final long serialVersionUID = Dataset.serialVersionUID;
022
023        private static final Logger logger = LoggerFactory.getLogger(DateDatasetImpl.class);
024
025        private static final SimpleDateFormat ISO8601_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
026        
027        static DateDatasetImpl createFromObject(final Object obj) {
028                final DateDatasetImpl result = new DateDatasetImpl();
029                result.shape = ShapeUtils.getShapeFromObject(obj);
030                result.size = ShapeUtils.calcSize(result.shape);
031                result.odata = result.data = createArray(result.size);
032                
033                final int[] pos = new int[result.shape.length];
034                result.fillData(obj, 0, pos);
035                
036                return result;
037        }
038
039        /**
040         * Create a null dataset
041         */
042        DateDatasetImpl() {
043                super();
044        }
045
046        DateDatasetImpl(final int... shape) {
047                super(shape);
048        }
049
050        DateDatasetImpl(final Date[] data, int... shape) {
051                super(datesToStrings(data), shape);
052        }
053
054        private static String[] datesToStrings(final Date[] dates) {
055                final String[] dateStrings = new String[dates.length];
056                for (int i = 0; i < dates.length; i++) {
057                        dateStrings[i] = dateToString(dates[i]);
058                }
059                
060                return dateStrings;
061        }
062        
063        private static String dateToString(final Date date) {
064                if (date != null) {
065                        return ISO8601_DATE_FORMAT.format(date);
066                }
067                
068                return null;
069        }
070        
071        private static String objectToDateString(final Object obj) {
072                if (obj instanceof Date) {
073                        return dateToString((Date) obj);
074                } else if (obj instanceof Dataset) {
075                        Dataset dataset = (Dataset) obj;
076                        if (dataset.getSize() != 1) {
077                                logger.error("Given dataset must only have one item");
078                                throw new IllegalArgumentException("Given dataset must have only one item");
079                        }
080                        
081                        return objectToDateString(dataset.getObject());
082                } else if (obj instanceof IDataset) {
083                        IDataset dataset = (IDataset) obj;
084                        if (dataset.getSize() != 1) {
085                                logger.error("Given dataset must only have one item");
086                                throw new IllegalArgumentException("Given dataset must have only one item");
087                        }
088                        return objectToDateString(dataset.getObject(new int[dataset.getRank()]));
089                } else {
090                        logger.error("Argument is of unsupported class");
091                        throw new IllegalArgumentException("Argument is of unsupported class");
092                }
093        }
094
095        private static Date stringToDate(final String dateAsString) {
096                if (dateAsString != null) {
097                        try {
098                                return ISO8601_DATE_FORMAT.parse(dateAsString);
099                        } catch (ParseException e) {
100                                // fall through to return null
101                                logger.error("Could not parse datetime: " + dateAsString);
102                        }
103                }
104                
105                return null;
106        }
107
108        @Override
109        public Date getDate() {
110                final String dateAsString = super.getString();
111                return stringToDate(dateAsString);
112        }
113
114        @Override
115        public Date getDate(int i) {
116                final String dateAsString = super.getString(i);
117                return stringToDate(dateAsString);
118        }
119
120        @Override
121        public Date getDate(int i, int j) {
122                final String dateAsString = super.getString(i, j);
123                return stringToDate(dateAsString);
124        }
125
126        @Override
127        public Date getDate(int... pos) {
128                final String dateAsString = super.getString(pos);
129                return stringToDate(dateAsString);
130        }
131
132        @Override
133        public Date getDateAbs(int index) {
134                final String dateAsString = super.getStringAbs(index);
135                if (dateAsString != null) {
136                        return stringToDate(dateAsString);
137                }
138                
139                return null;
140        }
141
142        @Override
143        public Object getObject() {
144                return getDate();
145        }
146
147        @Override
148        public Object getObject(int i) {
149                return getDate(i);
150        }
151
152        @Override
153        public Object getObject(int i, int j) {
154                return getDate(i, j);
155        }
156
157        @Override
158        public Object getObject(int... pos) {
159                return getDate(pos);
160        }
161
162        @Override
163        public Object getObjectAbs(int index) {
164                return getDateAbs(index);
165        }
166
167        @Override
168        public void setItemDirect(final int dindex, final int sindex, final Object src) {
169                if (src instanceof String[]) {
170                        super.setItemDirect(dindex, sindex, src);
171                } else if (src instanceof Date[]) {
172                        String[] datesAsStrings = datesToStrings((Date[]) src);
173                        data[dindex] = datesAsStrings[sindex];
174                } else {
175                        logger.error("Argument is of unsupported class");
176                        throw new IllegalArgumentException("Argument is of unsupported class");
177                }
178        }
179
180        public void setAbs(final int index, final Date date) {
181                data[index] = dateToString(date);
182                setDirty();
183        }
184
185        /**
186         * @param value to set
187         * @since 2.0
188         */
189        public void setItem(final Date value) {
190                setAbs(getFirst1DIndex(), value);
191        }
192
193        /**
194         * @param value to set
195         * @param i position in first dimension
196         */
197        public void setItem(final Date value, final int i) {
198                setAbs(get1DIndex(i), value);
199        }
200
201        /**
202         * @param value to set
203         * @param i position in first dimension
204         * @param j position in second dimension
205         */
206        public void setItem(final Date value, final int i, final int j) {
207                setAbs(get1DIndex(i, j), value);
208        }
209
210        /**
211         * @param value to set
212         * @param pos position
213         */
214        public void setItem(final Date value, final int... pos) {
215                setAbs(get1DIndex(pos), value);
216        }
217
218        @Override
219        public void set(final Object obj) {
220                setItem(objectToDateString(obj));
221        }
222
223        @Override
224        public void set(final Object obj, final int i) {
225                setItem(objectToDateString(obj), i);
226        }
227
228        @Override
229        public void set(final Object obj, final int i, final int j) {
230                setItem(objectToDateString(obj), i, j);
231        }
232        
233        @Override
234        public void set(final Object obj, int... pos) {
235                if (pos == null || (pos.length == 0 && shape.length > 0)) {
236                        pos = new int[shape.length];
237                }
238                
239                setItem(objectToDateString(obj), pos);
240        }
241        
242        @Override
243        public StringDatasetBase sort(Integer axis) {
244                // Note yet supported.
245                // TODO: this method will be inefficient as we store dates formatted as strings
246                throw new UnsupportedOperationException("Cannot sort dataset");
247        }
248
249}