/*
 * Decompiled with CFR 0.152.
 */
package org.jivesoftware.smack;

import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.Random;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.AbstractConnectionListener;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPConnectionRegistry;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.StreamError;
import org.jivesoftware.smack.util.Async;

public class ReconnectionManager {
    private static final Logger LOGGER = Logger.getLogger(ReconnectionManager.class.getName());
    private static final Map<AbstractXMPPConnection, ReconnectionManager> INSTANCES = new WeakHashMap<AbstractXMPPConnection, ReconnectionManager>();
    private static boolean enabledPerDefault;
    private final WeakReference<AbstractXMPPConnection> weakRefConnection;
    private final int randomBase = new Random().nextInt(13) + 2;
    private final Runnable reconnectionRunnable;
    private boolean automaticReconnectEnabled = false;
    boolean done = false;
    private Thread reconnectionThread;
    private final ConnectionListener connectionListener = new AbstractConnectionListener(){

        @Override
        public void connectionClosed() {
            ReconnectionManager.this.done = true;
        }

        @Override
        public void authenticated(XMPPConnection connection, boolean resumed) {
            ReconnectionManager.this.done = false;
        }

        @Override
        public void connectionClosedOnError(Exception e) {
            XMPPException.StreamErrorException xmppEx;
            StreamError error;
            ReconnectionManager.this.done = false;
            if (!ReconnectionManager.this.isAutomaticReconnectEnabled()) {
                return;
            }
            if (e instanceof XMPPException.StreamErrorException && StreamError.Condition.conflict == (error = (xmppEx = (XMPPException.StreamErrorException)e).getStreamError()).getCondition()) {
                return;
            }
            ReconnectionManager.this.reconnect();
        }
    };

    public static synchronized ReconnectionManager getInstanceFor(AbstractXMPPConnection connection) {
        ReconnectionManager reconnectionManager = INSTANCES.get(connection);
        if (reconnectionManager == null) {
            reconnectionManager = new ReconnectionManager(connection);
            INSTANCES.put(connection, reconnectionManager);
        }
        return reconnectionManager;
    }

    public static void setEnabledPerDefault(boolean enabled) {
        enabledPerDefault = enabled;
    }

    public static boolean getEnabledPerDefault() {
        return enabledPerDefault;
    }

    private ReconnectionManager(AbstractXMPPConnection connection) {
        this.weakRefConnection = new WeakReference<AbstractXMPPConnection>(connection);
        this.reconnectionRunnable = new Thread(){
            private int attempts = 0;

            private int timeDelay() {
                ++this.attempts;
                if (this.attempts > 13) {
                    return ReconnectionManager.this.randomBase * 6 * 5;
                }
                if (this.attempts > 7) {
                    return ReconnectionManager.this.randomBase * 6;
                }
                return ReconnectionManager.this.randomBase;
            }

            @Override
            public void run() {
                AbstractXMPPConnection connection = (AbstractXMPPConnection)ReconnectionManager.this.weakRefConnection.get();
                if (connection == null) {
                    return;
                }
                while (ReconnectionManager.this.isReconnectionPossible(connection)) {
                    int remainingSeconds = this.timeDelay();
                    while (ReconnectionManager.this.isReconnectionPossible(connection) && remainingSeconds > 0) {
                        try {
                            Thread.sleep(1000L);
                            --remainingSeconds;
                            for (ConnectionListener listener : connection.connectionListeners) {
                                listener.reconnectingIn(remainingSeconds);
                            }
                        }
                        catch (InterruptedException e) {
                            LOGGER.log(Level.FINE, "waiting for reconnection interrupted", e);
                            break;
                        }
                    }
                    for (ConnectionListener listener : connection.connectionListeners) {
                        listener.reconnectingIn(0);
                    }
                    try {
                        if (!ReconnectionManager.this.isReconnectionPossible(connection)) continue;
                        connection.connect();
                    }
                    catch (Exception e) {
                        for (ConnectionListener listener : connection.connectionListeners) {
                            listener.reconnectionFailed(e);
                        }
                    }
                }
            }
        };
        if (ReconnectionManager.getEnabledPerDefault()) {
            this.enableAutomaticReconnection();
        }
    }

    public synchronized void enableAutomaticReconnection() {
        if (this.automaticReconnectEnabled) {
            return;
        }
        XMPPConnection connection = (XMPPConnection)this.weakRefConnection.get();
        if (connection == null) {
            throw new IllegalStateException("Connection instance no longer available");
        }
        connection.addConnectionListener(this.connectionListener);
        this.automaticReconnectEnabled = true;
    }

    public synchronized void disableAutomaticReconnection() {
        if (!this.automaticReconnectEnabled) {
            return;
        }
        XMPPConnection connection = (XMPPConnection)this.weakRefConnection.get();
        if (connection == null) {
            throw new IllegalStateException("Connection instance no longer available");
        }
        connection.removeConnectionListener(this.connectionListener);
        this.automaticReconnectEnabled = false;
    }

    public boolean isAutomaticReconnectEnabled() {
        return this.automaticReconnectEnabled;
    }

    private boolean isReconnectionPossible(XMPPConnection connection) {
        return !this.done && !connection.isConnected() && this.isAutomaticReconnectEnabled();
    }

    private synchronized void reconnect() {
        XMPPConnection connection = (XMPPConnection)this.weakRefConnection.get();
        if (connection == null) {
            LOGGER.fine("Connection is null, will not reconnect");
            return;
        }
        if (this.reconnectionThread != null && this.reconnectionThread.isAlive()) {
            return;
        }
        this.reconnectionThread = Async.go(this.reconnectionRunnable, "Smack Reconnection Manager (" + connection.getConnectionCounter() + ')');
    }

    static {
        XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener(){

            @Override
            public void connectionCreated(XMPPConnection connection) {
                if (connection instanceof AbstractXMPPConnection) {
                    ReconnectionManager.getInstanceFor((AbstractXMPPConnection)connection);
                }
            }
        });
        enabledPerDefault = false;
    }
}
