001package csheets.ext.share.core;
002
003import java.io.*;
004import java.net.*;
005import java.util.*;
006import java.util.logging.*;
007
008import csheets.core.Cell;
009import csheets.core.formula.compiler.FormulaCompilationException;
010
011/**
012 * Class that implement the client in the extension
013 * 
014 * @see Runnable
015 * @author Andre
016 * 
017 */
018public class Client extends Observable implements Runnable {
019        /** the ip of the server */
020        private String IP;
021        /** the port of the connection */
022        private int port;
023        /** the cell where the program will copy */
024        private Cell cellStart;
025        /** the connection to the server */
026        private Connections connection;
027        /** the connection password */
028        private String password;
029        /** the observer class */
030        private Observer observer;
031        /** the cell listener */
032        private final CellNetworkListenerClient listener = new CellNetworkListenerClient();
033
034        /** share properties (writable wr) or read-only(r) */
035        private String properties;
036
037        /**
038         * Create a new client
039         */
040        public Client() {
041        }
042
043        /**
044         * Create internaly a new client
045         * 
046         * @param IP
047         *            of the server
048         * @param port
049         *            the port of the connection
050         * @param cellStart
051         *            the cell where the program will copy
052         * @param password
053         *            the connection password
054         * @param observer
055         *            the observer class
056         */
057        private Client(String IP, int port, Cell cellStart, String password,
058                        Observer observer) {
059                this.IP = IP;
060                this.port = port;
061                this.cellStart = cellStart;
062                this.password = password;
063                this.observer = observer;
064        }
065
066        /**
067         * Create internaly a new client
068         * 
069         * @param connection
070         *            the connection to the server
071         * @param cellStart
072         *            the cell where the program will copy
073         * @param observer
074         *            the connection observer
075         * @param password
076         *            the password connection
077         */
078        private Client(Connections connection, Cell cellStart, Observer observer,
079                        String password) {
080                this.connection = connection;
081                this.cellStart = cellStart;
082                this.observer = observer;
083                this.password = password;
084        }
085
086        /**
087         * Method that will start the client and receive cells throw network
088         * 
089         * @param IP
090         *            the server ip
091         * @param port
092         *            the connection port of the server
093         * @param cellStart
094         *            cell where we paste the content of the shared cells
095         * @param password
096         *            the connection password
097         * @param observer
098         *            the observer class
099         */
100        public void startClient(String IP, int port, Cell cellStart,
101                        String password, Observer observer) {
102                Thread thr = new Thread(new Client(IP, port, cellStart, password,
103                                observer));
104                thr.start();
105        }
106
107        /**
108         * Method that will start the client and receive cells throw network
109         * 
110         * @param connection
111         *            the connection to the server
112         * @param cellStart
113         *            cell where we paste the content of the shared cells
114         * @param observer
115         *            the observer class
116         * @param password
117         *            the password connection
118         */
119        public void startClient(Connections connection, Cell cellStart,
120                        Observer observer, String password) {
121                Thread thr = new Thread(new Client(connection, cellStart, observer,
122                                password));
123                thr.start();
124        }
125
126        /**
127         * The method that will treat the incoming cells
128         * 
129         * @param cellStart
130         *            cell where we paste the content
131         * @param cli
132         *            the socket of connection
133         * @param password
134         *            the connection password
135         * @throws IOException
136         *             throw this exception if the I/O have errors
137         * @throws ClassNotFoundException
138         *             throw this exception if the object passed throw network was
139         *             invalid
140         * @throws FormulaCompilationException
141         *             throw if the cell does not respect the formula compiler
142         */
143        private synchronized void receive(Cell cellStart, Socket cli,
144                        String password) throws IOException, ClassNotFoundException,
145                        FormulaCompilationException {
146                boolean isCell = true;
147                int cellStartRow = cellStart.getAddress().getRow();
148                int cellStartColumn = cellStart.getAddress().getColumn();
149                OutputStream out = cli.getOutputStream();
150                DataOutputStream outStream = new DataOutputStream(out);
151                outStream.writeUTF(password);
152                DataInputStream receiveProps = new DataInputStream(cli.getInputStream());
153                this.properties = receiveProps.readUTF();
154
155                while (isCell) {
156                        ObjectInputStream inStream = new ObjectInputStream(
157                                        cli.getInputStream());
158                        CellNetwork cell = (CellNetwork) inStream.readObject();
159                        if (cell.isCell()) {
160
161                                this.cellStart
162                                                .getSpreadsheet()
163                                                .getCell(cellStartColumn + cell.getColumn(),
164                                                                cellStartRow + cell.getRow())
165                                                .setContent(cell.getContent());
166
167                                this.cellStart
168                                                .getSpreadsheet()
169                                                .getCell(cellStartColumn + cell.getColumn(),
170                                                                cellStartRow + cell.getRow())
171                                                .addCellListener(listener);
172
173                        } else {
174                                isCell = false;
175                        }
176                }
177                outStream.writeUTF("Close yourself");
178
179        }
180
181        /**
182         * Method that when changes occurred on cells of client's share, listener
183         * changes a flag value and this method can run and send that update to the
184         * server
185         * 
186         * @param sock
187         *            the client socket
188         * @exception IOException
189         *                of a I/O exception occurs
190         */
191        public synchronized void sendToServer(Socket sock) throws IOException,
192                        InterruptedException {
193
194                while (true) {
195                        Thread.sleep(100);
196
197                        if (listener.getFlag() == true) {
198
199                                OutputStream out = sock.getOutputStream();
200                                DataOutputStream outStream = new DataOutputStream(out);
201                                outStream.writeUTF("send me updated data");
202
203                                CellNetwork cell = new CellNetwork(listener.getCell()
204                                                .getContent(), listener.getCell().getAddress().getRow()
205                                                - cellStart.getAddress().getRow(), listener.getCell()
206                                                .getAddress().getColumn()
207                                                - cellStart.getAddress().getColumn(), true);
208
209                                ObjectOutputStream objectOut = new ObjectOutputStream(
210                                                sock.getOutputStream());
211                                objectOut.writeObject(cell);
212
213                        }
214                        listener.setFlag(false);
215
216                }
217
218        }
219
220        /**
221         * Running thread
222         */
223        @Override
224        public void run() {
225                try {
226
227                        addObserver(observer);
228                        Socket cli;
229                        if (IP != null) {
230                                cli = new Socket(IP, port);
231                        } else
232                                cli = new Socket(connection.getIP(), connection.getPort());
233                        receive(cellStart, cli, password);
234                        Thread thr = new Thread(new ThreadClient(cellStart, cli, listener,
235                                        observer));
236                        thr.start();
237
238                        while (true) {
239                                if (this.properties.equals("wr"))
240
241                                        sendToServer(cli);
242                        }
243
244                } catch (UnknownHostException e) {
245
246                        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, e);
247                        setChanged();
248                        notifyObservers();
249                        clearChanged();
250                } catch (IOException e) {
251
252                        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, e);
253                        setChanged();
254                        notifyObservers();
255                        clearChanged();
256                } catch (ClassNotFoundException e) {
257                        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, e);
258                        setChanged();
259                        notifyObservers();
260                        clearChanged();
261                } catch (FormulaCompilationException e) {
262                        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, e);
263                        setChanged();
264                        notifyObservers();
265                        clearChanged();
266                } catch (InterruptedException e) {
267                        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, e);
268                        setChanged();
269                        notifyObservers();
270                        clearChanged();
271                }
272        }
273}