/* SPDX-License-Identifier: BSD-3-Clause */
/*
 * Copyright 2018 Raritan Inc. All rights reserved.
 */

#include <UserEvent.idl>

/** Raritan JSON-RPC */
module cascading {

    /** JSON-RPC Cascade Manager */
    interface CascadeManager_2_0_1 {

        constant int NO_ERROR = 0;                        ///< Operation successful, no error
        constant int ERR_INVALID_PARAM = 1;               ///< A parameter was invalid
        constant int ERR_UNSUPPORTED_ON_PRIMARY_UNIT = 2; ///< Operation not allowed for a primary unit
        constant int ERR_UNSUPPORTED_ON_LINK_UNIT = 3;    ///< Operation not allowed for a link unit
        constant int ERR_LINK_ID_IN_USE = 4;              ///< The specified link ID is already used
        constant int ERR_HOST_IN_USE = 5;                 ///< The specified host is already in use
        constant int ERR_LINK_UNIT_UNREACHABLE = 6;       ///< Could not connect to the link device
        constant int ERR_LINK_UNIT_ACCESS_DENIED = 7;     ///< Login to link device failed
        constant int ERR_LINK_UNIT_REFUSED = 8;           ///< Remote device refused to become a link unit
        constant int ERR_UNIT_BUSY = 9;                   ///< The unit could not respond because it was busy
        constant int ERR_NOT_SUPPORTED = 10;              ///< Operation not supported on this device
        constant int ERR_PASSWORD_CHANGE_REQUIRED = 11;   ///< The unit requires a password change
        constant int ERR_PASSWORD_POLICY = 12;            ///< The given password did not meet the requirements
        constant int ERR_LINK_UNIT_COMM_FAILED = 13;      ///< Communication with the link unit failed
        constant int ERR_LINK_UNIT_NOT_SUPPORTED = 14;    ///< Link unit does not support cascading
        constant int ERR_FIRMWARE_VERSION_MISMATCH = 15;  ///< The firmware versions between primary and link unit do not match

        /** Settings for primary unit */
        structure PrimaryUnitSettings {
            string      caCertChain;              ///< CA certificate chain that signs the link unit TLS certs
            boolean     allowOffTimeRangeCerts;   ///< allow expired and not yet valid TLS certs
        };

        /** JSON-RPC Cascade Role */
        enumeration Role {
            STANDALONE,                           ///< Standalone unit, not in cascade
            PRIMARY_UNIT,                         ///< Primary unit controlling other devices
            LINK_UNIT                             ///< Link unit under primary unit control
        };

        enumeration LinkUnitType {
            NETWORK,                              ///< High-level linking via JSON-RPC API
            SECURE_SERIAL                         ///< Linking via encrypted serial bus (ScalePoint)
        };

        /** Link Unit Communication Status */
        [unknown_fallback("UNKNOWN")]
        enumeration LinkUnitStatus {
            UNKNOWN,                              ///< The status of the link unit is unknown
            OK,                                   ///< The link unit operates normally
            UNREACHABLE,                          ///< The link unit is unreachable
            ACCESS_DENIED,                        ///< The link unit denies access
            FIRMWARE_UPDATE,                      ///< This link unit is performing a firmware update
            FIRMWARE_MISMATCH,                    ///< This link unit's firmware version does not match that of the primary unit
            PENDING                               ///< The link unit becomes active after the next reboot
        };

        /** Link Unit Status */
        structure LinkUnit {
            LinkUnitType type;                    ///< Link unit type
            string host;                          ///< Link unit host name, IP address or bus address
            LinkUnitStatus status;                ///< Communication status
            string fwVersion;                     ///< Firmware version of the link unit
        };

        /** Full Cascading Status */
        structure Status {
            Role role;                            ///< This unit's role in the JSON-RPC cascade
            string primaryUnit;                   ///< The primary unit IP address (if role is link unit)
            map<int, LinkUnit> linkUnits;         ///< The list of link units (if role is primary unit)
        };

        /** Status of the Link Port */
        structure LinkPortStatus {
            boolean isSupported;                  ///< true, if Link Port is supported on this device
            boolean isLinkDetected;               ///< true, if a link on the Link Port was detected
            boolean isLinkingConfirmationNeeded;  ///< true, if confirmation for linking via Link Port is needed
        };

        /** Event: This unit's role in the cascade has changed */
        valueobject RoleChangedEvent extends idl.Event {
            Role oldRole;                         ///< Previous role before the change
            Role newRole;                         ///< New role after the change
            string primaryUnit;                   ///< Primary unit IP address (if new role is link unit)
        };

