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

#ifndef __SMARTLOCK_DOOR_ACCESS_CONTROL_IDL__
#define __SMARTLOCK_DOOR_ACCESS_CONTROL_IDL__

#include <Event.idl>
#include <UserEvent.idl>
#include <PeripheralDeviceSlot.idl>

module smartlock {

    /** Access control for door locks */
    interface DoorAccessControl_1_1_2 {

        constant int ERR_INVALID_SETTINGS               = 1;            ///< Invalid settings
        constant int ERR_NO_SUCH_ID                     = 2;            ///< No such ID
        constant int ERR_MAX_RULES_REACHED              = 3;            ///< Maximum number of rules

        /**
         * A condition representing an absolute time range.
         *
         * Timestamps are UNIX timestamps (UTC)
         */
        structure AbsoluteTimeCondition {
            boolean enabled;                                            ///< Condition is enabled
            time validFrom;                                             ///< Time range starting from this date or 0 if not set
            time validTill;                                             ///< Time range valid until this date or 0 if not set
        };

        /**
         * A condition representing a periodic time range.
         *
         * Once this condition is enabled, weekdays have to be specified in
         * order to get granted access. A specific clock time range can be set
         * to allow access only certain times of the day. The system's local time
         * will be used (as defined by the configured time zone).
         *
         * The clock time range will wrap over into the next day if
         * fromHourOfDay:fromMinuteOfHour >= tillHourOfDay:tillMinuteOfHour,
         * meaning that the weekday of fromHourOfDay:fromMinuteOfHour will be checked.
         */
        structure PeriodicTimeCondition {
            boolean enabled;                                            ///< Condition is enabled
            vector<int> daysOfWeek;                                     ///< Range for these days of the week (valid values are 0 - 6, 0 is Sunday)
            int fromHourOfDay;                                          ///< Range periodically starts from this hour of the day (0 - 23)
            int tillHourOfDay;                                          ///< Range periodically ends this hour of the day (0 - 23)
            int fromMinuteOfHour;                                       ///< Specify minute of starting hour (0 - 59)
            int tillMinuteOfHour;                                       ///< Specify minute of ending hour (0 - 59)
        };

        /**
         * Information in order to refer to a specific card reader
         */
        structure CardReaderInfo {
            int linkId;                                                 ///< Unit the card reader is attached to
            string position;                                            ///< Position of the card reader.
                                                                        ///< This can be fetched from the CardReader MetaData
        };

        /**
         * Information in order to refer to a specific keypad
         */
        structure KeypadInfo {
            int linkId;                                                 ///< Unit the keypad is attached to
            string position;                                            ///< Position of the keypad
                                                                        ///< This can be fetched from the Keypad MetaData
        };

        /**
         * A condition for specific cards and card readers.
         */
        structure CardCondition {
            boolean enabled;                                            ///< Condition is enabled
            string cardUid;                                             ///< Matching card uid
            CardReaderInfo cardReader;                                  ///< The card reader that has to be used
        };

        /**
         * A condition for keypads with a secret pin
         */
        structure KeypadCondition {
            boolean enabled;                                            ///< Condition is enabled
            string pin;                                                 ///< Pin that has to be entered
            KeypadInfo keypad;                                          ///< The keypad that has to be used
        };


        /**
         * Data representing a rule to control access to certain doors.
         *
         * Access is granted (i.e. the defined locks are opened) if the defined
         * and enabled conditions are met. At least one CardCondition or one
         * KeypadCondition must be enabled. If multiple conditions are enabled, all
         * conditions have to be met during the timeout that is defined in
         * conditionsTimeout.
         */
        structure DoorAccessRule {
            string name;                                                ///< A name to describe this rule
            vector<peripheral.DeviceSlot_4_0_2> doorHandleLocks;        ///< Open these door handle locks
            CardCondition cardCondition1;                               ///< Condition that has to be fulfilled when inserting a card
            CardCondition cardCondition2;                               ///< Additional card condition that is needed
            KeypadCondition keypadCondition1;                           ///< Condition that has to be fulfilled when using a keypad
            KeypadCondition keypadCondition2;                           ///< Additional keypad condition that is needed
            int conditionsTimeout;                                      ///< Timeout for matching multiple card / keypad conditions
            AbsoluteTimeCondition absoluteTime;                         ///< Absolute time range condition
            PeriodicTimeCondition periodicTime;                         ///< Periodic time range condition
        };

