//////////////////////////////////////////////////////////////////////////
//
// DATAPACK
//
// Invocations contain a field 'datapack' which contains additional
// data for the invocation, packed up in a serialized format.  Executing
// the invocation involves unpacking the datapack.
//
// The actual contents of the datapack depends on the type of invocation:
//
// AccessKind::INVOKE_LUA_CALL:
//
//   A lua function call.  The class name, the function name, and then
//   the function arguments.
//
// AccessKind::INVOKE_LUA_EXPR:
//
//   A block of lua source code, in plaintext.
//
// AccessKind::INVOKE_FLUSH_PRINTS:
//
//   Line number in ascii.
//
// AccessKind::INVOKE_LUA_SOURCE:
//
//   Packaged lua sourcecode.  See drvutil::package_lua_source.
//
// AccessKind::INVOKE_TICK:
//
//   Nothing.
//
//////////////////////////////////////////////////////////////////////////

#pragma once

#include "wrap-string.hpp"
#include "wrap-map.hpp"
#include "wrap-deque.hpp"
#include "streambuffer.hpp"
#include "enginewrapper.hpp"


class Invocation : public eng::opnew {
public:
private:
    AccessKind kind_;
    int64_t actor_;
    int64_t place_;
    eng::string datapack_;
public:
    Invocation();
    Invocation(AccessKind kind, int64_t actor, int64_t place, std::string_view datapack);
    
    bool valid() const { return kind_ != AccessKind::INVALID; }
    AccessKind kind() const { return kind_; }
    int64_t actor() const { return actor_; }
    int64_t place() const { return place_; }
    const eng::string &datapack() const { return datapack_; }

    void serialize(StreamBuffer *sb) const;
    void deserialize(StreamBuffer *sb);

    // Return true if the kind is a valid kind of invocation
    // to go over the network.
    static bool is_valid_network_kind(AccessKind k)
    { return k == AccessKind::INVOKE_FLUSH_PRINTS ||
             k == AccessKind::INVOKE_LUA_CALL ||
             k == AccessKind::INVOKE_LUA_EXPR ||
             k == AccessKind::INVOKE_LUA_SOURCE; }
    
    eng::string debug_string() const;
};

using UniqueInvocation = std::unique_ptr<Invocation>;

class InvocationQueue : public eng::deque<Invocation> {
};
