001/* [{
002Copyright 2007, 2008 Nicolas Carranza <nicarran at gmail.com>
003
004This file is part of jpen.
005
006jpen is free software: you can redistribute it and/or modify
007it under the terms of the GNU Lesser General Public License as published by
008the Free Software Foundation, either version 3 of the License,
009or (at your option) any later version.
010
011jpen is distributed in the hope that it will be useful,
012but WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014GNU Lesser General Public License for more details.
015
016You should have received a copy of the GNU Lesser General Public License
017along with jpen.  If not, see <http://www.gnu.org/licenses/>.
018}] */
019package jpen;
020
021import java.io.IOException;
022import java.io.ObjectInputStream;
023import java.util.Arrays;
024import jpen.event.PenListener;
025import jpen.internal.AccessibleField;
026
027public abstract class PenEvent
028        implements java.io.Serializable {
029        public static final long serialVersionUID=2l;
030
031        protected long time=-1;
032        transient volatile PenEvent next;
033        public final transient Pen pen;
034        private final byte deviceId;
035        private final long deviceTime;
036        private transient Object penOwnerTag;
037
038        PenEvent(PenDevice device, long deviceTime) {
039                this(device.getProvider().getConstructor().getPenManager().pen,
040                                 device.getId(),
041                                 deviceTime);
042        }
043
044        private PenEvent(Pen pen, byte deviceId, long deviceTime){
045                this.pen=pen;
046                this.deviceId=deviceId;
047                this.deviceTime=deviceTime;
048        }
049
050        static final class Dummy
051                extends PenEvent{
052                Dummy(){
053                        super(null, (byte)0, 0);
054                }
055                @Override
056                void copyTo(PenState penState){}
057                @Override
058                void dispatch(){}
059        }
060
061        /**
062        Returns the time in milliseconds of when this event was scheduled by the {@link Pen}.
063        */
064        public long getTime() {
065                return time;
066        }
067
068        abstract void copyTo(PenState penState);
069
070        abstract void dispatch();
071
072        /**
073        Returns the id of the {@link PenDevice} which generated this event.
074
075        @see #getDevice()
076        @see PenManager#getDevice(byte)
077        */
078        public byte getDeviceId(){
079                return deviceId;
080        }
081
082        /**
083        @throws IllegalStateException if the {@link #pen} is null. {@code pen} is null after deserialization.
084        */
085        public PenDevice getDevice(){
086                if(pen==null)
087                        throw new IllegalStateException();
088                return pen.penManager.getDevice(deviceId);
089        }
090
091        /**
092        Returns the timestamp in milliseconds of when this event ocurred in the {@link PenDevice}. The value returned was measured since some fixed but arbitrary time imposed by the {@link PenDevice}.
093
094        @see #getDeviceId()
095        @see #getTime()
096        */
097        public long getDeviceTime(){
098                return deviceTime;
099        }
100        
101        /**
102        @see PenOwner#evalPenEventTag(PenEvent)
103        */
104        void setPenOwnerTag(Object penOwnerTag){
105                this.penOwnerTag=penOwnerTag;
106        }
107        
108        Object getPenOwnerTag(){
109                return penOwnerTag;
110        }
111
112        @Override
113        public String toString(){
114                return "[PenEvent: deviceId="+deviceId+", deviceTime="+deviceTime+", time="+time+"]";
115        }
116
117        private void readObject(ObjectInputStream in)
118        throws IOException, ClassNotFoundException {
119                try{
120                        ObjectInputStream.GetField fields = in.readFields();
121                        time=fields.get("time", 0l);
122                        //v Backwards compatibility:
123                        //vv deviceId and deviceTime are new, provide better defaults:
124                        //if(fields.defaulted("deviceId"))
125                        //deviceIdField.getField().set(this, fields.get("deviceId", (byte)0));
126                        if(fields.defaulted("deviceTime"))
127                                deviceTimeField.getField().set(this, fields.get("deviceTime", time));
128                        //^^
129                        //^
130                }catch(IllegalAccessException ex){
131                        throw new AssertionError(ex);
132                }
133        }
134
135        static final AccessibleField deviceIdField=new AccessibleField(PenEvent.class, "deviceId");
136        static final AccessibleField deviceTimeField=new AccessibleField(PenEvent.class, "deviceTime");
137}