package org.jivesoftware.smack;

import java.lang.ref.WeakReference;
import java.util.Iterator;
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.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();
   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() {
      public void connectionClosed() {
         ReconnectionManager.this.done = true;
      }

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

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

            ReconnectionManager.this.reconnect();
         }
      }
   };

   public static synchronized ReconnectionManager getInstanceFor(AbstractXMPPConnection connection) {
      ReconnectionManager 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(connection);
      this.reconnectionRunnable = new Thread() {
         private int attempts = 0;

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

         public void run() {
            AbstractXMPPConnection connection = (AbstractXMPPConnection)ReconnectionManager.this.weakRefConnection.get();
            if (connection != null) {
               while(ReconnectionManager.this.isReconnectionPossible(connection)) {
                  int remainingSeconds = this.timeDelay();

                  Iterator i$;
                  ConnectionListener listener;
                  while(ReconnectionManager.this.isReconnectionPossible(connection) && remainingSeconds > 0) {
                     try {
                        Thread.sleep(1000L);
                        --remainingSeconds;
                        i$ = connection.connectionListeners.iterator();

                        while(i$.hasNext()) {
                           listener = (ConnectionListener)i$.next();
                           listener.reconnectingIn(remainingSeconds);
                        }
                     } catch (InterruptedException var6) {
                        ReconnectionManager.LOGGER.log(Level.FINE, "waiting for reconnection interrupted", var6);
                        break;
                     }
                  }

                  i$ = connection.connectionListeners.iterator();

                  while(i$.hasNext()) {
                     listener = (ConnectionListener)i$.next();
                     listener.reconnectingIn(0);
                  }

                  try {
                     if (ReconnectionManager.this.isReconnectionPossible(connection)) {
                        connection.connect();
                     }
                  } catch (Exception var7) {
                     Exception e = var7;
                     Iterator i$x = connection.connectionListeners.iterator();

                     while(i$x.hasNext()) {
                        ConnectionListener listenerx = (ConnectionListener)i$x.next();
                        listenerx.reconnectionFailed(e);
                     }
                  }
               }

            }
         }
      };
      if (getEnabledPerDefault()) {
         this.enableAutomaticReconnection();
      }

   }

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

   public synchronized void disableAutomaticReconnection() {
      if (this.automaticReconnectEnabled) {
         XMPPConnection connection = (XMPPConnection)this.weakRefConnection.get();
         if (connection == null) {
            throw new IllegalStateException("Connection instance no longer available");
         } else {
            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");
      } else if (this.reconnectionThread == null || !this.reconnectionThread.isAlive()) {
         this.reconnectionThread = Async.go(this.reconnectionRunnable, "Smack Reconnection Manager (" + connection.getConnectionCounter() + ')');
      }
   }

   static {
      XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
         public void connectionCreated(XMPPConnection connection) {
            if (connection instanceof AbstractXMPPConnection) {
               ReconnectionManager.getInstanceFor((AbstractXMPPConnection)connection);
            }

         }
      });
      enabledPerDefault = false;
   }
}