        /** Event: A new link unit has been added */
        valueobject LinkUnitAddedEvent extends event.UserEvent {
            int linkId;                           ///< Link ID
            LinkUnitType type;                    ///< Link unit type
            string host;                          ///< Host name, IP address or bus address
        };

        /** Event: A link unit has been released */
        valueobject LinkUnitReleasedEvent extends event.UserEvent {
            int linkId;                           ///< Link ID
            LinkUnitType type;                    ///< Link unit type
            string host;                          ///< Host name, IP address or bus address
        };

        /** Event: A link unit's communication status has changed */
        valueobject LinkUnitStatusChangedEvent extends idl.Event {
            int linkId;                           ///< Link ID
            LinkUnitType type;                    ///< Link unit type
            string host;                          ///< Host name, IP address or bus address
            LinkUnitStatus oldStatus;             ///< Previous communication status
            LinkUnitStatus newStatus;             ///< New communication status
        };

        /** Link Port Status changed */
        valueobject LinkPortStatusChangedEvent extends idl.Event {
            LinkPortStatus oldStatus;             ///< Old Link Port status
            LinkPortStatus newStatus;             ///< New Link Port status
        };

        /**
         * Retrieve settings for the primary unit.
         *
         * @return Primary unit settings
         */
        PrimaryUnitSettings getPrimaryUnitSettings();

        /**
         * Set settings for the primary unit.
         *
         * @param primaryUnitSettings  Primary unit settings
         *
         * @return NO_ERROR            The operation was successful
         * @return ERR_INVALID_PARAM   At least one of the parameters had an invalid value
         */
        int setPrimaryUnitSettings(in PrimaryUnitSettings primaryUnitSettings);

        /**
         * Retrieve the full cascading status for this unit.
         *
         * @return Full cascading status
         */
        Status getStatus();

        /**
         * Retrieve the current Link Port status
         *
         * @return Current Link Port status
         */
        LinkPortStatus getLinkPortStatus();

        /**
         * Put a new link unit under this primary unit's control.
         *
         * The login credentials must have administrator privileges on the link
         * unit. They are only used to establish a trust relationship between
         * primary and link unit and not stored.
         *
         * This method can also be used to re-authenticate a link unit that
         * denies access. In that case the linkId and host parameter must
         * exactly match the existing values.
         *
         * @param linkId       The ID for the new link unit
         * @param host         The link unit's host name or IP address
         * @param login        The administrator login for the link unit
         * @param password     The administrator password for the link unit
         * @param newPassword  The new administrator password for the unit.
         *                     This is needed for adding a link unit that still has default
         *                     settings and requires a password change. Otherwise it can be
         *                     left empty.
         *
         * @return NO_ERROR                       The operation was successful
         * @return ERR_INVALID_PARAM              One of the parameters had an invalid value
         * @return ERR_UNSUPPORTED_ON_LINK_UNIT   This unit is currently a link unit and can't have link units of its own
         * @return ERR_LINK_ID_IN_USE             The specified link ID is already in use
         * @return ERR_HOST_IN_USE                The specified host is already in use
         * @return ERR_LINK_UNIT_UNREACHABLE      Connection to the link unit failed
         * @return ERR_LINK_UNIT_ACCESS_DENIED    The credentials for the link unit were invalid
         * @return ERR_LINK_UNIT_REFUSED          The remote unit refused to become our link unit because it's a primary unit itself
         * @return ERR_UNIT_BUSY                  This unit is currently busy with handling another request
         * @return ERR_NOT_SUPPORTED              This device does not support PDU linking
         * @return ERR_PASSWORD_CHANGE_REQUIRED   The specified link unit requires a password change
         * @return ERR_PASSWORD_POLICY            The new password did not meet the requirements
         * @return ERR_LINK_UNIT_COMM_FAILED      Communication with the link unit failed
         * @return ERR_LINK_UNIT_NOT_SUPPORTED    Link unit does not support cascading
         * @return ERR_FIRMWARE_VERSION_MISMATCH  The firmware version of the link unit does not match that of the primary unit
         */
        int addLinkUnit(in int linkId, in string host, in string login, in string password, in string newPassword);

        /**
         * Release a link unit from this primary unit's control.
         *
         * @param linkId   The ID of the link unit
         *
         * @return NO_ERROR           The operation was successful
         * @return ERR_INVALID_PARAM  The specified link ID is invalid
         */
        int releaseLinkUnit(in int linkId);

