/*_############################################################################
  _## 
  _##  SNMP4J-AgentX - AgentXSession.java  
  _## 
  _##  Copyright (C) 2005-2026  Frank Fock (SNMP4J.org)
  _##  
  _##  This program is free software; you can redistribute it and/or modify
  _##  it under the terms of the GNU General Public License version 2 as 
  _##  published by the Free Software Foundation.
  _##
  _##  This program is distributed in the hope that it will be useful,
  _##  but WITHOUT ANY WARRANTY; without even the implied warranty of
  _##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  _##  GNU General Public License for more details.
  _##
  _##  You should have received a copy of the GNU General Public License
  _##  along with this program; if not, write to the Free Software
  _##  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
  _##  MA  02110-1301  USA
  _##  
  _##########################################################################*/

package org.snmp4j.agent.agentx;

import org.snmp4j.smi.Address;

import java.io.Serializable;
import java.nio.ByteOrder;
import java.util.List;

/**
 * The {@link AgentXSession} class represents an AgentX session.
 * @param <A>
 *     the address type of the associated AgentX connection.
 */
public class AgentXSession<A extends Address> implements Serializable {

    private static final long serialVersionUID = 2890153102679435259L;

    private int sessionID;
    private ByteOrder byteOrder;
    private byte timeout = AgentXProtocol.DEFAULT_TIMEOUT_SECONDS;
    private volatile int consecutiveTimeouts;
    private AgentXPeer<A> peer;
    private volatile boolean closed;

    /**
     * Creates a new {@link AgentXSession} from a session ID.
     * @param sessionID
     *    a unique session ID.
     */
    public AgentXSession(int sessionID) {
        this.sessionID = sessionID;
        this.consecutiveTimeouts = 0;
    }

    /**
     * Gets the byte order of this session.
     * @return
     *    the byte order.
     */
    public ByteOrder getByteOrder() {
        return byteOrder;
    }

    /**
     * Gets the {@link AgentXPeer} associated with this session.
     * @return
     *    an {@link AgentXPeer}.
     */
    public AgentXPeer<A> getPeer() {
        return peer;
    }

    /**
     * Gets the session ID.
     * @return
     *    the session ID.
     */
    public int getSessionID() {
        return sessionID;
    }

    /**
     * Gets the session timeout in seconds.
     * @return
     *    the timeout in sec.
     */
    public byte getTimeout() {
        return timeout;
    }

    /**
     * Reset the consecutive timeout counter to zero.
     */
    public void clearConsecutiveTimeouts() {
        consecutiveTimeouts = 0;
    }

    /**
     * Increase the consecutive timeout counter by one.
     */
    public synchronized void incConsecutiveTimeouts() {
        consecutiveTimeouts++;
    }

    /**
     * Gets the number of consecutive timeouts.
     * @return
     *    the timeouts count.
     */
    public int getConsecutiveTimeouts() {
        return consecutiveTimeouts;
    }

    /**
     * Checks if the session is closed.
     * @return
     *    {@code true} if the session is closed.
     */
    public boolean isClosed() {
        return closed;
    }

    /**
     * Sets the byte order (must not be modified while session is opened!).
     * @param byteOrder
     *    a byte order.
     */
    public void setByteOrder(ByteOrder byteOrder) {
        this.byteOrder = byteOrder;
    }

    /**
     * Sets the {@link AgentXPeer}.
     * @param peer
     *    the AgentX peer associated with this session.
     */
    public void setPeer(AgentXPeer<A> peer) {
        this.peer = peer;
    }

    /**
     * Sets the session ID.
     * @param sessionID
     *    a session ID.
     */
    public void setSessionID(int sessionID) {
        this.sessionID = sessionID;
    }

    /**
     * Sets the session timeout.
     * @param timeout
     *    a session timeout in seconds.
     */
    public void setTimeout(byte timeout) {
        this.timeout = timeout;
    }

    /**
     * Sets this session to closed.
     * @param closed
     *    {@code true} if the session should be marked as closed.
     */
    public void setClosed(boolean closed) {
        this.closed = closed;
    }

    /**
     * Creates a new {@link AgentXTarget} based on this session.
     * @return
     *    a new {@link AgentXTarget} to the session peer.
     */
    public AgentXTarget<A> createAgentXTarget() {
        return new AgentXTarget<>(getPeer().getAddress(), getTimeout() * 1000);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof AgentXSession) {
            return ((AgentXSession) obj).sessionID == sessionID;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return sessionID;
    }

    @Override
    public String toString() {
        return getClass().getName() + "[peer=" + peer + ",sessionID=" + sessionID +
                ",byteOrder=" + byteOrder + ",timeout=" + timeout +
                ",consecutiveTimeouts=" + consecutiveTimeouts +
                ",closed=" + closed + "]";
    }

}
