public void setNegotiatorState(JingleNegotiatorState stateIs) {

    final JingleNegotiatorState stateWas = state;

    LOGGER.debug(
        "Negotiator state change: "
            + stateWas
            + "->"
            + stateIs
            + "("
            + this.getClass().getSimpleName()
            + ")");

    switch (stateIs) {
      case PENDING:
        break;

      case FAILED:
        break;

      case SUCCEEDED:
        break;

      default:
        break;
    }

    state = stateIs;
  }
/**
 * Basic Jingle negotiator.
 *
 * <p>
 *
 * <p>JingleNegotiator implements some basic behavior for every Jingle negotiation. It implements a
 * "state" pattern: each stage should process Jingle packets and act depending on the current state
 * in the negotiation...
 *
 * <p>
 *
 * @author Alvaro Saurin
 * @author Jeff Williams
 */
public abstract class JingleNegotiator {

  private static final SmackLogger LOGGER = SmackLogger.getLogger(JingleNegotiator.class);

  // private Connection connection; // The connection associated

  protected JingleSession session;

  private final List<JingleListener> listeners = new ArrayList<JingleListener>();

  private String expectedAckId;

  private JingleNegotiatorState state;

  private boolean isStarted;

  /** Default constructor. */
  public JingleNegotiator() {
    this(null);
  }

  /**
   * Default constructor with a Connection
   *
   * @param connection the connection associated
   */
  public JingleNegotiator(JingleSession session) {
    this.session = session;
    state = JingleNegotiatorState.PENDING;
  }

  /**
   * Add expected ID
   *
   * @param id
   */
  public void addExpectedId(String id) {
    expectedAckId = id;
  }

  /**
   * Add a Jingle session listener to listen to incoming session requests.
   *
   * @param li The listener
   * @see org.jivesoftware.smackx.jingle.listeners.JingleListener
   */
  public void addListener(JingleListener li) {
    synchronized (listeners) {
      listeners.add(li);
    }
  }

  /** Close the negotiation. */
  public void close() {}

  /**
   * Dispatch an incoming packet.
   *
   * <p>The negotiators form a tree relationship that roughly matches the Jingle packet format:
   *
   * <p>JingleSession Content Negotiator Media Negotiator Transport Negotiator Content Negotiator
   * Media Negotiator Transport Negotiator
   *
   * <p><jingle> <content> <description> <transport> <content> <description> <transport>
   *
   * <p>This way, each segment of a Jingle packet has a corresponding negotiator that know how to
   * deal with that part of the Jingle packet. It also allows us to support Jingle packets of
   * arbitraty complexity.
   *
   * <p>Each parent calls dispatchIncomingPacket for each of its children. The children then pass
   * back a List<> of results that will get sent when we reach the top level negotiator
   * (JingleSession).
   *
   * @param iq the packet received
   * @param id the ID of the response that will be sent
   * @return the new packet to send (either a Jingle or an IQ error).
   * @throws XMPPException
   */
  public abstract List<IQ> dispatchIncomingPacket(IQ iq, String id) throws XMPPException;

  /** Each of the negotiators has their individual behavior when they start. */
  protected abstract void doStart();

  // Acks management

  public Connection getConnection() {
    if (session != null) {
      return session.getConnection();
    } else {
      return null;
    }
  }

  /**
   * Get a copy of the listeners
   *
   * @return a copy of the listeners
   */
  protected List<JingleListener> getListenersList() {
    ArrayList<JingleListener> result;

    synchronized (listeners) {
      result = new ArrayList<JingleListener>(listeners);
    }

    return result;
  }

  public JingleNegotiatorState getNegotiatorState() {
    return state;
  }

  // Listeners

  /**
   * Get the XMPP connection associated with this negotiation.
   *
   * @return the connection
   */
  public JingleSession getSession() {
    return session;
  }

  /**
   * Check if the passed ID is the expected ID
   *
   * @param id
   * @return
   */
  public boolean isExpectedId(String id) {
    if (id != null) {
      return id.equals(expectedAckId);
    } else {
      return false;
    }
  }

  public boolean isStarted() {
    return isStarted;
  }

  /**
   * Remove and expected ID
   *
   * @param id
   */
  public void removeExpectedId(String id) {
    addExpectedId((String) null);
  }

  /**
   * Removes a Jingle session listener.
   *
   * @param li The jingle session listener to be removed
   * @see org.jivesoftware.smackx.jingle.listeners.JingleListener
   */
  public void removeListener(JingleListener li) {
    synchronized (listeners) {
      listeners.remove(li);
    }
  }

  public void setNegotiatorState(JingleNegotiatorState stateIs) {

    final JingleNegotiatorState stateWas = state;

    LOGGER.debug(
        "Negotiator state change: "
            + stateWas
            + "->"
            + stateIs
            + "("
            + this.getClass().getSimpleName()
            + ")");

    switch (stateIs) {
      case PENDING:
        break;

      case FAILED:
        break;

      case SUCCEEDED:
        break;

      default:
        break;
    }

    state = stateIs;
  }

  /**
   * Set the XMPP connection associated.
   *
   * @param connection the connection to set
   */
  public void setSession(JingleSession session) {
    this.session = session;
  }

  public void start() {
    isStarted = true;
    doStart();
  }
}