        /**
         * Door Access Denial Reason
         */
        enumeration DoorAccessDenialReason {
            DENIED_NO_MATCHING_RULE,                                    ///< No rule that matches the triggering event
            DENIED_ABSOLUTE_TIME_CONDITION,                             ///< Absolute time condition was not met
            DENIED_PERIODIC_TIME_CONDITION,                             ///< Periodic time condition was not met
            DENIED_CONDITIONS_TIMEOUT                                   ///< A needed condition was not fulfilled during conditionsTimeout
        };

        /**
         * Event: Door access granted
         *
         * This Event will be triggered for every rule whose conditions were fulfilled.
         */
        valueobject DoorAccessGrantedEvent extends idl.Event {
            int ruleId;                                                 ///< Rule id of rule that granted access
            DoorAccessRule rule;                                        ///< Rule settings of rule that granted access, cardUid and pin will be filtered
        };

        /**
         * Event: Door access denied
         *
         * This event will only be triggered if at least one DoorAccessRule
         * exists and a card was inserted or keypad PIN entered, but none of
         * the defined rules were sufficiently fulfilled to grant access.
         *
         * If matching rules are found, this will be triggered for every
         * matching rule that could not be fulfilled. Otherwise it will only be
         * triggered once with the according DoorAccessDenialReason.
         */
        valueobject DoorAccessDeniedEvent extends idl.Event {
            DoorAccessDenialReason reason;                              ///< A DoorAccessDenialReason, specifying why the access was denied
            int ruleId;                                                 ///< A matching rule that could not be fulfilled or -1 if no matching rule
            string ruleName;                                            ///< Name of the rule that could not be fulfilled or empty if no matching rule
        };

        /**
         * Event: Door access rule added
         */
        valueobject DoorAccessRuleAddedEvent extends event.UserEvent {
            int ruleId;                                                 ///< New rule id
            DoorAccessRule rule;                                        ///< Rule that was added, cardUid and pin will be filtered
        };

        /**
         * Event: Door access rule modified
         */
        valueobject DoorAccessRuleChangedEvent extends event.UserEvent {
            int ruleId;                                                 ///< Id of modified rule
            DoorAccessRule oldRule;                                     ///< Old rule settings, cardUid and pin will be filtered
            DoorAccessRule newRule;                                     ///< New rule settings, cardUid and pin will be filtered
        };

        /**
         * Event: Door access rule deleted
         */
        valueobject DoorAccessRuleDeletedEvent extends event.UserEvent {
            int ruleId;                                                 ///< Id of deleted rule
            DoorAccessRule rule;                                        ///< Rule that was deleted, cardUid and pin will be filtered
        };

        /**
         * Get all stored door access control rules
         *
         * @return list of rules by id
         */
        map<int, DoorAccessRule> getDoorAccessRules();

        /**
         * Replace all the currently existing rules. Note that this not only
         * adds and modifies rules, but also deletes existing rules that are
         * not present in the given rule set.
         *
         * In case of any rule being invalid, no changes will be made at all.
         *
         * @param rules             the new rule set
         * @param invalidRules      in case of an error, return ids of invalid rules
         *
         * @return 0 if OK
         * @return 1 if the rule set contains a rule with invalid values
         */
        int setAllDoorAccessRules(in map<int, DoorAccessRule> rules, out vector<int> invalidRuleIds);

        /**
         * Add a door access control rule. If successful, the id of the new
         * rule will be returned.
         *
         * @param rule          the new rule
         *
         * @return 0 if OK
         * @return 1 if rule has invalid values
         * @return 3 if maximum number of rules reached
         */
        int addDoorAccessRule(in DoorAccessRule rule, out int ruleId);

        /**
         * Modify an existing door access control rule
         *
         * @param id            id of the rule to modify
         * @param modifiedRule  rule containing the new settings
         *
         * @return 0 if OK
         * @return 1 if modifiedRule has invalid values
         * @return 2 if no rule with this id
         */
        int modifyDoorAccessRule(in int id, in DoorAccessRule modifiedRule);

        /**
         * Delete an existing door access control rule
         *
         * @param id            id of the rule to delete
         *
         * @return 0 if OK
         * @return 2 if no rule with this id
         */
        int deleteDoorAccessRule(in int id);
    };
}

#endif /* __SMARTLOCK_DOOR_ACCESS_CONTROL_IDL__ */