        /**
         * Request to make this unit a link unit and put it under the remote
         * primary unit's control.
         *
         * This method is usually called by the primary unit when adding a new
         * link unit. The link will only be established once finalizeLink() is
         * successfully called.
         *
         * @param token  Authorization token for future requests
         *
         * @return NO_ERROR                         The operation was successful
         * @return ERR_UNSUPPORTED_ON_PRIMARY_UNIT  This unit is a primary unit and can't become a link unit
         * @return ERR_NOT_SUPPORTED                This device does not support PDU linking
         */
        int requestLink(in string token);

        /**
         * Finalize the link with this link unit.
         *
         * @param token  same authorization token as used for requestLink()
         *
         * This method should only be called by the primary unit in order to
         * acknowledge the establishment of the link to the link unit and
         * finalize the link build-up. The linking will only take effect once
         * the link unit received this acknowledgement.
         *
         * If this method fails, you will get the ACCESS_DENIED status for this
         * link unit and you will have to re-authenticate it.
         */
        void finalizeLink(in string token);

        /**
         * Release this link unit from the remote primary unit's control.
         *
         * This method is usually called by the primary unit when releasing a
         * link unit. This unit will become a standalone unit.
         */
        void unlink();

        /**
         * Check which cascading roles this unit supports.
         *
         * @return vector with Roles that are supported by this unit
         */
        vector<Role> getSupportedRoles();

        /**
         * Check which type of link units this unit supports.
         *
         * @return vector with supported link unit types
         */
        vector<LinkUnitType> getSupportedLinkUnitTypes();

        /**
         * Can be called on a network cascade primary unit to add expansion
         * units of the network cascade as link units.
         *
         * @param linkId                The ID for the new link unit
         * @param nodeIndex             The expansion unit's index in the network cascade (1 - 15)
         * @param login                 The administrator login for the link unit
         * @param password              The administrator password for the link unit
         * @param positionDependent     If true, host names that depend on the nodex index will be used.
         *                              If false, unique link-local IPv6 addresses will be used for linking.
         *
         * @return see \ref addLinkUnit
         *
         */
        int addCascadeLinkUnit(in int linkId, in int nodeIndex, in string login, in string password, in boolean positionDependent);

        /**
         * Add a neighbor that was discovered on the link port as link unit. If
         * a new password needs to be set, it will be generated.
         *
         * @return NO_ERROR                       The operation was successful
         * @return ERR_INVALID_PARAM              No neighbor currently discovered or no link id left
         * @return ERR_UNSUPPORTED_ON_LINK_UNIT   This unit is currently a link unit and can't have link units of its own
         * @return ERR_HOST_IN_USE                The link port neighbor was already added
         * @return ERR_LINK_UNIT_UNREACHABLE      Connection to the link unit failed
         * @return ERR_LINK_UNIT_ACCESS_DENIED    The credentials for the link unit were invalid
         * @return ERR_LINK_UNIT_REFUSED          The remote unit refused to become our link unit because it's a primary unit itself
         * @return ERR_UNIT_BUSY                  This unit is currently busy with handling another request
         * @return ERR_NOT_SUPPORTED              This device does not support PDU linking via link port
         * @return ERR_LINK_UNIT_COMM_FAILED      Communication with the link unit failed
         * @return ERR_LINK_UNIT_NOT_SUPPORTED    Link unit does not support cascading
         * @return ERR_FIRMWARE_VERSION_MISMATCH  The firmware version of the link unit does not match that of the primary unit
         */
        int addLinkPortLinkUnit();

        /**
         * Add a serial link unit (ScalePoint Base).
         *
         * As a special case, link ID 1 is used to pair the primary unit on the
         * "internal" RS485 bus. It will not be added to the list of link units.
         *
         * @param linkId       The ID for the new link unit
         * @param installKey   The install key from the Base unit's label
         *
         * @return NO_ERROR                       The operation was successful
         * @return ERR_INVALID_PARAM              One of the parameters had an invalid value
         * @return ERR_UNSUPPORTED_ON_LINK_UNIT   This unit is currently a link unit and can't have link units of its own
         * @return ERR_LINK_ID_IN_USE             The specified link ID is already in use
         * @return ERR_LINK_UNIT_UNREACHABLE      Connection to the link unit failed
         * @return ERR_UNIT_BUSY                  This unit is currently busy with handling another request
         * @return ERR_NOT_SUPPORTED              This device does not support PDU linking
         * @return ERR_LINK_UNIT_COMM_FAILED      Communication with the link unit failed
         */
        int addSecureSerialLinkUnit(in int linkId, in string installKey);

    };

}
