package net.yeputons.spbau.spring2016.torrent;

import net.yeputons.spbau.spring2016.torrent.protocol.Request;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.io.IOException;
import java.net.SocketAddress;

public class FirmTorrentConnection implements Closeable {
    private static final Logger LOG = LoggerFactory.getLogger(FirmTorrentConnection.class);
    private final SocketAddress address;
    private TorrentConnection connection;

    public FirmTorrentConnection(SocketAddress address) {
        this.address = address;
        LOG.debug("Created FirmTorrentConnection with address " + address.toString());
    }

    @Override
    public void close() throws IOException {
        if (connection != null) {
            connection.close();
        }
    }

    private void ensureConnection() throws IOException {
        if (connection != null && !connection.getSocket().isClosed()) {
            return;
        }
        if (connection != null) {
            LOG.debug("Reconnecting to " + address.toString());
        }
        try {
            connection = TorrentConnection.connect(address);
        } catch (IOException e) {
            String message;
            if (connection != null) {
                message = "Unable to reconnect to " + address.toString();
            } else {
                message = "Unable to connect to " + address.toString();
            }
            throw new IOException(message, e);
        }
    }

    public synchronized <T> T makeRequest(Request<T> r) throws IOException {
        ensureConnection();
        try {
            return connection.makeRequest(r);
        } catch (IOException e) {
            LOG.warn("Caught IOException, closing connection, rethrowing exception");
            try {
                connection.close();
            } catch (Exception e1) {
                LOG.warn("Caught IOException while closing connection, suppress");
                e.addSuppressed(e1);
            }
            throw e;
        }
    }
}

@@ -162,16 +162,99 @@
 ctory;%0A%0A
+import java.beans.PropertyChangeListener;%0Aimport java.beans.PropertyChangeSupport;%0A
 import j
@@ -568,327 +568,1273 @@
 on;%0A
-%0A    public FirmTorrentConnection(SocketAddress address) %7B%0A        this.address = address;%0A        LOG.debug(%22Created FirmTorrentConnection with address %22 + address.toString());%0A    %7D%0A%0A    @Override%0A    public void close() throws IOException %7B%0A        if (connection != null) %7B%0A            connection.close();%0A        %7D
+    private State state = State.DISCONNECTED;%0A    private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);%0A%0A    public enum State %7B DISCONNECTED, CONNECTING, CONNECTED %7D%0A%0A    public FirmTorrentConnection(SocketAddress address) %7B%0A        this.address = address;%0A        LOG.debug(%22Created FirmTorrentConnection with address %22 + address.toString());%0A    %7D%0A%0A    public synchronized void addPropertyChangeListener(PropertyChangeListener listener) %7B%0A        propertyChangeSupport.addPropertyChangeListener(listener);%0A    %7D%0A%0A    public synchronized void firePropertyChange(String key, Object oldValue, Object newValue) %7B%0A        propertyChangeSupport.firePropertyChange(key, oldValue, newValue);%0A    %7D%0A%0A    public synchronized void removePropertyChangeListener(PropertyChangeListener listener) %7B%0A        propertyChangeSupport.removePropertyChangeListener(listener);%0A    %7D%0A%0A    @Override%0A    public void close() throws IOException %7B%0A        if (connection != null) %7B%0A            connection.close();%0A        %7D%0A    %7D%0A%0A    private void changeState(State newState) %7B%0A        State oldState = state;%0A        state = newState;%0A        firePropertyChange(%22state%22, oldState, newState);%0A    %7D%0A%0A    public State getState() %7B%0A        return state;
 %0A   
@@ -2110,32 +2110,75 @@
 %7D%0A        try %7B%0A
+            changeState(State.CONNECTING);%0A
             conn
@@ -2234,33 +2234,120 @@
     
-%7D catch (IOException e) %7B
+    changeState(State.CONNECTED);%0A        %7D catch (IOException e) %7B%0A            changeState(State.DISCONNECTED);
 %0A   
@@ -3156,32 +3156,77 @@
 ;%0A            %7D%0A
+            changeState(State.DISCONNECTED);%0A
             thro

add 'State' property and PropertyChangeListener support for it