/*_############################################################################
  _## 
  _##  SNMP4J-AgentX - AgentXRegEntry.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.master;

import org.snmp4j.agent.agentx.AgentXRegion;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.OID;

import java.io.Serializable;

/**
 * {@link AgentXRegEntry} represents an entry in the AgentX master agent registry.
 * @param <A>
 *     the address type of the associated master session.
 */
public class AgentXRegEntry<A extends Address> implements Comparable<AgentXRegEntry<A>>, Serializable {

    private static final long serialVersionUID = 7889656078544847560L;
    private final AgentXMasterSession<A> session;
    private final AgentXRegion region;
    private final int priority;
    private OctetString context;
    private final int timeout;
    private OID id;

    /**
     * Creates a new registry entry.
     * @param session
     *    the session associated with the entry.
     * @param region
     *    the region to register.
     * @param priority
     *    the priority (default is 127) of the registration.
     * @param context
     *    the SNMPv3 context.
     * @param timeout
     *    the region timeout in seconds.
     */
    public AgentXRegEntry(AgentXMasterSession<A> session,
                          AgentXRegion region,
                          int priority,
                          OctetString context,
                          int timeout) {
        this.session = session;
        this.region = region;
        this.priority = priority;
        this.context = context;
        if (this.context == null) {
            this.context = new OctetString();
        }
        this.timeout = timeout;
    }

    /**
     * Gets the context.
     * @return
     *    the SNMPv3 context associated with the region.
     */
    public OctetString getContext() {
        return context;
    }

    /**
     * Gets the priority of the registry entry.
     * @return
     *    the priority (lower value takes precedence)
     */
    public int getPriority() {
        return priority;
    }

    /**
     * Gets the MIB region registered.
     * @return
     *   the MIB region registered.
     */
    public AgentXRegion getRegion() {
        return region;
    }

    /**
     * Gets the {@link org.snmp4j.agent.agentx.AgentXSession}.
     * @return
     *    the AgentX session that registered this region.
     */
    public AgentXMasterSession<A> getSession() {
        return session;
    }

    /**
     * Gets the specific index (= the length of the lower bound {@link OID}).
     * @return
     *    the index that identifies how specific this region is (the highe the value the more specific).
     */
    public int getSpecific() {
        return region.getLowerBound().size();
    }

    /**
     * Gets the timeout for this region registration.
     * @return
     *    the timeout in seconds.
     */
    public int getTimeout() {
        return timeout;
    }

    /**
     * Compares this object with the specified object for order.
     *
     * @param other
     *         the AgentXRegEntry to be compared.
     *
     * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than
     * the specified object.
     */
    @Override
    public int compareTo(AgentXRegEntry<A> other) {
        int diff = other.getSpecific() - getSpecific();
        if (diff == 0) {
            diff = getPriority() - other.getPriority();
        }
/* The below is NOT correct since two registrations with the same specific
   subtree and priority must be deemed equal.
    if (diff == 0) {
      diff = getRegion().compareTo(other.getRegion());
    }
*/
        return diff;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof AgentXRegEntry) {
            @SuppressWarnings("unchecked")
            AgentXRegEntry<A> other = (AgentXRegEntry<A>) obj;
            return session.equals(other.session) &&
                    region.equals(other.region) &&
                    (compareTo(other) == 0);
        }
        return false;
    }

    public int hashCode() {
        return session.getSessionID() + region.getLowerBound().hashCode();
    }

    /**
     * Gets the index ID of the region.
     * @return
     *    the index ID.
     */
    public OID getId() {
        return id;
    }

    /**
     * Sets the index {@link OID} associated with this region entry.
     * @param id
     *    an index OID.
     */
    public void setId(OID id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return getClass().getName() + "[region=" + region +
                ",priority=" + priority +
                ",context=" + context +
                ",timeout=" + timeout +
                ",id=" + id +
                ",session=" + session + "]";
    }

}
