#pragma once

#include <memory>
#include <string>
#include <unordered_map>

#include <DirectXMath.h>
#include <gsl/span>

struct Ray3d;

namespace gfx {

	struct Light3d;
	struct MdfRenderOverrides;
	enum class MaterialPlaceholderSlot;

	struct AnimatedModelParams;
	using AnimatedModelPtr = std::shared_ptr<class AnimatedModel>;
	using MdfRenderMaterialPtr = std::shared_ptr<class MdfRenderMaterial>;

	enum class WeaponAnim : int {
		None = 0,
		RightAttack,
		RightAttack2,
		RightAttack3,
		LeftAttack,
		LeftAttack2,
		LeftAttack3,
		Walk,
		Run,
		Idle,
		FrontHit,
		FrontHit2,
		FrontHit3,
		LeftHit,
		LeftHit2,
		LeftHit3,
		RightHit,
		RightHit2,
		RightHit3,
		BackHit,
		BackHit2,
		BackHit3,
		RightCriticalSwing,
		LeftCriticalSwing,
		Fidget,
		Fidget2,
		Fidget3,
		Sneak,
		Panic,
		RightCombatStart,
		LeftCombatStart,
		CombatIdle,
		CombatFidget,
		Special1,
		Special2,
		Special3,
		FrontDodge,
		RightDodge,
		LeftDodge,
		BackDodge,
		RightThrow,
		LeftThrow,
		LeftSnatch,
		RightSnatch,
		LeftTurn,
		RightTurn
	};

	enum class WeaponAnimType : int {
		Unarmed = 0,
		Dagger,
		Sword,
		Mace,
		Hammer,
		Axe,
		Club,
		Battleaxe,
		Greatsword,
		Greataxe,
		Greathammer,
		Spear,
		Staff,
		Polearm,
		Bow,
		Crossbow,
		Sling,
		Shield,
		Flail,
		Chain,
		TwoHandedFlail,
		Shuriken,
		Monk
	};

	enum class BardInstrumentType : int {
		Flute = 0,
		Drum,
		Mandolin,
		Trumpet,
		Harp,
		Lute,
		Pipers,
		Recorder
	};

	enum class NormalAnimType : int {
		Falldown = 0,
		ProneIdle,
		ProneFidget,
		Getup,
		Magichands,
		Picklock,
		PicklockConcentrated,
		Examine,
		Throw,
		Death,
		Death2,
		Death3,
		DeadIdle,
		DeadFidget,
		DeathProneIdle,
		DeathProneFidget,
		AbjurationCasting,
		AbjurationConjuring,
		ConjurationCasting,
		ConjurationConjuring,
		DivinationCasting,
		DivinationConjuring,
		EnchantmentCasting,
		EnchantmentConjuring,
		EvocationCasting,
		EvocationConjuring,
		IllusionCasting,
		IllusionConjuring,
		NecromancyCasting,
		NecromancyConjuring,
		TransmutationCasting,
		TransmutationConjuring,
		Conceal,
		ConcealIdle,
		Unconceal,
		ItemIdle,
		ItemFidget,
		Open,
		Close,
		SkillAnimalEmpathy,
		SkillDisableDevice,
		SkillHeal,
		SkillHealConcentrated,
		SkillHide,
		SkillHideIdle,
		SkillHideFidget,
		SkillUnhide,
		SkillPickpocket,
		SkillSearch,
		SkillSpot,
		FeatTrack,
		Trip,
		Bullrush,
		Flurry,
		Kistrike,
		Tumble,
		Special1,
		Special2,
		Special3,
		Special4,
		Throw2,
		WandAbjurationCasting,
		WandAbjurationConjuring,
		WandConjurationCasting,
		WandConjurationConjuring,
		WandDivinationCasting,
		WandDivinationConjuring,
		WandEnchantmentCasting,
		WandEnchantmentConjuring,
		WandEvocationCasting,
		WandEvocationConjuring,
		WandIllusionCasting,
		WandIllusionConjuring,
		WandNecromancyCasting,
		WandNecromancyConjuring,
		WandTransmutationCasting,
		WandTransmutationConjuring,
		SkillBarbarianRage,
		OpenIdle
	};

	/*
	Represents an encoded animation id.
	*/
	class EncodedAnimId {
	public:
		explicit EncodedAnimId(int id) : mId(id) {
		}

		explicit EncodedAnimId(WeaponAnim anim,
		                       WeaponAnimType leftHand = WeaponAnimType::Unarmed,
		                       WeaponAnimType rightHand = WeaponAnimType::Unarmed) : mId(sWeaponAnimFlag) {
			auto animId = (int)anim;
			auto leftHandId = (int)leftHand;
			auto rightHandId = (int)rightHand;

			mId |= animId & 0xFFFFF;
			mId |= leftHandId << 20;
			mId |= rightHandId << 25;
		}

		explicit EncodedAnimId(BardInstrumentType instrumentType) : mId(sBardInstrumentAnimFlag) {
			mId |= (int)instrumentType;
		}

		explicit EncodedAnimId(NormalAnimType animType) : mId((int) animType) {
		}

		operator int() const {
			return mId;
		}

		bool IsConjuireAnimation() const;

		bool IsSpecialAnim() const {
			return (mId & (sWeaponAnimFlag | sBardInstrumentAnimFlag)) != 0;
		}

		// Not for weapon/bard anims
		NormalAnimType GetNormalAnimType() const {
			return (NormalAnimType)mId;
		}

		bool IsWeaponAnim() const {
			return (mId & sWeaponAnimFlag) != 0;
		}

		// Only valid for weapon animations
		WeaponAnimType GetWeaponLeftHand() const {
			return (WeaponAnimType)((mId >> 20) & 0x1F);
		}

		// Only valid for weapon animations
		WeaponAnimType GetWeaponRightHand() const {
			return (WeaponAnimType)((mId >> 25) & 0x1F);
		}

		// Only valid for weapon animations
		WeaponAnim GetWeaponAnim() const {
			return (WeaponAnim)(mId & 0xFFFFF);
		}

		bool IsBardInstrumentAnim() const {
			return (mId & sBardInstrumentAnimFlag) != 0;
		}

		// Only valid for bard instrument anim
		BardInstrumentType GetBardInstrumentType() const {
			return (BardInstrumentType)(mId & 7);
		}

		std::string GetName() const;

		bool ToFallback();

	private:
		// Indicates that an animation id uses the encoded format
		static constexpr int sWeaponAnimFlag = 1 << 30;
		static constexpr int sBardInstrumentAnimFlag = 1 << 31;

		int mId;
	};

	/*
		Represents the events that can trigger when the animation
		of an animated model is advanced.
	*/
	class AnimatedModelEvents {
	public:
		AnimatedModelEvents(bool isEnd, bool isAction)
			: mIsEnd(isEnd),
			  mIsAction(isAction) {
		}

		bool IsEnd() const {
			return mIsEnd;
		}

		bool IsAction() const {
			return mIsAction;
		}

	private:
		const bool mIsEnd : 1;
		const bool mIsAction : 1;
	};

	class Submesh {
	public:
		virtual ~Submesh() {
		}

		virtual int GetVertexCount() = 0;
		virtual int GetPrimitiveCount() = 0;
		virtual gsl::span<DirectX::XMFLOAT4> GetPositions() = 0;
		virtual gsl::span<DirectX::XMFLOAT4> GetNormals() = 0;
		virtual gsl::span<DirectX::XMFLOAT2> GetUV() = 0;
		virtual gsl::span<uint16_t> GetIndices() = 0;
	};

	class IRenderState {
	public:
		virtual ~IRenderState() = default;
	};

	class AnimatedModel {
	public:
		virtual ~AnimatedModel() {
		}

		virtual uint32_t GetHandle() const = 0;

		virtual bool AddAddMesh(const std::string& filename) = 0;

		virtual bool ClearAddMeshes() = 0;

		virtual AnimatedModelEvents Advance(float deltaTime,
		                                    float deltaDistance,
		                                    float deltaRotation,
		                                    const AnimatedModelParams& params) = 0;

		virtual EncodedAnimId GetAnimId() const = 0;

		virtual int GetBoneCount() const = 0;

		virtual std::string GetBoneName(int boneId) = 0;

		virtual int GetBoneParentId(int boneId) = 0;

		virtual bool GetBoneWorldMatrixByName(
			const AnimatedModelParams& params,
			const std::string& boneName,
			DirectX::XMFLOAT4X4* worldMatrixOut) = 0;

		virtual bool GetBoneWorldMatrixByNameForChild(const AnimatedModelPtr& child,
		                                              const AnimatedModelParams& params,
		                                              const std::string& boneName,
				DirectX::XMFLOAT4X4* worldMatrixOut) = 0;

		virtual float GetDistPerSec() const = 0;

		virtual float GetRotationPerSec() const = 0;

		virtual bool HasAnim(EncodedAnimId animId) const = 0;

		virtual void SetTime(const AnimatedModelParams& params, float timeInSecs) = 0;

		virtual bool HasBone(const std::string& boneName) const = 0;

		virtual void AddReplacementMaterial(gfx::MaterialPlaceholderSlot slot,
			const gfx::MdfRenderMaterialPtr &material) = 0;

		virtual void SetAnimId(EncodedAnimId animId) = 0;

		// This seems to reset cloth simulation state
		virtual void SetClothFlag() = 0;

		virtual std::vector<int> GetSubmeshes() = 0;

		virtual std::unique_ptr<Submesh> GetSubmesh(const AnimatedModelParams& params, int submeshIdx) = 0;

		virtual std::unique_ptr<Submesh> GetSubmeshForParticles(const AnimatedModelParams& params, int submeshIdx) = 0;

		bool HitTestRay(const AnimatedModelParams& params, const Ray3d &ray, float &hitDistance);

		/**
		 * Find the closest distance that the given point is away from the surface of this mesh.
		 */
		float GetDistanceToMesh(const AnimatedModelParams &params, DirectX::XMFLOAT3 pos);

		/**
			This calculates the effective height in world coordinate units of the model in its current
			state. Scale is the model scale in percent.
		*/
		virtual float GetHeight(int scale = 100) = 0;

		/**
			This calculates the visible radius of the model in its current state.
			The radius is the maximum distance of any vertex on the x,z plane from the models origin.
			If the model has no vertices, 0 is returned.
			Scale is model scale in percent.
		*/
		virtual float GetRadius(int scale = 100) = 0;

		/**
		 * Sets a custom render state pointer that will be freed when this model is freed.
		 */
		virtual void SetRenderState(std::unique_ptr<IRenderState> renderState) = 0;

		/**
		 * Returns the currently assigned render state or null.
		 */
		virtual IRenderState *GetRenderState() const = 0;

		template<typename T>
		T &GetOrCreateRenderState() {
			auto current = GetRenderState();
			if (!current) {
				auto newState = std::make_unique<T>();
				current = newState.get();
				SetRenderState(std::move(newState));
			}
			return (T&) *current;
		}

	};

	struct AnimatedModelParams { // see: objects.GetAnimParams(handle)
		uint32_t x = 0;
		uint32_t y = 0;
		float offsetX = 0;
		float offsetY = 0;
		float offsetZ = 0;
		float rotation = 0;
		float scale = 1;
		float rotationRoll = 0;
		float rotationPitch = 0;
		float rotationYaw = 0;
		AnimatedModelPtr parentAnim;
		std::string attachedBoneName;
		bool rotation3d = false; // Enables use of rotationRoll/rotationPitch/rotationYaw
	};

	class AnimatedModelFactory {
	public:
		virtual ~AnimatedModelFactory() {
		}

