package org.jivesoftware.smack.filter;

import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Stanza;
import org.jxmpp.jid.DomainBareJid;
import org.jxmpp.jid.FullJid;
import org.jxmpp.jid.Jid;

public class IQReplyFilter implements StanzaFilter {
   private static final Logger LOGGER = Logger.getLogger(IQReplyFilter.class.getName());
   private final StanzaFilter iqAndIdFilter;
   private final OrFilter fromFilter;
   private final Jid to;
   private final FullJid local;
   private final DomainBareJid server;
   private final String packetId;

   public IQReplyFilter(IQ iqPacket, XMPPConnection conn) {
      if (!iqPacket.isRequestIQ()) {
         throw new IllegalArgumentException("IQ must be a request IQ, i.e. of type 'get' or 'set'.");
      } else {
         this.to = iqPacket.getTo();
         this.local = conn.getUser();
         if (this.local == null) {
            throw new IllegalArgumentException("Must have a local (user) JID set. Either you didn't configure one or you where not connected at least once");
         } else {
            this.server = conn.getServiceName();
            this.packetId = iqPacket.getStanzaId();
            StanzaFilter iqFilter = new OrFilter(new StanzaFilter[]{IQTypeFilter.ERROR, IQTypeFilter.RESULT});
            StanzaFilter idFilter = new StanzaIdFilter(iqPacket);
            this.iqAndIdFilter = new AndFilter(new StanzaFilter[]{iqFilter, idFilter});
            this.fromFilter = new OrFilter();
            this.fromFilter.addFilter(FromMatchesFilter.createFull(this.to));
            if (this.to == null) {
               this.fromFilter.addFilter(FromMatchesFilter.createBare(this.local));
               this.fromFilter.addFilter(FromMatchesFilter.createFull(this.server));
            } else if (this.to.equals((CharSequence)this.local.asBareJid())) {
               this.fromFilter.addFilter(FromMatchesFilter.createFull((Jid)null));
            }

         }
      }
   }

   public boolean accept(Stanza packet) {
      if (!this.iqAndIdFilter.accept(packet)) {
         return false;
      } else if (this.fromFilter.accept(packet)) {
         return true;
      } else {
         String msg = String.format("Rejected potentially spoofed reply to IQ-packet. Filter settings: packetId=%s, to=%s, local=%s, server=%s. Received packet with from=%s", this.packetId, this.to, this.local, this.server, packet.getFrom());
         LOGGER.log(Level.WARNING, msg, packet);
         return false;
      }
   }

   public String toString() {
      StringBuilder sb = new StringBuilder();
      sb.append(this.getClass().getSimpleName());
      sb.append(": iqAndIdFilter (").append(this.iqAndIdFilter.toString()).append("), ");
      sb.append(": fromFilter (").append(this.fromFilter.toString()).append(')');
      return sb.toString();
   }
}
