text: /**
   *  @file
   *  @copyright defined in seat/LICENSE.txt
   */
  #pragma once
  #include <cubetrain/chain/authority.hpp>
  
  #include "multi_index_includes.hpp"
  
  namespace cubetrain { namespace chain {
  
     class permission_usage_object : public chainbase::object<permission_usage_object_type, permission_usage_object> {
        OBJECT_CTOR(permission_usage_object)
  
        id_type           id;
        time_point        last_used;   ///< when this permission was last used
     };
  
     struct by_account_permission;
     using permission_usage_index = chainbase::shared_multi_index_container<
        permission_usage_object,
        indexed_by<
           ordered_unique<tag<by_id>, member<permission_usage_object, permission_usage_object::id_type, &permission_usage_object::id>>
        >
     >;
  
  
     class permission_object : public chainbase::object<permission_object_type, permission_object> {
        OBJECT_CTOR(permission_object, (auth) )
  
        id_type                           id;
        permission_usage_object::id_type  usage_id;
        id_type                           parent; ///< parent permission
        account_name                      owner; ///< the account this permission belongs to
        permission_name                   name; ///< human-readable name for the permission
        time_point                        last_updated; ///< the last time this authority was updated
        shared_authority                  auth; ///< authority required to execute this permission
  
  
        /**
         * @brief Checks if this permission is equivalent or greater than other
         * @tparam Index The permission_index
         * @return true if this permission is equivalent or greater than other, false otherwise
         *
         * Permissions are organized hierarchically such that a parent permission is strictly more powerful than its
         * children/grandchildren. This method checks whether this permission is of greater or equal power (capable of
         * satisfying) permission @ref other.
         */
        template <typename Index>
        bool satisfies(const permission_object& other, const Index& permission_index) const {
           // If the owners are not the same, this permission cannot satisfy other
           if( owner != other.owner )
              return false;
  
           // If this permission matches other, or is the immediate parent of other, then this permission satisfies other
           if( id == other.id || id == other.parent )
              return true;
  
           // Walk up other's parent tree, seeing if we find this permission. If so, this permission satisfies other
           const permission_object* parent = &*permission_index.template get<by_id>().find(other.parent);
           while( parent ) {
              if( id == parent->parent )
                 return true;
              if( parent->parent._id == 0 )
                 return false;
              parent = &*permission_index.template get<by_id>().find(parent->parent);
           }
           // This permission is not a parent of other, and so does not satisfy other
           return false;
        }
     };
  
     struct by_parent;
     struct by_owner;
     struct by_name;
     using permission_index = chainbase::shared_multi_index_container<
        permission_object,
        indexed_by<
           ordered_unique<tag<by_id>, member<permission_object, permission_object::id_type, &permission_object::id>>,
           ordered_unique<tag<by_parent>,
              composite_key<permission_object,
                 member<permission_object, permission_object::id_type, &permission_object::parent>,
                 member<permission_object, permission_object::id_type, &permission_object::id>
              >
           >,
           ordered_unique<tag<by_owner>,
              composite_key<permission_object,
                 member<permission_object, account_name, &permission_object::owner>,
                 member<permission_object, permission_name, &permission_object::name>
              >
           >,
           ordered_unique<tag<by_name>,
              composite_key<permission_object,
                 member<permission_object, permission_name, &permission_object::name>,
                 member<permission_object, permission_object::id_type, &permission_object::id>
              >
           >
        >
     >;
  
     namespace config {
        template<>
        struct billable_size<permission_object> { // Also counts memory usage of the associated permission_usage_object
           static const uint64_t  overhead = 5 * overhead_per_row_per_index_ram_bytes; ///< 5 indices 2x internal ID, parent, owner, name
           static const uint64_t  value = (config::billable_size_v<shared_authority> + 64) + overhead;  ///< fixed field size + overhead
        };
     }
  } } // cubetrain::chain
  
  CHAINBASE_SET_INDEX_TYPE(cubetrain::chain::permission_object, cubetrain::chain::permission_index)
  CHAINBASE_SET_INDEX_TYPE(cubetrain::chain::permission_usage_object, cubetrain::chain::permission_usage_index)
  
  FC_REFLECT(chainbase::oid<cubetrain::chain::permission_object>, (_id))
  FC_REFLECT(cubetrain::chain::permission_object, (id)(usage_id)(parent)(owner)(name)(last_updated)(auth))
  
  FC_REFLECT(chainbase::oid<cubetrain::chain::permission_usage_object>, (_id))
  FC_REFLECT(cubetrain::chain::permission_usage_object, (id)(last_used))
  