		virtual AnimatedModelPtr FromIds(
			int meshId,
			int skeletonId,
			EncodedAnimId idleAnimId,
			const AnimatedModelParams& params,
			bool borrow = false) = 0;

		virtual AnimatedModelPtr FromFilenames(
			const std::string& meshFilename,
			const std::string& skeletonFilename,
			EncodedAnimId idleAnimId,
			const AnimatedModelParams& params) = 0;

		virtual std::unique_ptr<gfx::AnimatedModel> BorrowByHandle(uint32_t handle) = 0;

		virtual void FreeHandle(uint32_t handle) = 0;

		virtual void FreeAll() = 0;

	};

	class AnimatedModelRenderer {
	public:
		virtual ~AnimatedModelRenderer() {}

		virtual void Render(AnimatedModel *model,
			const AnimatedModelParams& params,
			gsl::span<Light3d> lights,
			const MdfRenderOverrides *materialOverrides = nullptr) = 0;
	};

}


#pragma once

#include "BgfxCallback.h"
#include "FrameBuffer.h"
#include "ShaderCompiler.h"

#include <Babylon/JsRuntime.h>
#include <Babylon/JsRuntimeScheduler.h>

#include <GraphicsImpl.h>

#include <napi/napi.h>

#include <bgfx/bgfx.h>
#include <bgfx/platform.h>
#include <bimg/bimg.h>
#include <bx/allocator.h>

#include <gsl/gsl>

#include <assert.h>

#include <arcana/containers/weak_table.h>
#include <arcana/threading/cancellation.h>
#include <unordered_map>

namespace Babylon
{
    struct TextureData final
    {
        ~TextureData()
        {
            if (OwnsHandle && bgfx::isValid(Handle))
            {
                bgfx::destroy(Handle);
            }
        }

        bgfx::TextureHandle Handle{bgfx::kInvalidHandle};
        bool OwnsHandle{true};
        uint32_t Width{0};
        uint32_t Height{0};
        uint32_t Flags{0};
        uint8_t AnisotropicLevel{0};
    };

    struct UniformInfo final
    {
        uint8_t Stage{};
        bgfx::UniformHandle Handle{bgfx::kInvalidHandle};
        bool YFlip{false};
    };

    struct ProgramData final
    {
        ProgramData() = default;
        ProgramData(const ProgramData&) = delete;
        ProgramData(ProgramData&&) = delete;

        ~ProgramData()
        {
            if (bgfx::isValid(Handle))
            {
                bgfx::destroy(Handle);
            }
        }

        std::unordered_map<std::string, uint32_t> VertexAttributeLocations{};
        std::unordered_map<std::string, UniformInfo> VertexUniformInfos{};
        std::unordered_map<std::string, UniformInfo> FragmentUniformInfos{};

        bgfx::ProgramHandle Handle{bgfx::kInvalidHandle};

        struct UniformValue
        {
            std::vector<float> Data{};
            uint16_t ElementLength{};
            bool YFlip{false};
        };

        std::unordered_map<uint16_t, UniformValue> Uniforms{};

        void SetUniform(bgfx::UniformHandle handle, gsl::span<const float> data, bool YFlip, size_t elementLength = 1)
        {
            UniformValue& value = Uniforms[handle.idx];
            value.Data.assign(data.begin(), data.end());
            value.ElementLength = static_cast<uint16_t>(elementLength);
            value.YFlip = YFlip;
        }
    };

    class IndexBufferData;
    class VertexBufferData;

    struct VertexArray final
    {
        ~VertexArray()
        {
            for (auto& vertexBufferPair : VertexBuffers)
            {
                bgfx::destroy(vertexBufferPair.second.VertexLayoutHandle);
            }
        }

        struct IndexBuffer
        {
            const IndexBufferData* Data{};
        };

        IndexBuffer indexBuffer{};

        struct VertexBuffer
        {
            const VertexBufferData* Data{};
            uint32_t StartVertex{};
            bgfx::VertexLayoutHandle VertexLayoutHandle{};
        };

        std::unordered_map<uint32_t, VertexBuffer> VertexBuffers;
    };

    class NativeEngine final : public Napi::ObjectWrap<NativeEngine>
    {
        static constexpr auto JS_CLASS_NAME = "_NativeEngine";
        static constexpr auto JS_ENGINE_CONSTRUCTOR_NAME = "Engine";

    public:
        NativeEngine(const Napi::CallbackInfo& info);
        NativeEngine(const Napi::CallbackInfo& info, JsRuntime& runtime);
        ~NativeEngine();

        static void Initialize(Napi::Env env);

    private:
        void Dispose();

        void Dispose(const Napi::CallbackInfo& info);
        Napi::Value HomogeneousDepth(const Napi::CallbackInfo& info);
        void RequestAnimationFrame(const Napi::CallbackInfo& info);
        Napi::Value CreateVertexArray(const Napi::CallbackInfo& info);
        void DeleteVertexArray(const Napi::CallbackInfo& info);
        void BindVertexArray(const Napi::CallbackInfo& info);
        Napi::Value CreateIndexBuffer(const Napi::CallbackInfo& info);
        void DeleteIndexBuffer(const Napi::CallbackInfo& info);
        void RecordIndexBuffer(const Napi::CallbackInfo& info);
        void UpdateDynamicIndexBuffer(const Napi::CallbackInfo& info);
        Napi::Value CreateVertexBuffer(const Napi::CallbackInfo& info);
        void DeleteVertexBuffer(const Napi::CallbackInfo& info);
        void RecordVertexBuffer(const Napi::CallbackInfo& info);
        void UpdateDynamicVertexBuffer(const Napi::CallbackInfo& info);
        Napi::Value CreateProgram(const Napi::CallbackInfo& info);
        Napi::Value GetUniforms(const Napi::CallbackInfo& info);
        Napi::Value GetAttributes(const Napi::CallbackInfo& info);
        void SetProgram(const Napi::CallbackInfo& info);
        void SetState(const Napi::CallbackInfo& info);
        void SetZOffset(const Napi::CallbackInfo& info);
        Napi::Value GetZOffset(const Napi::CallbackInfo& info);
        void SetDepthTest(const Napi::CallbackInfo& info);
        Napi::Value GetDepthWrite(const Napi::CallbackInfo& info);
        void SetDepthWrite(const Napi::CallbackInfo& info);
        void SetColorWrite(const Napi::CallbackInfo& info);
        void SetBlendMode(const Napi::CallbackInfo& info);
        void SetMatrix(const Napi::CallbackInfo& info);
        void SetInt(const Napi::CallbackInfo& info);
        void SetIntArray(const Napi::CallbackInfo& info);
        void SetIntArray2(const Napi::CallbackInfo& info);
        void SetIntArray3(const Napi::CallbackInfo& info);
        void SetIntArray4(const Napi::CallbackInfo& info);
        void SetFloatArray(const Napi::CallbackInfo& info);
        void SetFloatArray2(const Napi::CallbackInfo& info);
        void SetFloatArray3(const Napi::CallbackInfo& info);
        void SetFloatArray4(const Napi::CallbackInfo& info);
        void SetMatrices(const Napi::CallbackInfo& info);
        void SetMatrix3x3(const Napi::CallbackInfo& info);
        void SetMatrix2x2(const Napi::CallbackInfo& info);
        void SetFloat(const Napi::CallbackInfo& info);
        void SetFloat2(const Napi::CallbackInfo& info);
        void SetFloat3(const Napi::CallbackInfo& info);
        void SetFloat4(const Napi::CallbackInfo& info);
        Napi::Value CreateTexture(const Napi::CallbackInfo& info);
        void LoadTexture(const Napi::CallbackInfo& info);
        void LoadRawTexture(const Napi::CallbackInfo& info);
        void LoadCubeTexture(const Napi::CallbackInfo& info);
        void LoadCubeTextureWithMips(const Napi::CallbackInfo& info);
        Napi::Value GetTextureWidth(const Napi::CallbackInfo& info);
        Napi::Value GetTextureHeight(const Napi::CallbackInfo& info);
        void SetTextureSampling(const Napi::CallbackInfo& info);
        void SetTextureWrapMode(const Napi::CallbackInfo& info);
        void SetTextureAnisotropicLevel(const Napi::CallbackInfo& info);
        void SetTexture(const Napi::CallbackInfo& info);
        void DeleteTexture(const Napi::CallbackInfo& info);
        Napi::Value CreateFrameBuffer(const Napi::CallbackInfo& info);
        void DeleteFrameBuffer(const Napi::CallbackInfo& info);
        void BindFrameBuffer(const Napi::CallbackInfo& info);
        void UnbindFrameBuffer(const Napi::CallbackInfo& info);
        void DrawIndexed(const Napi::CallbackInfo& info);
        void Draw(const Napi::CallbackInfo& info);
        void Clear(const Napi::CallbackInfo& info);
        Napi::Value GetRenderWidth(const Napi::CallbackInfo& info);
        Napi::Value GetRenderHeight(const Napi::CallbackInfo& info);
        void SetViewPort(const Napi::CallbackInfo& info);
        Napi::Value GetHardwareScalingLevel(const Napi::CallbackInfo& info);
        void SetHardwareScalingLevel(const Napi::CallbackInfo& info);
        Napi::Value CreateImageBitmap(const Napi::CallbackInfo& info);
        Napi::Value ResizeImageBitmap(const Napi::CallbackInfo& info);
        void GetFrameBufferData(const Napi::CallbackInfo& info);

        void Draw(bgfx::Encoder* encoder, int fillMode);

        GraphicsImpl::UpdateToken& GetUpdateToken();

        std::shared_ptr<arcana::cancellation_source> m_cancellationSource{};

        ShaderCompiler m_shaderCompiler{};

        ProgramData* m_currentProgram{nullptr};
        arcana::weak_table<std::unique_ptr<ProgramData>> m_programDataCollection{};

        JsRuntime& m_runtime;
        GraphicsImpl& m_graphicsImpl;

        JsRuntimeScheduler m_runtimeScheduler;

        std::optional<GraphicsImpl::UpdateToken> m_updateToken{};

        void ScheduleRequestAnimationFrameCallbacks();
        bool m_requestAnimationFrameCallbacksScheduled{};

        bx::DefaultAllocator m_allocator{};
        uint64_t m_engineState{BGFX_STATE_DEFAULT};

        template<int size, typename arrayType>
        void SetTypeArrayN(const Napi::CallbackInfo& info);

        template<int size>
        void SetFloatN(const Napi::CallbackInfo& info);

        template<int size>
        void SetMatrixN(const Napi::CallbackInfo& info);

        // Scratch vector used for data alignment.
        std::vector<float> m_scratch{};

        std::vector<Napi::FunctionReference> m_requestAnimationFrameCallbacks{};

        const VertexArray* m_boundVertexArray{};
        FrameBuffer* m_boundFrameBuffer{};
    };
}


//          Copyright Jean Pierre Cimalando 2019.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE.md or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#pragma once
#include <gsl/gsl>

template <class Ch> bool string_starts_with(gsl::basic_string_span<const Ch> text, gsl::basic_string_span<const Ch> prefix);
template <class Ch> bool string_ends_with(gsl::basic_string_span<const Ch> text, gsl::basic_string_span<const Ch> suffix);

#include "strings.tcc"


#pragma once

#include <gsl/span>
#include <rapidjson/fwd.h>
#include <spdlog/fwd.h>

#include <memory>

namespace CesiumGltf {
struct Model;
}

