package org.jivesoftware.smack.sasl;

import javax.security.auth.callback.CallbackHandler;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.sasl.packet.SaslStreamElements;
import org.jivesoftware.smack.util.StringTransformer;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.stringencoder.Base64;
import org.jxmpp.jid.DomainBareJid;

public abstract class SASLMechanism implements Comparable<SASLMechanism> {
   public static final String CRAMMD5 = "CRAM-MD5";
   public static final String DIGESTMD5 = "DIGEST-MD5";
   public static final String EXTERNAL = "EXTERNAL";
   public static final String GSSAPI = "GSSAPI";
   public static final String PLAIN = "PLAIN";
   private static StringTransformer saslPrepTransformer;
   protected XMPPConnection connection;
   protected String authenticationId;
   protected DomainBareJid serviceName;
   protected String password;
   protected String host;

   public static void setSaslPrepTransformer(StringTransformer stringTransformer) {
      saslPrepTransformer = stringTransformer;
   }

   public final void authenticate(String username, String host, DomainBareJid serviceName, String password) throws SmackException, SmackException.NotConnectedException, InterruptedException {
      this.authenticationId = username;
      this.host = host;
      this.serviceName = serviceName;
      this.password = password;
      this.authenticateInternal();
      this.authenticate();
   }

   protected void authenticateInternal() throws SmackException {
   }

   public void authenticate(String host, DomainBareJid serviceName, CallbackHandler cbh) throws SmackException, SmackException.NotConnectedException, InterruptedException {
      this.host = host;
      this.serviceName = serviceName;
      this.authenticateInternal(cbh);
      this.authenticate();
   }

   protected abstract void authenticateInternal(CallbackHandler var1) throws SmackException;

   private final void authenticate() throws SmackException, SmackException.NotConnectedException, InterruptedException {
      byte[] authenticationBytes = this.getAuthenticationText();
      String authenticationText;
      if (authenticationBytes != null) {
         authenticationText = Base64.encodeToString(authenticationBytes);
      } else {
         authenticationText = "=";
      }

      this.connection.send(new SaslStreamElements.AuthMechanism(this.getName(), authenticationText));
   }

   protected abstract byte[] getAuthenticationText() throws SmackException;

   public final void challengeReceived(String challengeString, boolean finalChallenge) throws SmackException, SmackException.NotConnectedException, InterruptedException {
      byte[] challenge = Base64.decode(challengeString);
      byte[] response = this.evaluateChallenge(challenge);
      if (!finalChallenge) {
         SaslStreamElements.Response responseStanza;
         if (response == null) {
            responseStanza = new SaslStreamElements.Response();
         } else {
            responseStanza = new SaslStreamElements.Response(Base64.encodeToString(response));
         }

         this.connection.send(responseStanza);
      }
   }

   protected byte[] evaluateChallenge(byte[] challenge) throws SmackException {
      return null;
   }

   public final int compareTo(SASLMechanism other) {
      return this.getPriority() - other.getPriority();
   }

   public abstract String getName();

   public abstract int getPriority();

   public abstract void checkIfSuccessfulOrThrow() throws SmackException;

   public SASLMechanism instanceForAuthentication(XMPPConnection connection) {
      SASLMechanism saslMechansim = this.newInstance();
      saslMechansim.connection = connection;
      return saslMechansim;
   }

   protected abstract SASLMechanism newInstance();

   protected static byte[] toBytes(String string) {
      return StringUtils.toBytes(string);
   }

   protected static String saslPrep(String string) {
      StringTransformer stringTransformer = saslPrepTransformer;
      return stringTransformer != null ? stringTransformer.transform(string) : string;
   }
}
