/*_############################################################################
  _## 
  _##  SNMP4J - RetrievalEvent.java  
  _## 
  _##  Copyright (C) 2003-2026  Frank Fock (SNMP4J.org)
  _##  
  _##  Licensed under the Apache License, Version 2.0 (the "License");
  _##  you may not use this file except in compliance with the License.
  _##  You may obtain a copy of the License at
  _##  
  _##      http://www.apache.org/licenses/LICENSE-2.0
  _##  
  _##  Unless required by applicable law or agreed to in writing, software
  _##  distributed under the License is distributed on an "AS IS" BASIS,
  _##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  _##  See the License for the specific language governing permissions and
  _##  limitations under the License.
  _##  
  _##########################################################################*/

package org.snmp4j.util;

import java.util.EventListener;
import java.util.EventObject;
import org.snmp4j.PDU;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.mp.SnmpConstants;
import java.util.Arrays;

/**
 * The {@code RetrievalEvent} is an abstract class representing the result
 * of one or more GET/GETNEXT/GETBULK requests.
 *
 * @author Frank Fock
 * @version 3.12.3
 * @since 1.8
 */
public abstract class RetrievalEvent extends EventObject {

    /**
     * The retrieval operation was successful.
     */
    public static final int STATUS_OK = SnmpConstants.SNMP_ERROR_SUCCESS;
    /**
     * A request to the agent timed out.
     */
    public static final int STATUS_TIMEOUT = SnmpConstants.SNMP_ERROR_TIMEOUT;
    /**
     * The agent failed to return the objects in lexicographic order.
     */
    public static final int STATUS_WRONG_ORDER = SnmpConstants.SNMP_ERROR_LEXICOGRAPHIC_ORDER;
    /**
     * A report has been received from the agent.
     * @see #getReportPDU()
     */
    public static final int STATUS_REPORT = SnmpConstants.SNMP_ERROR_REPORT;

    /**
     * The maximum number of to be retrieved has been reached. See {@link TableUtils#setRowLimit(int)}.
     */
    public static final int STATUS_ROW_LIMIT_REACHED = -5;

    /**
     * An exception occurred during the retrieval operation.
     * @see #getException()
     */
    public static final int STATUS_EXCEPTION = -4;
    private static final long serialVersionUID = 6592701899052543606L;

    protected VariableBinding[] vbs;
    protected int status = STATUS_OK;
    protected transient Object userObject;
    protected Exception exception;
    protected PDU reportPDU;

    protected RetrievalEvent(EventListener source, Object userObject) {
        super(source);
        this.userObject = userObject;
    }

    /**
     * Creates a retrieval event with a status.
     * @param source
     *    the source of the event.
     * @param userObject
     *    the user object or {@code null}.
     * @param status
     *    one of the status constants defined for this object.
     */
    RetrievalEvent(TreeUtils.TreeRequest source, Object userObject, int status) {
        this(source, userObject);
        this.status = status;
    }

    /**
     * Creates a retrieval event with an exception.
     * @param source
     *    the source of the event.
     * @param userObject
     *    the user object or {@code null}.
     * @param exception
     *    an exception instance.
     */
    RetrievalEvent(TreeUtils.TreeRequest source, Object userObject, Exception exception) {
        this(source, userObject);
        this.exception = exception;
        this.status = STATUS_EXCEPTION;
    }

    /**
     * Creates a retrieval event with a report PDU.
     * @param source
     *    the source of the event.
     * @param userObject
     *    the user object or {@code null}.
     * @param report
     *    a PDU of type {@link PDU#REPORT}.
     */
    RetrievalEvent(TreeUtils.TreeRequest source, Object userObject, PDU report) {
        this(source, userObject);
        this.reportPDU = report;
        this.status = STATUS_REPORT;
    }

    /**
     * Creates a retrieval event with row data.
     *
     * @param source
     *    the source of the event.
     * @param userObject
     *    the user object or {@code null}.
     * @param variableBindings
     *    an array of {@code VariableBinding} instances.
     */
    public RetrievalEvent(ResponseListener source, Object userObject,
                          VariableBinding[] variableBindings) {
        this(source, userObject);
        this.vbs = variableBindings;
    }

    /**
     * Gets the status of the table operation.
     * @return
     *    one of the status constants defined for this object.
     *    {@link #STATUS_OK} indicates success, all other values indicate
     *    failure of the operation which corresponds to an SNMP error status
     *    as defined by {@link org.snmp4j.PDU#getErrorStatus()}.
     */
    public int getStatus() {
        return status;
    }

    /**
     * Indicates whether the event reports an error or not.
     * @return
     *    {@code true} if the operation failed with an error.
     */
    public boolean isError() {
        return (status != STATUS_OK);
    }

    /**
     * Gets the user object that has been specified by the user when the retrieval
     * operation that fired this event has been requested.
     * @return
     *    an object instance if an user object has been specified or
     *    {@code null} otherwise.
     */
    public Object getUserObject() {
        return userObject;
    }

    /**
     * Gets the exception associated with this event.
     * @return
     *    an Exception instance if there has been an exception instance
     *    associated with this event ({@link #getStatus()} returns
     *    {@link #STATUS_EXCEPTION}), or {@code null} otherwise.
     */
    public Exception getException() {
        return exception;
    }

    /**
     * Gets the report PDU associated with this event.
     * @return
     *    a {@code ScopedPDU} instance if there has been a report PDU
     *    instance associated with this event ({@link #getStatus()} returns
     *    {@link #STATUS_REPORT}), or {@code null} otherwise.
     */
    public PDU getReportPDU() {
        return reportPDU;
    }

    /**
     * Returns a textual error message for the error.
     * @return
     *    an error message or an empty string if no error occurred.
     */
    public String getErrorMessage() {
        switch (status) {
            case STATUS_EXCEPTION: {
                return exception.getMessage();
            }
            case STATUS_REPORT: {
                return "Report: "+reportPDU.get(0);
            }
            case STATUS_TIMEOUT: {
                return "Request timed out.";
            }
            case STATUS_WRONG_ORDER: {
                return "Agent did not return variable bindings in lexicographic order.";
            }
            default: {
                return PDU.toErrorStatusText(status);
            }
        }
    }

    public String toString() {
        return getClass().getName()+"[vbs="+
                ((vbs == null) ? "null" : ""+Arrays.asList(vbs))+
                ",status="+status+",exception="+
                exception+",report="+reportPDU+"]";
    }

}