namespace Cesium3DTilesSelection {

/**
 * @brief Parses the provided B3DM batch table and adds an equivalent
 * EXT_feature_metadata extension to the provided glTF.
 *
 * @param pLogger
 * @param gltf
 * @param featureTable
 * @param batchTableJson
 * @param batchTableBinaryData
 */
void upgradeBatchTableToFeatureMetadata(
    const std::shared_ptr<spdlog::logger>& pLogger,
    CesiumGltf::Model& gltf,
    const rapidjson::Document& featureTable,
    const rapidjson::Document& batchTableJson,
    const gsl::span<const std::byte>& batchTableBinaryData);

} // namespace Cesium3DTilesSelection


// MIT License
//
// Copyright (c) 2020 SunnyCase
//
// 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.
#pragma once
#include <board.h>
#include <chino/ddk/list.h>
#include <chino/ddk/object.h>
#include <chino/threading.h>
#include <gsl/gsl-lite.hpp>

namespace chino::threading
{
namespace details
{
    struct kthread_checker;
}

struct kprocess;

struct kthread : public ob::object
{
    static constexpr ptrdiff_t PROCESS_THREAD_ENTRY_OFFSET = 0;
    static constexpr ptrdiff_t SCHED_ENTRY_OFFSET = PROCESS_THREAD_ENTRY_OFFSET + VOID_LIST_NODE_SIZE;

    kthread() = default;

    void init_stack(gsl::span<uintptr_t> stack, thread_start_t start, void *arg) noexcept;

    friend struct details::kthread_checker;

    // BEGIN LIST NODES, BE CAREFUL ABOUT THE OFFSETS !!!
    list_node<kthread, void, PROCESS_THREAD_ENTRY_OFFSET> process_threads_entry_;
    list_node<kthread, void, SCHED_ENTRY_OFFSET> sched_entry_;
    // END LIST NODES

    kprocess *owner_ = nullptr;
    tid_t tid_;
    thread_priority priority_;
    std::atomic<uint32_t> exit_code_;
    gsl::span<uintptr_t> stack_;
    arch::thread_context_t context_;
};

namespace details
{
    struct kthread_checker
    {
        static_assert(offsetof(kthread, process_threads_entry_) == kthread::PROCESS_THREAD_ENTRY_OFFSET);
    };
}
}


#pragma once

#define STRICT
#define NOMINMAX
#include <phnt/phnt_windows.h>
#include <phnt/phnt.h>
#pragma comment( lib, "ntdll.lib" )

#include <delayimp.h>
#ifndef _delayimp_h
#define _delayimp_h
#endif
#pragma comment( lib, "delayimp.lib" )

EXTERN_C const IMAGE_DOS_HEADER __ImageBase;

#include <stdlib.h>
#include <stdio.h>
#include <strsafe.h>
#include <stdint.h>

#include <string>
#include <filesystem>
namespace fs = std::filesystem;

#include <codecvt>
#include <gsl/gsl>
#include <wil/token_helpers.h>
#include <wil/resource.h>

#define DETOURS_INTERNAL
#include <detours/detours.h>

#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
#define SPDLOG_WCHAR_TO_UTF8_SUPPORT
#include <spdlog/spdlog.h>
#include <spdlog/sinks/msvc_sink.h>
#include <spdlog/fmt/bin_to_hex.h>


#pragma once

#include <gsl.h>

#include <boost/optional.hpp>

#include <mitkDataStorage.h>
#include <mitkNodePredicateBase.h>

#include <mitkOperationActor.h>

#include "uk_ac_kcl_HierarchyManager_Export.h"

#define DECLARE_HIERARCHY_MANAGER_NODE_TYPE(nodeTypeName) static const crimson::HierarchyManager::NodeType& nodeTypeName();

#define DEFINE_HIERARCHY_MANAGER_NODE_TYPE(containerClass, nodeTypeName)                                                       \
    const crimson::HierarchyManager::NodeType& containerClass::nodeTypeName()                                                  \
    {                                                                                \
        static const crimson::HierarchyManager::NodeType type = crimson::HierarchyManager::getInstance()->createNodeType();    \
        return type;                                                                                \
    }

namespace crimson
{

/*! \brief   A singleton class for managing the hierarchical relations of CRIMSON data objects.
 *
 * The hierarchical relations define the dependencies between various data objects.
 * This mostly affects how the nodes are presented to the user in the MITK's Data Manager view.
 * For example, the vessel paths belonging to the same vessel tree must be grouped under the node
 * representing this vessel tree. Thus, deleting the vessel tree node will also delete the vessel
 * paths belonging to it.
 *
 * Hierarchical grouping also facilitates the discovery of th nodes using the mitk::DataStorage.
 * For example, to find all the contours defining a vessel, it is sufficient to iterate the
 * child nodes of the vessel path and select the nodes containing contours.
 *
 * HierarchyManager allows adding new node types and relationships between them. The most
 * convenient way to do so is to use the DECLARE_HIERARCHY_MANAGER_NODE_TYPE and
 * DEFINE_HIERARCHY_MANAGER_NODE_TYPE macro pair. This will correctly register the node types in
 * the hierarchy mananger.
 *
 * Example usage:
 *
 *     // MyNodeTypes.h
 *     #pragma once
 *     #include <HierarchyManager.h>
 *
 *     struct MyNodeTypes {
 *         DECLARE_HIERARCHY_MANAGER_NODE_TYPE(MyParentNode)
 *         DECLARE_HIERARCHY_MANAGER_NODE_TYPE(MyChildNode)
 *     };
 *
 *     // MyNodeTypes.cpp
 *     #include "MyNodeTypes.h"
 *
 *     DEFINE_HIERARCHY_MANAGER_NODE_TYPE(MyNodeTypes, MyParentNode)
 *     DEFINE_HIERARCHY_MANAGER_NODE_TYPE(MyNodeTypes, MyChildNode)
 *
 *     // UsingHierarchyManager.cpp
 *     void initialize()
 *     {
 *          auto hm = crimson::HierarchyManager::getInstance();
 *          hm->addNodeType(MyNodeTypes::MyParentNode(), ParentNodePredicate::New());
 *          hm->addNodeType(MyNodeTypes::MyChildNode(),  ChildNodePredicate::New());
 *          hm->addRelation(MyNodeTypes::MyParentNode(), MyNodeTypes::MyChildNode(), crimson::HierarchyManager::rtOneToMany);
 *     }
 *
 *     void addNode(mitk::DataNode* parent, mitkDataNode* child)
 *     {
 *          auto hm = crimson::HierarchyManager::getInstance();
 *          hm->addNodeToHierarchy(parent, MyNodeTypes::MyParentNode(), child, MyNodeTypes::MyChildNode());
 *          // ...
 *     }
 */

class HIERARCHYMANAGER_EXPORT HierarchyManager : public itk::Object, public mitk::OperationActor
{
public:
    /*! \name Singleton interface */
    ///@{
    static bool init();
    static HierarchyManager* getInstance();
    static void term();
    ///@}

    using NodeType = int;

    /*!
     * \brief   Creates a unique id for a new node type.
     */
    int createNodeType() { return _lastAssignedNodeType++; }

    /*! \brief   Values that represent relation types between parent and child nodes. */
    enum RelationType {
        rtOneToOne = 0, ///< Only one child of a particular type is allowed for the parent
        rtOneToMany, ///< Multiple children of a particular type are allowed for the parent
        rtUnknown   ///< No information about the relations between types
    };

    /*! \brief   Values that represent node type flags. */
    enum NodeTypeFlags {
        ntfNone = 0x00, ///< No flags
        ntfRecursiveDeletion = 0x01,    ///< Deleting a parent node also deletes all its children
        ntfUndoableDeletion = 0x02, ///< If the node is deleted, it should be put onto undo stack to allow deletion undo
        ntfPickable = 0x04  ///< The node should be allowed to be picked with mouse clicks in 3D rendering window
    };

    ///@{
    /*!
     * \brief   Adds a new node type.
     *
     * \param   type        The new node type identifier.
     * \param   predicate   The predicate defining the node.
     * \param   flags       The flags to be applied for nodes of this type.
     */
    bool addNodeType(const NodeType& type, const mitk::NodePredicateBase::Pointer& predicate, int flags = ntfNone);

    /*!
     * \brief   Adds a relation between the parent and child node types.
     *
     * \param   parentType  Type of the parent.
     * \param   childType   Type of the child.
     * \param   relation    The type of relation.
     */
    bool addRelation(const NodeType& parentType, const NodeType& childType, const RelationType& relation);

    /*!
     * \brief   Gets a relation between the parent and child node types.
     *
     * \param   parentNodeType  Type of the parent node.
     * \param   childNodeType   Type of the child node.
     */
    RelationType getRelation(const NodeType& parentNodeType, const NodeType& childNodeType) const;
    ///@}

    /*!
     * \brief   Gets data storage that the HierarchyManager operates upon.
     */
    mitk::DataStorage::Pointer getDataStorage() const;

    /*!
     * \brief   Set the flag whether to start a new undo group when adding nodes to hierarchy.
     *
     *  By default, addNodeToHierarchy() will start a new undo group meaning that undoing the
     *  addition will remove nodes one by one. However, when multiple nodes are to be added as a
     *  single unit, set this flag to false (and reset it to true after all nodes are added).
     */
    void setStartNewUndoGroup(bool start);

    /*!
     * \brief   Determine if a child node of a particular type can be added to the parent node of a different type.
     *
     * \param   parentNode          The desired parent node.
     * \param   parentNodeType      Type of the parent node.
     * \param   childNodeType       Type of the child node.
     * \param   allowReplacement    true if replacing a node is allowed (useful for rtOneToOne relationship).
     */
    bool canAddNode(mitk::DataNode* parentNode, const NodeType& parentNodeType, const NodeType& childNodeType,
                    bool allowReplacement) const;

    /*!
     * \brief   Adds a node to hierarchy.
     *
     * \param   parentNode      The parent node.
     * \param   parentNodeType  Type of the parent node.
     * \param   newNode         The new node.
     * \param   newNodeType     Type of the new node.
     *
     * \return  false if the relationship between the node types is unknown.
     */
    bool addNodeToHierarchy(const mitk::DataNode* parentNode, const NodeType& parentNodeType, const mitk::DataNode* newNode,
                            const NodeType& newNodeType);

    /*!
     * \brief   Searches for the first node type that the node satisfies.
     */
    boost::optional<NodeType> findFittingNodeType(mitk::DataNode* node) const;

    /*!
     * \brief   Searches for the potential parents of the node with a particular nodeType.
     */
    std::unordered_set<mitk::DataNode*> findPotentialParents(mitk::DataNode* node, NodeType nodeType) const;

    /*!
     * \brief   Change the parent of the node.
     */
    bool reparentNode(const mitk::DataNode::Pointer& node, const mitk::DataNode::Pointer& newParent);

    /*!
     * \brief   Gets a predicate associated with the node type.
     */
    mitk::NodePredicateBase::Pointer getPredicate(const NodeType& type) const;

    ///@{
    /*!
     * \brief   Gets an ancestor of the node of a particular type.
     *
     * \param   node        The child node.
     * \param   parentType  Type of the parent.
     * \param   directOnly  false to search parents of parents.
     */
    mitk::DataNode::Pointer getAncestor(const mitk::DataNode* node, const NodeType& parentType, bool directOnly = false) const;

    /*!
     * \brief   Gets the first descendant node of a particular type.
     *
     * \param   node            The parent node.
     * \param   descendantType  Type of the descendant.
     * \param   directOnly      false to search children of children.
     */
    mitk::DataNode::Pointer getFirstDescendant(const mitk::DataNode* node, const NodeType& descendantType,
                                               bool directOnly = false) const;

