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.util.Arrays;
013import java.util.EventObject;
014import java.util.regex.Matcher;
015import java.util.regex.Pattern;
016
017/**
018 * Event fired to disseminate information about a dataset changing.
019 * For instance if an image represents a live stream.
020 * 
021 * This event is passed over web-sockets. To keep dependencies to a 
022 * minimum and since it is really simple, we have added an encode and
023 * decode to JSON without the need for an API like Jackson.
024 */
025public class DataEvent extends EventObject {
026        
027        /**
028         * 
029         */
030        private static final long serialVersionUID = 751125872769278449L;
031
032        private int[]  shape;
033        
034        /**
035         * Optionally, we can indicate where the file path was.
036         */
037        private String filePath;
038
039        /**
040         * The name of the dataset, may be ""
041         */
042        private String name;
043
044        public DataEvent() {
045                this("", new int[] { 1 });
046        }
047
048        /**
049         * Creates an event to notify that this data has changed.
050         * @param name of event
051         * @param shape of dataset
052         */
053        public DataEvent(String name, int[] shape) {
054                super(name);
055                this.shape = shape;
056                this.name  = name;
057        }
058
059        @Override
060        public String getSource() {
061                return (String)super.getSource();
062        }
063        
064        public String getName() {
065                return getSource();
066        }
067        
068        public void setName(String name) {
069                this.name = name;
070        }
071        
072        public int[] getShape() {
073                return shape;
074        }
075
076        public void setShape(int[] shape) {
077                this.shape = shape;
078        }
079
080        public String getFilePath() {
081                return filePath;
082        }
083
084        public void setFilePath(String filePath) {
085                this.filePath = filePath;
086        }
087
088        /**
089         * Encodes event to string
090         * @return encoded string
091         */
092        public String encode() {
093                final StringBuilder buf = new StringBuilder();
094                buf.append("{");
095                buf.append("\"name\" : \"");
096                buf.append(getName());
097                buf.append("\"");
098                buf.append(", \"shape\" : ");
099                buf.append(Arrays.toString(shape));
100                
101                buf.append(", \"filepath\" : \"");
102                buf.append(getFilePath());
103                buf.append("\"");
104                
105                buf.append("}");
106                return buf.toString();
107        }
108        
109        /**
110         * Decodes from input for instance {"name" : "Tests", "shape" : [1024, 1024], "filepath" : "C:/tmp/Fred.txt"}
111         * @param json input
112         * @return DataEvent
113         */
114        public static DataEvent decode(String json) {
115                
116                String name     = getValue(json, ".*\"name\" \\: \"([^\"]+)\".*");
117                String filepath = getValue(json, ".*\"filepath\" \\: \"([^\"]+)\".*");
118                String shape    = getValue(json, ".*\"shape\" \\: \\[([^\\]]+)\\].*");
119
120                DataEvent ret = new DataEvent(name, getArray(shape));
121                if (filepath!=null && !"null".equals(filepath)) {
122                        ret.setFilePath(filepath);
123                }
124                return ret;
125        }
126
127
128        private static String getValue(String json, String regex) {
129                Matcher matcher = Pattern.compile(regex).matcher(json);
130                if (matcher.matches()) {
131                        return matcher.group(1);
132                }
133                throw new RuntimeException(regex+" unmatched in "+json);
134        }
135
136        private static int[] getArray(String value) {
137                String[] split = value.split(",");
138                int[] ret      = new int[split.length];
139                for (int i = 0; i < split.length; i++) ret[i] = Integer.parseInt(split[i].trim());
140                return ret;
141        }
142
143        @Override
144        public int hashCode() {
145                final int prime = 31;
146                int result = 1;
147                result = prime * result + ((filePath == null) ? 0 : filePath.hashCode());
148                result = prime * result + ((name == null) ? 0 : name.hashCode());
149                result = prime * result + Arrays.hashCode(shape);
150                return result;
151        }
152
153        @Override
154        public boolean equals(Object obj) {
155                if (this == obj)
156                        return true;
157                if (obj == null)
158                        return false;
159                if (getClass() != obj.getClass())
160                        return false;
161                DataEvent other = (DataEvent) obj;
162                if (filePath == null) {
163                        if (other.filePath != null)
164                                return false;
165                } else if (!filePath.equals(other.filePath))
166                        return false;
167                if (name == null) {
168                        if (other.name != null)
169                                return false;
170                } else if (!name.equals(other.name))
171                        return false;
172                if (!Arrays.equals(shape, other.shape))
173                        return false;
174                return true;
175        }
176
177}