001package edu.wpi.first.wpilibj.networktables2;
002
003import edu.wpi.first.wpilibj.networktables2.AbstractNetworkTableEntryStore.TableListenerManager;
004import edu.wpi.first.wpilibj.networktables2.client.*;
005import edu.wpi.first.wpilibj.networktables2.type.*;
006import edu.wpi.first.wpilibj.networktables2.util.*;
007import edu.wpi.first.wpilibj.tables.*;
008
009/**
010 * represents a node (either a client or a server) in a network tables 2.0
011 * <br>
012 * implementers of the class must ensure that they call {@link #init(NetworkTableTransactionPool, AbstractNetworkTableEntryStore)} before calling any other methods on this class
013 * 
014 * @author Mitchell
015 *
016 */
017public abstract class NetworkTableNode implements TableListenerManager, ClientConnectionListenerManager, IRemote{
018
019        protected AbstractNetworkTableEntryStore entryStore;
020        
021
022        protected final void init(AbstractNetworkTableEntryStore entryStore) {
023                this.entryStore = entryStore;
024        }
025        
026        /**
027         * @return the entry store used by this node
028         */
029        public AbstractNetworkTableEntryStore getEntryStore(){
030                return entryStore;
031        }
032
033        
034        
035        public void putBoolean(String name, boolean value){
036                putValue(name, DefaultEntryTypes.BOOLEAN, value?Boolean.TRUE:Boolean.FALSE);
037        }
038        public boolean getBoolean(String name) throws TableKeyNotDefinedException{
039                NetworkTableEntry entry = entryStore.getEntry(name);
040                if(entry==null)
041                        throw new TableKeyNotDefinedException(name);
042                return ((Boolean)entry.getValue()).booleanValue();
043        }
044
045        public void putDouble(String name, double value){
046                putValue(name, DefaultEntryTypes.DOUBLE, new Double(value));//TODO don't make a new double every time
047        }
048        public double getDouble(String name) throws TableKeyNotDefinedException{
049                NetworkTableEntry entry = entryStore.getEntry(name);
050                if(entry==null)
051                        throw new TableKeyNotDefinedException(name);
052                return ((Double)entry.getValue()).doubleValue();
053        }
054
055        public void putString(String name, String value){
056                putValue(name, DefaultEntryTypes.STRING, value);
057        }
058        public String getString(String name) throws TableKeyNotDefinedException{
059                NetworkTableEntry entry = entryStore.getEntry(name);
060                if(entry==null)
061                        throw new TableKeyNotDefinedException(name);
062                return ((String)entry.getValue());
063        }
064        
065        public void putComplex(String name, ComplexData value){
066            putValue(name, value.getType(), value);
067        }
068        
069        public void retrieveValue(String name, Object externalData) throws TableKeyNotDefinedException{
070            synchronized(entryStore){
071                NetworkTableEntry entry = entryStore.getEntry(name);
072                if(entry==null)
073                    throw new TableKeyNotDefinedException(name);
074                NetworkTableEntryType entryType = entry.getType();
075                if(!(entryType instanceof ComplexEntryType))
076                    throw new TableKeyExistsWithDifferentTypeException(name, entryType, "Is not a complex data type");
077                ComplexEntryType complexType = (ComplexEntryType)entryType;
078                complexType.exportValue(name, entry.getValue(), externalData);
079            }
080        }
081        
082        
083        
084        
085        public void putValue(String name, Object value) throws IllegalArgumentException{
086            if(value instanceof Double){
087                    putValue(name, DefaultEntryTypes.DOUBLE, value);
088            } else if (value instanceof String){
089                    putValue(name, DefaultEntryTypes.STRING, value);
090            } else if(value instanceof Boolean){
091                    putValue(name, DefaultEntryTypes.BOOLEAN, value);
092            } else if(value instanceof ComplexData){
093                    putValue(name, ((ComplexData)value).getType(), value);
094            } else if(value==null) {
095                throw new NullPointerException("Cannot put a null value into networktables");
096            } else {
097                throw new IllegalArgumentException("Invalid Type");
098            }
099        }
100        
101        /**
102         * Put a value with a specific network table type
103         * @param name the name of the entry to associate with the given value
104         * @param type the type of the entry
105         * @param value the actual value of the entry
106         */
107        public void putValue(String name, NetworkTableEntryType type, Object value){
108            if(type instanceof ComplexEntryType){
109                synchronized(entryStore){//must sync because use get
110                    ComplexEntryType entryType = (ComplexEntryType)type;
111                    NetworkTableEntry entry = entryStore.getEntry(name);
112                    if(entry!=null)
113                        entryStore.putOutgoing(entry, entryType.internalizeValue(entry.name, value, entry.getValue()));
114                    else
115                        entryStore.putOutgoing(name, type, entryType.internalizeValue(name, value, null));
116                }
117            }
118            else
119                entryStore.putOutgoing(name, type, value);
120        }
121        
122        public void putValue(NetworkTableEntry entry, Object value){
123        if(entry.getType() instanceof ComplexEntryType){
124            synchronized(entryStore){//must sync because use get
125                ComplexEntryType entryType = (ComplexEntryType)entry.getType();
126                entryStore.putOutgoing(entry, entryType.internalizeValue(entry.name, value, entry.getValue()));
127            }
128        }
129        else
130                entryStore.putOutgoing(entry, value);
131        }
132        
133        public Object getValue(String name) throws TableKeyNotDefinedException{//TODO don't allow get of complex types
134            synchronized(entryStore){
135                NetworkTableEntry entry = entryStore.getEntry(name);
136                if(entry == null)
137                        throw new TableKeyNotDefinedException(name);
138                return entry.getValue();
139            }
140        }
141        
142        
143        /**
144         * @param key the key to check for existence
145         * @return true if the table has the given key
146         */
147        public boolean containsKey(final String key){
148                return entryStore.getEntry(key)!=null;
149        }
150
151        /**
152         * close all networking activity related to this node
153         */
154        public abstract void close();
155        
156        private final List remoteListeners = new List();
157        public void addConnectionListener(IRemoteConnectionListener listener, boolean immediateNotify) {
158                remoteListeners.add(listener);
159                if(isConnected())
160                        listener.connected(this);
161                else
162                        listener.disconnected(this);
163        }
164        public void removeConnectionListener(IRemoteConnectionListener listener) {
165                remoteListeners.remove(listener);
166        }
167        public void fireConnectedEvent(){
168                for(int i = 0; i<remoteListeners.size(); ++i)
169                        ((IRemoteConnectionListener)remoteListeners.get(i)).connected(this);
170        }
171        public void fireDisconnectedEvent(){
172                for(int i = 0; i<remoteListeners.size(); ++i)
173                        ((IRemoteConnectionListener)remoteListeners.get(i)).disconnected(this);
174        }
175        
176
177        private final List tableListeners = new List();
178        public void addTableListener(ITableListener listener, boolean immediateNotify) {
179                tableListeners.add(listener);
180                if(immediateNotify)
181                        entryStore.notifyEntries(null, listener);
182        }
183        public void removeTableListener(ITableListener listener) {
184                tableListeners.remove(listener);
185        }
186        public void fireTableListeners(String key, Object value, boolean isNew){
187                for(int i = 0; i<tableListeners.size(); ++i)
188                        ((ITableListener)tableListeners.get(i)).valueChanged(null, key, value, isNew);
189        }
190}