    /*!
     * \brief   Gets all the descendant nodes of a particular type.
     *
     * \param   node            The parent node.
     * \param   descendantsType Type of the descendants.
     * \param   directOnly      false to search children of children.
     */
    mitk::DataStorage::SetOfObjects::ConstPointer getDescendants(const mitk::DataNode* node, const NodeType& descendantsType,
                                                                 bool directOnly = false) const;

    ///@}

    static const char* nodeUIDPropertyName; ///< The name of the DataNode property where the nodeUID is stored

    /*!
     * \brief   Searches for the node with a particular UID.
     */
    mitk::DataNode::Pointer findNodeByUID(gsl::cstring_span<> nodeUID) const;

    /*!
     * \brief   Enables/disables the undo for adding and deleting nodes.
     */
    void enableUndo(bool enable);

    /*!
     * \brief   Overriden from mitk::Operation for undo/redo support.
     */
    void ExecuteOperation(mitk::Operation* operation) override;

private:
    HierarchyManager();
    ~HierarchyManager();

    HierarchyManager(const HierarchyManager&) = delete;
    HierarchyManager& operator=(const HierarchyManager&) = delete;

    void _connectDataStorageEvents();
    void _disconnectDataStorageEvents();

    void nodeAdded(const mitk::DataNode*);
    void nodeRemoved(const mitk::DataNode*);

private:
    static HierarchyManager* _instance;

    struct HierarchyManagerImpl;

    std::unique_ptr<HierarchyManagerImpl> _impl;

    int _lastAssignedNodeType = 0;

    bool _testFlags(const mitk::DataNode* node, NodeTypeFlags flags) const;
    std::vector<std::pair<std::vector<const mitk::DataNode*>, mitk::DataNode::ConstPointer>>
    _getUndoableRemoveNodes(const mitk::DataNode* node) const;
};

} // namespace crimson


#pragma once

#include "CesiumGltfWriter/Library.h"

#include <CesiumJsonWriter/ExtensionWriterContext.h>

#include <gsl/span>

// forward declarations
namespace CesiumGltf {
struct Model;
}

namespace CesiumGltfWriter {

/**
 * @brief The result of writing a glTF with
 * {@link GltfWriter::writeGltf} or {@link GltfWriter::writeGlb}
 */
struct CESIUMGLTFWRITER_API GltfWriterResult {
  /**
   * @brief The final generated std::vector<std::byte> of the glTF or glb.
   */
  std::vector<std::byte> gltfBytes;

  /**
   * @brief Errors, if any, that occurred during the write process.
   */
  std::vector<std::string> errors;

  /**
   * @brief Warnings, if any, that occurred during the write process.
   */
  std::vector<std::string> warnings;
};

/**
 * @brief Options for how to write a glTF.
 */
struct CESIUMGLTFWRITER_API GltfWriterOptions {
  /**
   * @brief If the glTF JSON should be pretty printed. Usable with glTF or GLB
   * (not advised).
   */
  bool prettyPrint = false;

  /**
   * @brief Byte alignment of the GLB binary chunk. When using 64-bit types in
   * EXT_mesh_features or EXT_feature_metadata this value should be set to 8.
   */
  size_t binaryChunkByteAlignment = 4;
};

/**
 * @brief Writes glTF.
 */
class CESIUMGLTFWRITER_API GltfWriter {
public:
  /**
   * @brief Constructs a new instance.
   */
  GltfWriter();

  /**
   * @brief Gets the context used to control how glTF extensions are written.
   */
  CesiumJsonWriter::ExtensionWriterContext& getExtensions();

  /**
   * @brief Gets the context used to control how glTF extensions are written.
   */
  const CesiumJsonWriter::ExtensionWriterContext& getExtensions() const;

  /**
   * @brief Serializes the provided model into a glTF JSON byte vector.
   *
   * @details Ignores internal data such as {@link CesiumGltf::BufferCesium}
   * and {@link CesiumGltf::ImageCesium} when serializing the glTF. Internal
   * data must either be converted to data uris or saved as external files. The
   * buffer.uri and image.uri fields must be set accordingly prior to calling
   * this function.
   *
   * @param model The model.
   * @param options Options for how to write the glTF.
   * @return The result of writing the glTF.
   */
  GltfWriterResult writeGltf(
      const CesiumGltf::Model& model,
      const GltfWriterOptions& options = GltfWriterOptions()) const;

  /**
   * @brief Serializes the provided model into a glb byte vector.
   *
   * @details The first buffer object implicitly refers to the GLB binary chunk
   * and should not have a uri. Ignores internal data such as
   * {@link CesiumGltf::BufferCesium} and {@link CesiumGltf::ImageCesium}.
   *
   * @param model The model.
   * @param bufferData The buffer data to store in the GLB binary chunk.
   * @param options Options for how to write the glb.
   * @return The result of writing the glb.
   */
  GltfWriterResult writeGlb(
      const CesiumGltf::Model& model,
      const gsl::span<const std::byte>& bufferData,
      const GltfWriterOptions& options = GltfWriterOptions()) const;

private:
  CesiumJsonWriter::ExtensionWriterContext _context;
};

} // namespace CesiumGltfWriter


#pragma once

#include <winrt\Windows.Foundation.h>
#include <d3d11.h>
#include <gsl\gsl>

namespace Library
{
	class BlendStates final
	{
	public:
		inline static winrt::com_ptr<ID3D11BlendState> AlphaBlending;
		inline static winrt::com_ptr<ID3D11BlendState> MultiplicativeBlending;

		static void Initialize(gsl::not_null<ID3D11Device*> direct3DDevice);
		static void Shutdown();

		BlendStates() = delete;
		BlendStates(const BlendStates&) = delete;
		BlendStates& operator=(const BlendStates&) = delete;
		BlendStates(BlendStates&&) = delete;
		BlendStates& operator=(BlendStates&&) = delete;
		~BlendStates() = default;
	};
}


// Copyright (c) 2021 SmartPolarBear
//
// 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.

//
// Created by cleve on 9/1/2021.
//
#pragma once

#include <base/iterable_stack.h>

#include <interpreter/vm/opcode.h>
#include <interpreter/vm/chunk.h>
#include <interpreter/vm/value.h>
#include <interpreter/vm/exceptions.h>

#include <interpreter/vm/heap.h>
#include <interpreter/vm/heap_allocator.h>
#include <interpreter/vm/garbage_collector.h>

#include <interpreter/vm/string_object.h>
#include <interpreter/vm/closure_object.h>
#include <interpreter/vm/instance_object.h>

#include <memory>
#include <map>
#include <ranges>

#include <gsl/gsl>
#include "class_object.h"

namespace clox::interpreting::vm
{

enum class virtual_machine_status
{
	OK,
	RUNTIME_ERROR,
};

template<typename F, typename R, class ...Args>
concept BinaryOperator=
requires(F&& f, Args&& ... args) {
	{ std::invoke(std::forward<F>(f), std::forward<Args>(args)...) }->std::same_as<R>;
};

class virtual_machine final
{
public:
	friend class garbage_collector;

	static inline constexpr size_t CALL_STACK_RESERVED_SIZE = 64;
	static inline constexpr size_t STACK_RESERVED_SIZE = 16384;

	using value_list_type = std::vector<value>;
	using global_table_type = std::unordered_map<std::string, value>;
	using function_table_type = std::unordered_map<full_opcode_type, value>;
	using ip_type = chunk::iterator_type;

	using index_type = gsl::index;

	class call_frame final
	{
	public:

	public:

		explicit call_frame(closure_object_raw_pointer closure, ip_type ip, size_t offset)
				: closure_(closure), ip_(ip), stack_offset_(offset)
		{
		}

		[[nodiscard]] size_t stack_offset() const
		{
			return stack_offset_;
		}

		[[nodiscard]] function_object_raw_pointer function() const
		{
			return closure_->function();
		}

		[[nodiscard]] closure_object_raw_pointer closure() const
		{
			return closure_;
		}

		[[nodiscard]] ip_type& ip()
		{
			return ip_;
		}

	private:
		closure_object_raw_pointer closure_{};
		ip_type ip_{};
		size_t stack_offset_{};
	};

	using call_frame_list_type = std::vector<call_frame>;

public:
	virtual_machine() = delete;

	~virtual_machine();

	explicit virtual_machine(helper::console& cons,
			std::shared_ptr<object_heap> heap);

	virtual_machine_status run(clox::interpreting::vm::closure_object* closure);

private:
	virtual_machine_status run();

	// {return status, exit}
	std::tuple<std::optional<virtual_machine_status>, bool> run_code(chunk::code_type instruction, call_frame& frame);

	template<class ...TArgs>
	void runtime_error(std::string_view fmt, const TArgs& ...args)
	{

		cons_->error() << std::format("[Line {}] in file {}:",
				top_call_frame().function()->body()->line_of(top_call_frame().ip()),
				top_call_frame().function()->body()->filename()) << std::endl;

		cons_->error() << std::format(fmt, args...) << "\n";

		cons_->error() << "Call stack:" << std::endl;
		for (auto& frm: call_frames_ | std::ranges::views::reverse)
		{
			auto func = frm.function();
			auto line = func->body()->line_of(frm.ip() - 1);
			cons_->error() << std::format("[Line {}] in ", line);
			if (func->name().empty())
			{
				cons_->error() << "script" << std::endl;
			}
			else
			{
				cons_->error() << func->name() << std::endl;
			}
		}

		reset_stack();
	}

	template<typename TOp>
	requires BinaryOperator<TOp, floating_value_type, floating_value_type, floating_value_type>
	inline void binary_op(TOp op)
	{
		try
		{
			auto l = peek(0), r = peek(1);

			auto right = get_number_promoted(l);

			auto left = get_number_promoted(r);

			auto ret = op(left, right);

			if (std::holds_alternative<floating_value_type>(l) ||
				std::holds_alternative<floating_value_type>(r))
			{
				pop_two_and_push(ret);
			}
			else if (std::holds_alternative<integer_value_type>(l) ||
					 std::holds_alternative<integer_value_type>(r))
			{
				pop_two_and_push(static_cast<integer_value_type>(ret));
			}
			else if (std::holds_alternative<boolean_value_type>(l) ||
					 std::holds_alternative<boolean_value_type>(r))
			{
				pop_two_and_push(static_cast<scanning::boolean_literal_type>(ret));
			}
			else
			{
				pop_two_and_push(
						static_cast<integer_value_type>(ret)); // cannot combine for the sake of the rules of type promoting
			}
		}
		catch (const std::exception& e)
		{
			this->runtime_error("Invalid operands for binary operator: {}", e.what());
			throw e;
		}
	}

	template<typename TOp>
	requires BinaryOperator<TOp, object_raw_pointer, string_object_raw_pointer, string_object_raw_pointer>
	inline void binary_op(TOp op)
	{
		try
		{
			auto right = get_string(peek(0));
			auto left = get_string(peek(1));

			pop_two_and_push(op(left, right));
		}
		catch (const std::exception& e)
		{
			this->runtime_error("Invalid operands for binary operator: {}", e.what());
			throw e;
		}
	}

	// for comparing, whose op returns bool value
	template<typename TOp>
	requires BinaryOperator<TOp, bool, floating_value_type, floating_value_type>
	inline void binary_op(TOp op)
	{
		try
		{
			auto right = get_number_promoted(peek(0));
			auto left = get_number_promoted(peek(1));

			pop_two_and_push(op(left, right));
		}
		catch (const std::exception& e)
		{
			this->runtime_error("Invalid operands for binary operator: {}", e.what());
			throw e;
		}
	}

