# Copyright © 2020 Gregor Reitzenstein
# Licensed under the MIT License:
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


@0xfd92ce9be2369b8e;

interface Diflouroborane {
    # Upon initial connection this is the interface a program is presented with, serving as the
    # common point to access specific subsystems. Keep in mind that one can use pipelining to make this
    # just as efficient as direct calls — e.g. access the authentication system and call
    # `initializeAuthentication` on it in one roundtrip, provided one gets granted access to the
    # Authentication subsystem (which in all fairness is a reasonable assumption)

    permissions @0 () -> ( perm :Permissions );
    # Permission subsystem to manage permissions and systems underlying the authorization process

    machines @1 () -> ( mach :Machines );
    # Diflouroborane stores machine¹ information in an opaque internal database. This interface is
    # the only stable process of modifying that information

    # TODO Capability transfer system, required for machine takeover, session resumption.
}

struct UUID {
    # UUID type used to identify machines.
    # Since the exact value has no meaning the encoding rules are not too relevant, but it is
    # paramount that you are consistent when encoding and decoding this type.
    #
    # Consider using this algorithm for assembling the 128-bit integer:
    # (assuming ISO9899:2018 shifting & casting rules)
    #   uint128_t num = (uuid1 << 64) + uuid0;
    # And then respectively this code for deconstructing it:
    #   uint64_t uuid0 = (uint64_t) num;
    #   uint64_t uuid1 = (uint64_t) (num >> 64);

    uuid0 @0 :UInt64;
    uuid1 @1 :UInt64;
}

struct Maybe(T) {
    union {
        none @0 :Void;
        some @1 :T;
    }
}

enum State {
    free @0;
    inUse @1;
    toCheck @2;
    blocked @3;
    disabled @4;
    reserved @5;
}

interface Machine {
    struct MInfo {
        state @0 :State;
        name @1 :Text;
        description @2 :Text;

        responsible @3 :Text;
        # TODO: Make that an user, issue #XXX
    }

    info @0 () -> ( minfo :MInfo );
    # Check the state of a machine.

    interface GiveBack {
        ret @0 () -> ();
    }

    use @1 () -> ( ret :Maybe(GiveBack) );
    # Try to use a machine. Fails if the user doesn't have enough permissions

    interface Check {
        ok @0 () -> (); # The machine was clean & ok. -> free
        not_ok @1 () -> ();
        # The machine was left in an unacceptable state.
        # Most likely marks the machine as `blocked` and somehow informs the previous user.
    }

    check @2 () -> ( chk :Maybe(Check) );
    # After a machine has been used by an user with low enough permissions it's
    # in the 'toCheck' state.  This call then allows more priviledged users to
    # "check" the machine and move it to the `free` state.

    reserve @3 () -> ( rsrv :Maybe(AnyPointer) );
}

interface Machines {
    lookup @0 ( uuid :UUID ) -> ( machine :Maybe(Machine) );
    # Get a machine interface. Returns `none` if there is no Machine with the given uuid.

    list @1 () -> ( machines :List(Machine) );
    # List all machines
}

interface Permissions {
}