	template<typename TOp>
	requires BinaryOperator<TOp, bool, string_object_raw_pointer, string_object_raw_pointer>
	inline void binary_op(TOp op)
	{
		try
		{
			auto right = get_string(peek(0));
			auto left = get_string(peek(1));

			pop_two_and_push(op(left, right));
		}
		catch (const std::exception& e)
		{
			this->runtime_error("Invalid operands for binary operator: {}", e.what());
			throw e;
		}
	}

	void call_value(const value& val, size_t arg_count);

	void call(closure_object_raw_pointer closure, size_t arg_count);

	bool is_false(const value& val);

	[[maybe_unused]] bool is_true(const value& val)
	{
		return !is_false(val);
	}

	// stack modification
	void reset_stack();

	template<object_pointer T>
	T peek_object(size_t offset = 0)
	{
		return std::visit([](auto&& val) -> T
		{
			using TV = std::decay_t<decltype(val)>;
			if constexpr (std::is_same_v<TV, object_raw_pointer>)
			{
				if (auto func = dynamic_cast<T>(val);func)
				{
					return func;
				}
				else
				{
					throw invalid_value{ val };
				}
			}
			else
			{
				throw invalid_value{ val };
			}
		}, peek(offset));
	}

	value peek(size_t offset = 0);

	value pop();

	void push(const value& val);

	inline void pop_two_and_push(const value& val);
	//

	// instruction reading
	value next_constant();

	std::string next_variable_name();

	chunk::code_type next_code();

	value& slot_at(const call_frame& frame, size_t slot);

	upvalue_object_raw_pointer capture_upvalue(value* val, index_type stack_index);

	void close_upvalues(index_type last);

	// call frame

	call_frame& top_call_frame()
	{
		return *call_frames_.rbegin();
	}

	void push_call_frame(closure_object_raw_pointer closure, chunk::iterator_type ip, size_t stack_offset)
	{
		call_frames_.emplace_back(closure, ip, stack_offset);
	}

	void pop_call_frame()
	{
		call_frames_.pop_back();
	}

	//

	// method
	bool bind_method(class_object_raw_pointer class_obj, resolving::function_id_type id);

	bool bind_method(instance_object_raw_pointer class_obj, resolving::function_id_type id);

	std::shared_ptr<object_heap> heap_{};

	value_list_type stack_{};

	global_table_type globals_{};

	function_table_type functions_{};

	call_frame_list_type call_frames_{};

	std::map<index_type, upvalue_object_raw_pointer> open_upvalues_{}; // it should be ordered

	mutable helper::console* cons_{ nullptr };
};

}


#pragma once
#include "utility/types.h"
#include "utility/c++std/optional.h"
#include <gsl/gsl>
#include <vector>
#include <string>

namespace cws80 {

enum class FileChooserMode {
    Open,
    Save,
};

struct FileChooserFilter {
    const char *name;
    std::vector<const char *> patterns;
};

class NativeUI {
public:
    virtual ~NativeUI() {}

    static NativeUI *create();

    virtual std::string choose_file(gsl::span<const FileChooserFilter> filters, const std::string &directory, const std::string &title, FileChooserMode mode) = 0;
    virtual cxx::optional<std::string> edit_line(const std::string &title, const std::string &initial_value) = 0;
    virtual uint select_by_menu(gsl::span<const std::string> choices, uint initial_selection) = 0;
};

}  // namespace cws80


#pragma once
//=============================================================================
// EXTERNAL DECLARATIONS
//=============================================================================
#include "Core/Components/IComponentInterface.h"
#include "Core/Components/IdType.h"
#include <memory>
#include <gsl/span>

namespace engine
{

//=============================================================================
// FORWARD DECLARATIONS
//=============================================================================
class IGameObject;
using GameObjectRef = std::shared_ptr<IGameObject>;
using GameObjectWeakRef = std::weak_ptr<IGameObject>;

//=============================================================================
// INTERFACE IComponent
//=============================================================================
class IComponent
{
public:
	virtual ~IComponent() {}

public:
	virtual gsl::span<IdType> interfaces() = 0;
	virtual void onAttached(const GameObjectRef &iGameObject) = 0;
	virtual void onDetached(const GameObjectRef &iGameObject) = 0;
};

} // namespace engine


#ifndef PCH_H
#define PCH_H
#pragma once
// add tat ca cac cai thu vien, ham thuong xuyen dung trong suot chuong trinh
#include <fmt/format.h>
#include <QtCore/QObject>
#include <QtSql/QtSql>
#include <any>
#include <gsl/gsl>
#include <memory>
#include <optional>
#include "common.inl"
#include "database.inl"
#include "macros.inl"
#endif  // !PCH_H


#pragma once

#include "halley_gl.h"
#include <gsl/gsl>

namespace Halley
{
	class GLBuffer
	{
	public:
		GLBuffer();
		~GLBuffer();

		void bind();
		void bindToTarget(GLuint index);
		void init(GLenum target, GLenum usage = GL_STREAM_DRAW);
		void setData(gsl::span<const gsl::byte> data);
		size_t getSize() const;

	private:
		GLenum target = 0;
		GLenum usage = 0;
        GLuint name = 0;
		size_t capacity = 0;
		size_t size = 0;
	};
}


#pragma once

#include <string_view>
#include <gsl/span>

namespace kab_advent {
	auto day(gsl::span<std::string_view const> args) -> int;
}


#pragma once

#include <errno.h>  // errno
#include <fcntl.h>  // open, write
#include <unistd.h> // getpid
#include <sstream>
#include <boost/filesystem.hpp>
#include <gsl/gsl_util>
#include "do_persistence.h"
#include "error_macros.h"

// RAII wrapper for creating, writing and deleting the file that will
// contain the port number for the REST interface.
class RestPortAdvertiser
{
public:
    RestPortAdvertiser(uint16_t port)
    {
        // We cannot remove the port file on shutdown because we have already dropped permissions.
        // Clean it up now when we are still running as root.
        _DeleteOlderPortFiles();

        std::stringstream ss;
        ss << docli::GetRuntimeDirectory() << '/' << _restPortFileNamePrefix << '.' << getpid();
        _outFilePath = ss.str();

        // If file already exists, it is truncated. Probably from an old instance that terminated abnormally.
        // Allow file to only be read by others.
        int fd = open(_outFilePath.data(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IRGRP | S_IROTH);
        if (fd == -1)
        {
            THROW_HR_MSG(E_FAIL, "Failed to open file %s, errno: %d", _outFilePath.data(), errno);
        }

        try
        {
            const auto writeStr = std::to_string(port) + '\n';
            const auto cbWrite = gsl::narrow_cast<ssize_t>(writeStr.size() * sizeof(char));

            const ssize_t written = write(fd, writeStr.data(), cbWrite);
            if (written != cbWrite)
            {
                THROW_HR_MSG(E_FAIL, "Failed to write port, written: %zd, errno: %d", written, errno);
            }
        }
        catch (...)
        {
            (void)close(fd);
            throw;
        }
        (void)close(fd);
    }

    const std::string& OutFilePath() const { return _outFilePath; }

private:
    void _DeleteOlderPortFiles() try
    {
        auto& runtimeDirectory = docli::GetRuntimeDirectory();
        for (boost::filesystem::directory_iterator itr(runtimeDirectory); itr != boost::filesystem::directory_iterator(); ++itr)
        {
            auto& dirEntry = itr->path();
            if (dirEntry.filename().string().find(_restPortFileNamePrefix) != std::string::npos)
            {
                boost::system::error_code ec;
                boost::filesystem::remove(dirEntry, ec);
                if (ec)
                {
                    DoLogWarning("Failed to delete old port file (%d, %s) %s", ec.value(), ec.message().data(), dirEntry.string().data());
                }
            }
        }
    } CATCH_LOG()

    std::string _outFilePath;
    static constexpr const char* const _restPortFileNamePrefix = "restport";
};


/*
 *     Copyright 2021-Present Couchbase, Inc.
 *
 *   Use of this software is governed by the Business Source License included
 *   in the file licenses/BSL-Couchbase.txt.  As of the Change Date specified
 *   in that file, in accordance with the Business Source License, use of this
 *   software will be governed by the Apache License, Version 2.0, included in
 *   the file licenses/APL2.txt.
 */
#pragma once
#define MEMCACHED_ENGINE_H

#include <sys/types.h>
#include <functional>
#include <memory>
#include <string_view>
#include <unordered_set>
#include <utility>

#include <gsl/gsl>
#include <optional>

#include <memcached/visibility.h>

#include "memcached/collections.h"
#include "memcached/engine_common.h"
#include "memcached/thread_pool_config.h"
#include "memcached/types.h"
#include "memcached/vbucket.h"

namespace cb::durability {
class Requirements;
} // namespace cb::durability

namespace cb::mcbp {
class Request;
} // namespace cb::mcbp

namespace cb::prometheus {
enum class Cardinality;
} // namespace cb::prometheus

class BucketStatCollector;
class StatCollector;

/*! \mainpage memcached public API
 *
 * \section intro_sec Introduction
 *
 * The memcached project provides an API for providing engines as well
 * as data definitions for those implementing the protocol in C.  This
 * documentation will explain both to you.
 *
 * \section docs_sec API Documentation
 *
 * Jump right into the modules docs to get started.
 *
 * \example default_engine.cc
 */

/**
 * \defgroup Engine Storage Engine API
 * \defgroup Protex Protocol Extension API
 * \defgroup Protocol Binary Protocol Structures
 *
 * \addtogroup Engine
 * @{
 *
 * Most interesting here is to implement engine_interface_v1 for your
 * engine.
 */

struct DocKey;
struct ServerBucketIface;
struct ServerCoreIface;
struct ServerCallbackIface;
struct ServerLogIface;
struct ServerCookieIface;
struct ServerDocumentIface;
union protocol_binary_request_header;

struct ServerApi {
    ServerCoreIface* core = nullptr;
    ServerCallbackIface* callback = nullptr;
    ServerLogIface* log = nullptr;
    ServerCookieIface* cookie = nullptr;
    ServerDocumentIface* document = nullptr;
    ServerBucketIface* bucket = nullptr;
};

using GET_SERVER_API = ServerApi* (*)();

namespace cb {
using EngineErrorItemPair = std::pair<cb::engine_errc, cb::unique_item_ptr>;

using EngineErrorMetadataPair = std::pair<engine_errc, item_info>;

enum class StoreIfStatus {
    Continue,
    Fail,
    GetItemInfo // please get me the item_info
};

using StoreIfPredicate = std::function<StoreIfStatus(
        const std::optional<item_info>&, cb::vbucket_info)>;

struct EngineErrorCasPair {
    engine_errc status;
    uint64_t cas;
};

/// Result of getVBucketHlcNow()
struct HlcTime {
    enum class Mode { Real, Logical };

    /// Seconds since Unix epoch.
    std::chrono::seconds now;
    Mode mode;
};
} // namespace cb

/**
 * The different compression modes that a bucket supports
 */
enum class BucketCompressionMode : uint8_t {
    Off,     //Data will be stored as uncompressed
    Passive, //Data will be stored as provided by the client
    Active   //Bucket will actively try to compress stored
             //data
};

/* The default minimum compression ratio */
static const float default_min_compression_ratio = 1.2f;

/* The default maximum size for a value */
static const size_t default_max_item_size = 20 * 1024 * 1024;

namespace cb::engine {
/**
 * Definition of the features that an engine can support
 */
enum class Feature : uint16_t {
    Collections = 1,
};

using FeatureSet = std::unordered_set<Feature>;
} // namespace cb::engine

namespace std {
template <>
struct hash<cb::engine::Feature> {
public:
    size_t operator()(const cb::engine::Feature& f) const {
        return static_cast<size_t>(f);
    }
};
} // namespace std

/**
 * Definition of the first version of the engine interface
 */
struct MEMCACHED_PUBLIC_CLASS EngineIface {
    virtual ~EngineIface() = default;

    /**
     * Initialize an engine instance.
     * This is called *after* creation, but before the engine may be used.
     *
     * @param handle the engine handle
     * @param config_str configuration this engine needs to initialize itself.
     */
    virtual cb::engine_errc initialize(const char* config_str) = 0;

    /**
     * Tear down this engine.
     *
     * @param force the flag indicating the force shutdown or not.
     */
    virtual void destroy(bool force) = 0;

    /// Callback that a cookie will be disconnected
    virtual void disconnect(gsl::not_null<const void*> cookie){};

    /**
     * Initiate the bucket shutdown logic (disconnect clients etc)
     */
    virtual void initiate_shutdown() {
        // empty
    }

    // Set the number or reader threads
    virtual void set_num_reader_threads(ThreadPoolConfig::ThreadCount num) {
        // ignored
    }

    // Set the number or writer threads
    virtual void set_num_writer_threads(ThreadPoolConfig::ThreadCount num) {
        // ignored
    }

    // Set the number of storage threads
    virtual void set_num_storage_threads(
            ThreadPoolConfig::StorageThreadCount num) {
        // ignored
    }

    /**
     * Request the engine to cancel all of the ongoing requests which
     * may have cookies in an ewouldblock state.
     *
     * This method is to removed in CC when we'll tighten the logic for
     * bucket deletion to use the following logic:
     *
     * 1) Stop any new requests into the engine.
     * 2) Tell the engine to complete (cancel) anything currently in-flight
     *    (this notification holds a write lock to the engine so it won't
     *    race with any front end threads)
     * 3) wait for in-flight ops (i.e. step B) to finish then delete bucket.
     *
     * In Mad-Hatter initiate_shutdown may race with all of the frontend
     * worker threads, and could lead to operations being added after we've
     * inspected the vbucket. To work around that problem this new method
     * was introduced and will be called multiple times during bucket
     * deletion to work around potential race situations.
     */
    virtual void cancel_all_operations_in_ewb_state() {
        // empty
    }

    /*
     * Item operations.
     */

    /**
     * Allocate an item (extended API)
     *
     * @param cookie The cookie provided by the frontend
     * @param key the item's key
     * @param nbytes the number of bytes that will make up the
     *               value of this item.
     * @param priv_nbytes The number of bytes in nbytes containing
     *                    system data (and may exceed the item limit).
     * @param flags the item's flags
     * @param exptime the maximum lifetime of this item
     * @param vbucket virtual bucket to request allocation from
     * @return pair containing the item and the items information
     * @thows cb::engine_error with:
     *
     *   * `cb::engine_errc::no_bucket` The client is bound to the dummy
     *                                  `no bucket` which don't allow
     *                                  allocations.
     *
     *   * `cb::engine_errc::no_memory` The bucket is full
     *
     *   * `cb::engine_errc::too_big` The requested memory exceeds the
     *                                limit set for items in the bucket.
     *
     *   * `cb::engine_errc::disconnect` The client should be disconnected
     *
     *   * `cb::engine_errc::not_my_vbucket` The requested vbucket belongs
     *                                       to someone else
     *
     *   * `cb::engine_errc::temporary_failure` Temporary failure, the
     *                                          _client_ should try again
     *
     *   * `cb::engine_errc::too_busy` Too busy to serve the request,
     *                                 back off and try again.
     */
    virtual std::pair<cb::unique_item_ptr, item_info> allocateItem(
            gsl::not_null<const void*> cookie,
            const DocKey& key,
            size_t nbytes,
            size_t priv_nbytes,
            int flags,
            rel_time_t exptime,
            uint8_t datatype,
            Vbid vbucket) = 0;

    /**
     * Remove an item.
     *
     * @param cookie The cookie provided by the frontend
     * @param key the key identifying the item to be removed
     * @param cas The cas to value to use for delete (or 0 as wildcard)
     * @param vbucket the virtual bucket id
     * @param durability the durability specifier for the command
     * @param mut_info On a successful remove write the mutation details to
     *                 this address.
     *
     * @return cb::engine_errc::success if all goes well
     */
    virtual cb::engine_errc remove(
            gsl::not_null<const void*> cookie,
            const DocKey& key,
            uint64_t& cas,
            Vbid vbucket,
            const std::optional<cb::durability::Requirements>& durability,
            mutation_descr_t& mut_info) = 0;

    /**
     * Indicate that a caller who received an item no longer needs
     * it.
     *
     * @param item the item to be released
     */
    virtual void release(gsl::not_null<ItemIface*> item) = 0;

    /**
     * Retrieve an item.
     *
     * @param cookie The cookie provided by the frontend
     * @param item output variable that will receive the located item
     * @param key the key to look up
     * @param vbucket the virtual bucket id
     * @param documentStateFilter The document to return must be in any of
     *                            of these states. (If `Alive` is set, return
     *                            KEY_ENOENT if the document in the engine
     *                            is in another state)
     *
     * @return cb::engine_errc::success if all goes well
     */
    virtual cb::EngineErrorItemPair get(gsl::not_null<const void*> cookie,
                                        const DocKey& key,
                                        Vbid vbucket,
                                        DocStateFilter documentStateFilter) = 0;

    /**
     * Optionally retrieve an item. Only non-deleted items may be fetched
     * through this interface (Documents in deleted state may be evicted
     * from memory and we don't want to go to disk in order to fetch these)
     *
     * @param cookie The cookie provided by the frontend
     * @param key the key to look up
     * @param vbucket the virtual bucket id
     * @param filter callback filter to see if the item should be returned
     *               or not. If filter returns false the item should be
     *               skipped.
     *               Note: the filter is applied only to the *metadata* of the
     *               item_info - i.e. the `value` should not be expected to be
     *               present when filter is invoked.
     * @return A pair of the error code and (optionally) the item
     */
    virtual cb::EngineErrorItemPair get_if(
            gsl::not_null<const void*> cookie,
            const DocKey& key,
            Vbid vbucket,
            std::function<bool(const item_info&)> filter) = 0;

    /**
     * Retrieve metadata for a given item.
     *
     * @param cookie The cookie provided by the frontend
     * @param key the key to look up
     * @param vbucket the virtual bucket id
     *
     * @return  Pair (cb::engine_errc::success, Metadata) if all goes well
     */
    virtual cb::EngineErrorMetadataPair get_meta(
            gsl::not_null<const void*> cookie,
            const DocKey& key,
            Vbid vbucket) = 0;

    /**
     * Lock and Retrieve an item.
     *
     * @param cookie The cookie provided by the frontend
     * @param key the key to look up
     * @param vbucket the virtual bucket id
     * @param lock_timeout the number of seconds to hold the lock
     *                     (0 == use the engines default lock time)
     *
     * @return A pair of the error code and (optionally) the item
     */
    virtual cb::EngineErrorItemPair get_locked(
            gsl::not_null<const void*> cookie,
            const DocKey& key,
            Vbid vbucket,
            uint32_t lock_timeout) = 0;

    /**
     * Unlock an item.
     *
     * @param cookie The cookie provided by the frontend
     * @param key the key to look up
     * @param vbucket the virtual bucket id
     * @param cas the cas value for the locked item
     *
     * @return cb::engine_errc::success if all goes well
     */
    virtual cb::engine_errc unlock(gsl::not_null<const void*> cookie,
                                   const DocKey& key,
                                   Vbid vbucket,
                                   uint64_t cas) = 0;

    /**
     * Get and update the expiry time for the document
     *
     * @param cookie The cookie provided by the frontend
     * @param key the key to look up
     * @param vbucket the virtual bucket id
     * @param expirytime the new expiry time for the object
     * @param durability An optional durability requirement
     * @return A pair of the error code and (optionally) the item
     */
    virtual cb::EngineErrorItemPair get_and_touch(
            gsl::not_null<const void*> cookie,
            const DocKey& key,
            Vbid vbucket,
            uint32_t expirytime,
            const std::optional<cb::durability::Requirements>& durability) = 0;

    /**
     * Store an item into the underlying engine with the given
     * state. If the DocumentState is set to DocumentState::Deleted
     * the document shall not be returned unless explicitly asked for
     * documents in that state, and the underlying engine may choose to
     * purge it whenever it please.
     *
     * @param cookie The cookie provided by the frontend
     * @param item the item to store
     * @param cas the CAS value for conditional sets
     * @param semantics the semantics of the store operation
     * @param durability An optional durability requirement
     * @param document_state The state the document should have after
     *                       the update
     * @param preserveTtl if set to true the existing documents TTL should
     *                    be used.
     *
     * @return cb::engine_errc::success if all goes well
     */
    virtual cb::engine_errc store(
            gsl::not_null<const void*> cookie,
            gsl::not_null<ItemIface*> item,
            uint64_t& cas,
            StoreSemantics semantics,
            const std::optional<cb::durability::Requirements>& durability,
            DocumentState document_state,
            bool preserveTtl) = 0;

    /**
     * Store an item into the underlying engine with the given
     * state only if the predicate argument returns true when called against an
     * existing item.
     *
     * Optional interface; not supported by all engines.
     *
     * @param cookie The cookie provided by the frontend
     * @param item the item to store
     * @param cas the CAS value for conditional sets
     * @param semantics the semantics of the store operation
     * @param predicate a function that will be called from the engine the
     *                  result of which determines how the store behaves.
     *                  The function is given any existing item's item_info (as
     *                  a std::optional) and a cb::vbucket_info object. In the
     *                  case that the optional item_info is not initialised the
     *                  function can return cb::StoreIfStatus::GetInfo to
     *                  request that the engine tries to get the item_info, the
     *                  engine may ignore this return code if it knows better
     *                  i.e. a memory only engine and no item_info can be
     *                  fetched. The function can also return ::Fail if it
     *                  wishes to fail the store_if (returning predicate_failed)
     *                  or the predicate can return ::Continue and the rest of
     *                  the store_if will execute (and possibly fail for other
     *                  reasons).
     * @param durability An optional durability requirement
     * @param document_state The state the document should have after
     *                       the update
     * @param preserveTtl if set to true the existing documents TTL should
     *                    be used.
     *
     * @return a std::pair containing the engine_error code and new CAS
     */
    virtual cb::EngineErrorCasPair store_if(
            gsl::not_null<const void*> cookie,
            gsl::not_null<ItemIface*> item,
            uint64_t cas,
            StoreSemantics semantics,
            const cb::StoreIfPredicate& predicate,
            const std::optional<cb::durability::Requirements>& durability,
            DocumentState document_state,
            bool preserveTtl) {
        return {cb::engine_errc::not_supported, 0};
    }

    /**
     * Flush the cache.
     *
     * Optional interface; not supported by all engines.
     *
     * @param cookie The cookie provided by the frontend
     * @return cb::engine_errc::success if all goes well
     */
    virtual cb::engine_errc flush(gsl::not_null<const void*> cookie) {
        return cb::engine_errc::not_supported;
    }

    /*
     * Statistics
     */

    /**
     * Get statistics from the engine.
     *
     * @param cookie The cookie provided by the frontend
     * @param key optional argument to stats
     * @param value optional value for the given stat group
     * @param add_stat callback to feed results to the output
     *
     * @return cb::engine_errc::success if all goes well
     */
    virtual cb::engine_errc get_stats(gsl::not_null<const void*> cookie,
                                      std::string_view key,
                                      std::string_view value,
                                      const AddStatFn& add_stat) = 0;

    /**
     * Get statistics for Prometheus exposition from the engine.
     * Some engines may not support this.
     *
     * @param collector where the bucket may register stats
     *
     * @return cb::engine_errc::success if all goes well
     */
    virtual cb::engine_errc get_prometheus_stats(
            const BucketStatCollector& collector,
            cb::prometheus::Cardinality cardinality) {
        return cb::engine_errc::not_supported;
    }

    /**
     * Reset the stats.
     *
     * @param cookie The cookie provided by the frontend
     */
    virtual void reset_stats(gsl::not_null<const void*> cookie) = 0;

    /**
     * Any unknown command will be considered engine specific.
     *
     * @param cookie The cookie provided by the frontend
     * @param request The request from the client
     * @param response function to transmit data
     *
     * @return cb::engine_errc::success if all goes well
     */
    virtual cb::engine_errc unknown_command(const void* cookie,
                                            const cb::mcbp::Request& request,
                                            const AddResponseFn& response) {
        return cb::engine_errc::not_supported;
    }

    /**
     * Set the CAS id on an item.
     */
    virtual void item_set_cas(gsl::not_null<ItemIface*> item,
                              uint64_t cas) = 0;

    /**
     * Set the data type on an item.
     */
    virtual void item_set_datatype(gsl::not_null<ItemIface*> item,
                                   protocol_binary_datatype_t datatype) = 0;

    /**
     * Get information about an item.
     *
     * The loader of the module may need the pointers to the actual data within
     * an item. Instead of having to create multiple functions to get each
     * individual item, this function will get all of them.
     *
     * @param item the item to request information about
     * @param item_info
     * @return true if successful
     */
    virtual bool get_item_info(gsl::not_null<const ItemIface*> item,
                               gsl::not_null<item_info*> item_info) = 0;

    /**
     * The set of collections related functions. May be defined optionally by
     * the engine(s) that support them.
     */
    virtual cb::engine_errc set_collection_manifest(
            gsl::not_null<const void*> cookie, std::string_view json) {
        return cb::engine_errc::not_supported;
    }

    /**
     * Retrieve the last manifest set using set_manifest (a JSON document)
     */
    virtual cb::engine_errc get_collection_manifest(
            gsl::not_null<const void*> cookie, const AddResponseFn& response) {
        return cb::engine_errc::not_supported;
    }

    virtual cb::EngineErrorGetCollectionIDResult get_collection_id(
            gsl::not_null<const void*> cookie, std::string_view path) {
        return cb::EngineErrorGetCollectionIDResult{
                cb::engine_errc::not_supported};
    }

    virtual cb::EngineErrorGetScopeIDResult get_scope_id(
            gsl::not_null<const void*> cookie, std::string_view path) {
        return cb::EngineErrorGetScopeIDResult{cb::engine_errc::not_supported};
    }

    /**
     * Get the scope for the provided key
     *
     * @param cookie cookie object used to identify the request
     * @param key the key to look up
     * @return pair with the manifest UID and if found the scope where the key
     *              belongs.
     */
    virtual cb::EngineErrorGetScopeIDResult get_scope_id(
            gsl::not_null<const void*> cookie,
            const DocKey& key,
            std::optional<Vbid> vbid = std::nullopt) const {
        return cb::EngineErrorGetScopeIDResult(cb::engine_errc::not_supported);
    }

    /**
     * Ask the engine what features it supports.
     */
    virtual cb::engine::FeatureSet getFeatures() = 0;

    /**
     * @returns if XATTRs are enabled for this bucket
     */
    virtual bool isXattrEnabled() {
        return false;
    }

    /**
     * Get the "current" time and mode of the Hybrid Logical Clock for the
     * specified vBucket.
     * @returns seconds since unix epoch of the HLC, along with the current
     * HLC Mode (Real / Logical).
     */
    virtual cb::HlcTime getVBucketHlcNow(Vbid vbucket) = 0;

    /**
     * @returns the compression mode of the bucket
     */
    virtual BucketCompressionMode getCompressionMode() {
        return BucketCompressionMode::Off;
    }

    /**
     * @returns the maximum item size supported by the bucket
     */
    virtual size_t getMaxItemSize() {
        return default_max_item_size;
    };

    /**
     * @returns the minimum compression ratio defined in the bucket
     */
    virtual float getMinCompressionRatio() {
        return default_min_compression_ratio;
    }

    /**
     * Set a configuration parameter in the engine
     *
     * @param cookie The cookie identifying the request
     * @param category The parameter category
     * @param key The name of the parameter
     * @param value The value for the parameter
     * @param vbucket The vbucket specified in the request (only used for
     *                the vbucket sub group)
     * @return The standard engine codes
     */
    virtual cb::engine_errc setParameter(gsl::not_null<const void*> cookie,
                                         EngineParamCategory category,
                                         std::string_view key,
                                         std::string_view value,
                                         Vbid vbucket) {
        return cb::engine_errc::not_supported;
    }

    /**
     * Compact a database
     *
     * @param cookie The cookie identifying the request
     * @param vbid The vbucket to compact
     * @param purge_before_ts The timestamp to purge items before
     * @param purge_before_seq The sequence number to purge items before
     * @param drop_deletes Set to true if deletes should be dropped
     * @return The standard engine codes
     */
    virtual cb::engine_errc compactDatabase(gsl::not_null<const void*> cookie,
                                            Vbid vbid,
                                            uint64_t purge_before_ts,
                                            uint64_t purge_before_seq,
                                            bool drop_deletes) {
        return cb::engine_errc::not_supported;
    }

    /**
     * Get the state of a vbucket
     *
     * @param cookie The cookie identifying the request
     * @param vbid The vbucket to look up
     * @return A pair where the first entry is one of the standard engine codes
     *         and the second is the state when the status is success.
     */
    virtual std::pair<cb::engine_errc, vbucket_state_t> getVBucket(
            gsl::not_null<const void*> cookie, Vbid vbid) {
        return {cb::engine_errc::not_supported, vbucket_state_dead};
    }

    /**
     * Set the state of a vbucket
     *
     * @param cookie The cookie identifying the request
     * @param vbid The vbucket to update
     * @param cas The current value used for CAS swap
     * @param state The new vbucket state
     * @param meta The optional meta information for the state (nullptr if
     *             none is provided)
     * @return The standard engine codes
     */
    virtual cb::engine_errc setVBucket(gsl::not_null<const void*> cookie,
                                       Vbid vbid,
                                       uint64_t cas,
                                       vbucket_state_t state,
                                       nlohmann::json* meta) {
        return cb::engine_errc::not_supported;
    }

    /**
     * Delete a vbucket
     *
     * @param cookie The cookie identifying the request
     * @param vbid The vbucket to delete
     * @param sync If the operation should block (return EWB and be signalled
     *             when the operation is done) or delete in "fire and forget"
     *             mode.
     * @return The standard engine codes
     */
    virtual cb::engine_errc deleteVBucket(gsl::not_null<const void*> cookie,
                                          Vbid vbid,
                                          bool sync) {
        return cb::engine_errc::not_supported;
    }
};

namespace cb {
class ItemDeleter {
public:
    ItemDeleter() : handle(nullptr) {}

    /**
     * Create a new instance of the item deleter.
     *
     * @param handle_ the handle to the the engine who owns the item
     */
    explicit ItemDeleter(EngineIface* handle_) : handle(handle_) {
        if (handle == nullptr) {
            throw std::invalid_argument(
                "cb::ItemDeleter: engine handle cannot be nil");
        }
    }

    /**
     * Create a copy constructor to allow us to use std::move of the item
     */
    ItemDeleter(const ItemDeleter& other) = default;

    void operator()(ItemIface* item) {
        if (handle) {
            handle->release(item);
        } else {
            throw std::invalid_argument("cb::ItemDeleter: item attempted to be "
                                        "freed by null engine handle");
        }
    }

private:
    EngineIface* handle;
};

inline EngineErrorItemPair makeEngineErrorItemPair(cb::engine_errc err) {
    return {err, unique_item_ptr{nullptr, ItemDeleter{}}};
}

inline EngineErrorItemPair makeEngineErrorItemPair(cb::engine_errc err,
                                                   ItemIface* it,
                                                   EngineIface* handle) {
    return {err, unique_item_ptr{it, ItemDeleter{handle}}};
}
}

struct EngineDeletor {
    void operator()(EngineIface* engine) {
        engine->destroy(force);
    }

    bool force = false;
};

using unique_engine_ptr = std::unique_ptr<EngineIface, EngineDeletor>;

/**
 * @}
 */


#ifndef __COMPLEARN_REALCOMPRESSOR_H
#define __COMPLEARN_REALCOMPRESSOR_H

#define COMPLEARN_REAL_COMPRESSOR_TYPE        (real_compressor_get_type ())
#define COMPLEARN_TYPE_REAL_COMPRESSOR        (real_compressor_get_type ())
#define COMPLEARN_REAL_COMPRESSOR(obj)        (G_TYPE_CHECK_INSTANCE_CAST ((obj), COMPLEARN_REAL_COMPRESSOR_TYPE, CompLearnRealCompressor))
#define IS_COMPLEARN_REAL_COMPRESSOR(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), COMPLEARN_REAL_COMPRESSOR_TYPE))
#define COMPLEARN_REAL_COMPRESSOR_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), COMPLEARN_REAL_COMPRESSOR_TYPE, CompLearnRealCompressorIface))

#include <glib.h>
#include <glib-object.h>
#include <glib/garray.h>
#include <gsl/gsl_matrix.h>

#define COMPLEARN_ERROR 1
#define COMPLEARN_ERROR_NO_COMPRESSOR_SET 100

typedef struct _CompLearnRealCompressor CompLearnRealCompressor;
typedef struct _CompLearnRealCompressorIface CompLearnRealCompressorIface;

struct _CompLearnRealCompressorIface {
  GTypeInterface parent;

  GString *(*compress)(CompLearnRealCompressor *self, const GString *input);
  GString *(*decompress)(CompLearnRealCompressor *self, const GString *input);
  GString *(*blurb)(CompLearnRealCompressor *self);
  GString *(*canonical_extension)(CompLearnRealCompressor *self);
  GString *(*name)(CompLearnRealCompressor *self);
  GString *(*compressor_version)(CompLearnRealCompressor *self);
  GString *(*binding_version)(CompLearnRealCompressor *self);
  gboolean (*is_threadsafe)(CompLearnRealCompressor *self);
  gboolean (*is_compressible)(CompLearnRealCompressor *self, const GString *input);
  gboolean (*is_decompressible)(CompLearnRealCompressor *self, const GString *input);
  gboolean (*is_just_size)(CompLearnRealCompressor *self);
  gboolean (*is_hash_function)(CompLearnRealCompressor *self);
  GString *(*hash)(CompLearnRealCompressor *self, const GString *input);
  gboolean (*is_operational)(CompLearnRealCompressor *self);
  gboolean (*is_private_property)(CompLearnRealCompressor *self, const char *propname);
  gdouble (*compressed_size)(CompLearnRealCompressor *self, const GString *input);
  guint64 (*window_size)(CompLearnRealCompressor *self);
  CompLearnRealCompressor *(*clone)(CompLearnRealCompressor *self);
};

GType real_compressor_get_type(void);

GString *real_compressor_compress(CompLearnRealCompressor *self,const GString *input);
GString *real_compressor_hash(CompLearnRealCompressor *self,const GString *input);
GString *real_compressor_decompress(CompLearnRealCompressor *self,const GString *input);
gdouble real_compressor_compressed_size(CompLearnRealCompressor *self,const GString *input);
GString *real_compressor_blurb(CompLearnRealCompressor *self);
GString *real_compressor_name(CompLearnRealCompressor *self);
GString *real_compressor_compressor_version(CompLearnRealCompressor *self);
GString *real_compressor_binding_version(CompLearnRealCompressor *self);
gboolean real_compressor_is_compressible(CompLearnRealCompressor *self, const GString *input);
gboolean real_compressor_is_decompressible(CompLearnRealCompressor *self, const GString *input);
gboolean real_compressor_is_private_property(CompLearnRealCompressor *self, const char *input);
guint64 real_compressor_window_size(CompLearnRealCompressor *self);
gboolean real_compressor_is_threadsafe(CompLearnRealCompressor *self);
gboolean real_compressor_is_just_size(CompLearnRealCompressor *self);
gboolean real_compressor_is_hash_function(CompLearnRealCompressor *self);
GString *real_compressor_canonical_extension(CompLearnRealCompressor *rc);
gboolean real_compressor_is_operational(CompLearnRealCompressor *self);
CompLearnRealCompressor *real_compressor_clone(CompLearnRealCompressor *self);

#define SET_DEFAULT_PROPS(groupname, clt, mobj) \
  do { \
  GParamSpec **gps, **cur; \
  g_assert(mobj != NULL); \
    if (complearn_environment_get_nameable(groupname) == NULL) { \
      complearn_environment_register_nameable(groupname, G_OBJECT(mobj)); \
      break; \
    } \
  gps =g_object_class_list_properties(G_OBJECT_CLASS(clt(mobj)), NULL); \
  for (cur = gps; *cur; cur += 1) { \
    GValue v = {0,}; \
    g_value_init(&v, (*cur)->value_type); \
    g_param_value_set_default(*cur, &v); \
    g_object_set_property(G_OBJECT(mobj), (*cur)->name, &v); \
    complearn_environment_register_property(G_OBJECT(mobj), (*cur), &v); \
  } } while(0)

#define SET_DEFAULT_COMPRESSOR_PROPS(groupname, clt, mobj) \
  do { \
      SET_DEFAULT_PROPS(groupname, clt, mobj); \
    if (complearn_environment_get_nameable(groupname) == NULL) { \
      complearn_environment_register_compressor(mobj); \
    } \
  } while (0);

#endif

#define G_LOG_LEVEL_NOTICE G_LOG_LEVEL_USER_SHIFT
#define g_notice(...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_NOTICE, __VA_ARGS__)

void real_compressor_interface_init (gpointer g_iface, gpointer iface_data);


#ifndef NETWORK_CANUDPRECEIVER_H
#define NETWORK_CANUDPRECEIVER_H

#include <cstdint>
#include <gsl/gsl>
#include <QObject>

#include "tincan/canrawframe.h"
#include "network/udpasyncreceiver.h"

namespace network {

class Can_udp_receiver final : public QObject, public udp::Async_receiver
{
  Q_OBJECT

public:
  Can_udp_receiver() = default;
  Can_udp_receiver(const Can_udp_receiver&) = delete;
  Can_udp_receiver(Can_udp_receiver&&) = delete;
  Can_udp_receiver& operator=(const Can_udp_receiver&) = delete;
  Can_udp_receiver& operator=(Can_udp_receiver&&) = delete;

  void handle_receive(gsl::span<std::uint8_t> buffer) override;

signals:
  void received_frame(std::uint64_t, tin::Can_raw_frame);
};

}  // namespace network

#endif  // NETWORK_CANUDPRECEIVER_H


// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once

#include "core/common/inlined_containers.h"
#include "core/codegen/common/common.h"
#include "core/graph/graph.h"
#include "core/providers/nuphar/common/analysis/analysis.h"
#include <gsl/gsl>

namespace onnxruntime {
namespace nuphar {

class OutputAliasAnalysis : public NupharAnalysis {
 public:
  OutputAliasAnalysis()
      : NupharAnalysis("OutputAliasAnalysis") {}

  ~OutputAliasAnalysis() = default;

  void Evaluate(const onnxruntime::nuphar::NupharSubgraphUnit& graph) override;

  bool IsOutputNode(const onnxruntime::Node* node) const;

  bool IsOutputAlias(const onnxruntime::Node* node) const;

  const onnxruntime::NodeArg* SourceDefOfOutputAlias(const onnxruntime::NodeArg* node) const;

 private:
  // a set for output nodes
  std::set<NodeKey> output_nodes_;
  // a map from an output alias to its input
  std::map<NodeKey, const onnxruntime::NodeArg*> alias_use_defs_;

  void Traverse(gsl::span<const Node* const> nodes,
                const InlinedHashSet<std::string_view>& graph_inputs,
                const InlinedHashSet<std::string_view>& graph_outputs);

 private:
  ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(OutputAliasAnalysis);
};

}  // namespace nuphar
}  // namespace onnxruntime


/*
 * Copyright (c) 2016-2021 lymastee, All rights reserved.
 * Contact: lymastee@hotmail.com
 *
 * This file is part of the gslib project.
 *
 * 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.
 */

#pragma once

#ifndef config_27ec2780_3d0a_41f9_8a8b_0099ced77cf1_h
#define config_27ec2780_3d0a_41f9_8a8b_0099ced77cf1_h

#include <gslib/config.h>

#define __ariel_begin__     namespace gs { namespace ariel {
#define __ariel_end__       } };

#if defined(ARIEL_LIB)
#define ariel_export
#elif defined(ARIEL_DLL)
#define ariel_export __declspec(dllexport)
#else
#define ariel_export __declspec(dllimport)
#endif

enum
{
    render_platform_gl_20,
    render_platform_gl_30,
    render_platform_d3d_9,
    render_platform_d3d_11,
};

/* select render system here. */
#define select_render_platform  render_platform_d3d_11

#define use_rendersys_d3d_9     (select_render_platform == render_platform_d3d_9)
#define use_rendersys_d3d_11    (select_render_platform == render_platform_d3d_11)
#define use_rendersys_gl_20     (select_render_platform == render_platform_gl_20)
#define use_rendersys_gl_30     (select_render_platform == render_platform_gl_30)

#if use_rendersys_d3d_11
#include <d3d11.h>
#include <dxgi.h>
#endif

__ariel_begin__

define_select_type(render_device);
define_select_type(render_context);
define_select_type(render_resource);
define_select_type(render_swap_chain);
define_select_type(render_target_view);
define_select_type(shader_resource_view);
define_select_type(depth_stencil_view);
define_select_type(unordered_access_view);
define_select_type(render_blob);
define_select_type(vertex_shader);
define_select_type(pixel_shader);
define_select_type(geometry_shader);
define_select_type(compute_shader);
define_select_type(hull_shader);
define_select_type(domain_shader);
define_select_type(render_include);
define_select_type(vertex_format);
define_select_type(vertex_format_desc);
define_select_type(render_vertex_buffer);
define_select_type(render_index_buffer);
define_select_type(render_constant_buffer);
define_select_type(render_texture1d);
define_select_type(render_texture2d);
define_select_type(render_texture3d);
define_select_type(render_sampler_state);
define_select_type(render_blend_state);
define_select_type(render_raster_state);
define_select_type(render_depth_state);

install_select_type(render_platform_d3d_11, render_device, ID3D11Device);
install_select_type(render_platform_d3d_11, render_context, ID3D11DeviceContext);
install_select_type(render_platform_d3d_11, render_resource, ID3D11Resource);
install_select_type(render_platform_d3d_11, render_swap_chain, IDXGISwapChain);
install_select_type(render_platform_d3d_11, render_target_view, ID3D11RenderTargetView);
install_select_type(render_platform_d3d_11, shader_resource_view, ID3D11ShaderResourceView);
install_select_type(render_platform_d3d_11, depth_stencil_view, ID3D11DepthStencilView);
install_select_type(render_platform_d3d_11, unordered_access_view, ID3D11UnorderedAccessView);
install_select_type(render_platform_d3d_11, render_blob, ID3DBlob);
install_select_type(render_platform_d3d_11, vertex_shader, ID3D11VertexShader);
install_select_type(render_platform_d3d_11, pixel_shader, ID3D11PixelShader);
install_select_type(render_platform_d3d_11, geometry_shader, ID3D11GeometryShader);
install_select_type(render_platform_d3d_11, compute_shader, ID3D11ComputeShader);
install_select_type(render_platform_d3d_11, hull_shader, ID3D11HullShader);
install_select_type(render_platform_d3d_11, domain_shader, ID3D11DomainShader);

install_select_type(render_platform_d3d_11, render_include, ID3DInclude);
install_select_type(render_platform_d3d_11, vertex_format, ID3D11InputLayout);
install_select_type(render_platform_d3d_11, vertex_format_desc, D3D11_INPUT_ELEMENT_DESC);
install_select_type(render_platform_d3d_11, render_vertex_buffer, ID3D11Buffer);
install_select_type(render_platform_d3d_11, render_index_buffer, ID3D11Buffer);
install_select_type(render_platform_d3d_11, render_constant_buffer, ID3D11Buffer);

install_select_type(render_platform_d3d_11, render_texture1d, ID3D11Texture1D);
install_select_type(render_platform_d3d_11, render_texture2d, ID3D11Texture2D);
install_select_type(render_platform_d3d_11, render_texture3d, ID3D11Texture3D);
install_select_type(render_platform_d3d_11, render_sampler_state, ID3D11SamplerState);
install_select_type(render_platform_d3d_11, render_blend_state, ID3D11BlendState);
install_select_type(render_platform_d3d_11, render_raster_state, ID3D11RasterizerState);
install_select_type(render_platform_d3d_11, render_depth_state, ID3D11DepthStencilState);

config_select_type(select_render_platform, render_device);
config_select_type(select_render_platform, render_context);
config_select_type(select_render_platform, render_resource);
config_select_type(select_render_platform, render_swap_chain);
config_select_type(select_render_platform, render_target_view);
config_select_type(select_render_platform, shader_resource_view);
config_select_type(select_render_platform, depth_stencil_view);
config_select_type(select_render_platform, unordered_access_view);
config_select_type(select_render_platform, render_blob);
config_select_type(select_render_platform, vertex_shader);
config_select_type(select_render_platform, pixel_shader);
config_select_type(select_render_platform, geometry_shader);
config_select_type(select_render_platform, compute_shader);
config_select_type(select_render_platform, hull_shader);
config_select_type(select_render_platform, domain_shader);
config_select_type(select_render_platform, render_include);
config_select_type(select_render_platform, vertex_format);
config_select_type(select_render_platform, render_vertex_buffer);
config_select_type(select_render_platform, render_index_buffer);
config_select_type(select_render_platform, render_constant_buffer);
config_select_type(select_render_platform, render_texture1d);
config_select_type(select_render_platform, render_texture2d);
config_select_type(select_render_platform, render_texture3d);
config_select_type(select_render_platform, render_sampler_state);
config_select_type(select_render_platform, render_blend_state);
config_select_type(select_render_platform, render_raster_state);
config_select_type(select_render_platform, render_depth_state);

enum render_option
{
    opt_primitive_topology,
    /* more to come. */
};

__ariel_end__

#endif


#pragma once
#include <memory>
#include <gsl/span>
#include "D3DManager.h"

namespace vrutil
{

class OverlayItem
{
    class OverlayItemImpl *m_impl;
    OverlayItem(class OverlayItemImpl *impl);

public:
    ~OverlayItem();
    static std::shared_ptr<OverlayItem> Create(uint64_t handle);
    void ProcessEvents();
    void SetTexture(const ComPtr<ID3D11Texture2D> &texture);
    void SetSharedHandle(void *handle);
    void SetOverlayWidthInMeters(float meter);
    void Show();
    void SetMatrix34(const float *matrix34);
};
using OverlayItemPtr = std::shared_ptr<OverlayItem>;

} // namespace vrutil