#pragma once

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

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

#include <GraphicsImpl.h>

#include <NativeWindow.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
{
    class ClearState final
    {
    public:
        void UpdateColor(float r, float g, float b, float a)
        {
            const bool needToUpdate = r != Red || g != Green || b != Blue || a != Alpha;
            if (needToUpdate)
            {
                Red = r;
                Green = g;
                Blue = b;
                Alpha = a;
                Update();
            }
        }

        void UpdateFlags(const Napi::CallbackInfo& info)
        {
            const auto flags = static_cast<uint16_t>(info[0].As<Napi::Number>().Uint32Value());
            Flags = flags;
            Update();
        }

        void UpdateDepth(const Napi::CallbackInfo& info)
        {
            const auto depth = info[0].As<Napi::Number>().FloatValue();
            const bool needToUpdate = Depth != depth;
            if (needToUpdate)
            {
                Depth = depth;
                Update();
            }
        }

        void UpdateStencil(const Napi::CallbackInfo& info)
        {
            const auto stencil = static_cast<uint8_t>(info[0].As<Napi::Number>().Int32Value());
            const bool needToUpdate = Stencil != stencil;
            if (needToUpdate)
            {
                Stencil = stencil;
                Update();
            }
        }

        arcana::weak_table<std::function<void()>>::ticket AddUpdateCallback(std::function<void()> callback)
        {
            return m_callbacks.insert(std::move(callback));
        }

        void Update()
        {
            m_callbacks.apply_to_all([](std::function<void()>& callback) {
                callback();
            });
        }

        uint32_t Color() const
        {
            uint32_t color = 0x0;
            color += static_cast<uint8_t>(Red * std::numeric_limits<uint8_t>::max());
            color = color << 8;
            color += static_cast<uint8_t>(Green * std::numeric_limits<uint8_t>::max());
            color = color << 8;
            color += static_cast<uint8_t>(Blue * std::numeric_limits<uint8_t>::max());
            color = color << 8;
            color += static_cast<uint8_t>(Alpha * std::numeric_limits<uint8_t>::max());
            return color;
        }

        float Red{68.f / 255.f};
        float Green{51.f / 255.f};
        float Blue{85.f / 255.f};
        float Alpha{1.f};
        float Depth{1.f};
        uint16_t Flags{BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH};
        uint8_t Stencil{0};

    private:
        arcana::weak_table<std::function<void()>> m_callbacks{};
    };

    class ViewClearState final
    {
    public:
        ViewClearState(uint16_t viewId, ClearState& clearState)
            : m_viewId{viewId}
            , m_clearState{clearState}
            , m_callbackTicket{m_clearState.AddUpdateCallback([this]() { Update(); })}
        {
        }

        void UpdateColor(float r, float g, float b, float a = 1.f)
        {
            m_clearState.UpdateColor(r, g, b, a);
        }

        void UpdateColor(const Napi::CallbackInfo& info)
        {
            const auto r = info[0].As<Napi::Number>().FloatValue();
            const auto g = info[1].As<Napi::Number>().FloatValue();
            const auto b = info[2].As<Napi::Number>().FloatValue();
            const auto a = info[3].IsUndefined() ? 1.f : info[3].As<Napi::Number>().FloatValue();
            m_clearState.UpdateColor(r, g, b, a);
        }

        void UpdateFlags(const Napi::CallbackInfo& info)
        {
            m_clearState.UpdateFlags(info);
        }

        void UpdateDepth(const Napi::CallbackInfo& info)
        {
            m_clearState.UpdateDepth(info);
        }

        void UpdateStencil(const Napi::CallbackInfo& info)
        {
            m_clearState.UpdateStencil(info);
        }

        void UpdateViewId(uint16_t viewId)
        {
            m_viewId = viewId;
            Update();
        }

    private:

        void Update() const
        {
            bgfx::setViewClear(m_viewId, m_clearState.Flags, m_clearState.Color(), m_clearState.Depth, m_clearState.Stencil);
            // discard any previous set state
            bgfx::discard();
        }

        uint16_t m_viewId{};
        ClearState& m_clearState;
        arcana::weak_table<std::function<void()>>::ticket m_callbackTicket;
    };

    struct FrameBufferData final
    {
    private:
        std::unique_ptr<ClearState> m_clearState{};

    public:
        FrameBufferData(bgfx::FrameBufferHandle frameBuffer, uint16_t viewId, uint16_t width, uint16_t height, bool actAsBackBuffer = false)
            : m_clearState{std::make_unique<ClearState>()}
            , FrameBuffer{frameBuffer}
            , ViewId{viewId}
            , ViewClearState{ViewId, *m_clearState}
            , Width{width}
            , Height{height}
            , ActAsBackBuffer{actAsBackBuffer}
        {
            assert(ViewId < bgfx::getCaps()->limits.maxViews);
        }

        FrameBufferData(bgfx::FrameBufferHandle frameBuffer, uint16_t viewId, ClearState& clearState, uint16_t width, uint16_t height, bool actAsBackBuffer = false)
            : m_clearState{}
            , FrameBuffer{frameBuffer}
            , ViewId{viewId}
            , ViewClearState{ViewId, clearState}
            , Width{width}
            , Height{height}
            , ActAsBackBuffer{actAsBackBuffer}
        {
            assert(ViewId < bgfx::getCaps()->limits.maxViews);
        }

        FrameBufferData(FrameBufferData&) = delete;

        ~FrameBufferData()
        {
            bgfx::destroy(FrameBuffer);
        }

        void UseViewId(uint16_t viewId)
        {
            ViewId = viewId;
            ViewClearState.UpdateViewId(ViewId);
        }

        void SetUpView(uint16_t viewId)
        {
            bgfx::setViewFrameBuffer(viewId, FrameBuffer);
            UseViewId(viewId);
            bgfx::setViewRect(ViewId, 0, 0, Width, Height);
        }

        bgfx::FrameBufferHandle FrameBuffer{bgfx::kInvalidHandle};
        bgfx::ViewId ViewId{};
        Babylon::ViewClearState ViewClearState;
        uint16_t Width{};
        uint16_t Height{};
        // When a FrameBuffer acts as a back buffer, it means it will not be used as a texture in a shader.
        // For example as a post process. It will be used as-is in a swapchain or for direct rendering (XR)
        // When this flag is true, projection matrix will not be flipped for API that would normaly need it.
        // Namely Direct3D and Metal.
        bool ActAsBackBuffer{false};
    };

    struct FrameBufferManager final
    {
        FrameBufferManager()
        {
            m_boundFrameBuffer = m_backBuffer = new FrameBufferData(BGFX_INVALID_HANDLE, GetNewViewId(), bgfx::getStats()->width, bgfx::getStats()->height);
        }

        FrameBufferData* CreateNew(bgfx::FrameBufferHandle frameBufferHandle, uint16_t width, uint16_t height)
        {
            return new FrameBufferData(frameBufferHandle, GetNewViewId(), width, height);
        }

        FrameBufferData* CreateNew(bgfx::FrameBufferHandle frameBufferHandle, ClearState& clearState, uint16_t width, uint16_t height, bool actAsBackBuffer)
        {
            return new FrameBufferData(frameBufferHandle, GetNewViewId(), clearState, width, height, actAsBackBuffer);
        }

        void Bind(FrameBufferData* data)
        {
            m_boundFrameBuffer = data;

            // TODO: Consider doing this only on bgfx::reset(); the effects of this call don't survive reset, but as
            // long as there's no reset this doesn't technically need to be called every time the frame buffer is bound.
            m_boundFrameBuffer->SetUpView(GetNewViewId());

            // bgfx::setTexture()? Why?
            // TODO: View order?
            m_renderingToTarget = !m_boundFrameBuffer->ActAsBackBuffer;
        }

        FrameBufferData& GetBound() const
        {
            return *m_boundFrameBuffer;
        }

        void Unbind(FrameBufferData* data)
        {
            // this assert is commented because of an issue with XR described here : https://github.com/BabylonJS/BabylonNative/issues/344
            //assert(m_boundFrameBuffer == data);
            (void)data;
            m_boundFrameBuffer = m_backBuffer;
            m_renderingToTarget = false;
        }

        uint16_t GetNewViewId()
        {
            m_nextId++;
            assert(m_nextId < bgfx::getCaps()->limits.maxViews);
            return m_nextId;
        }

        void Reset()
        {
            m_nextId = 0;
        }

        bool IsRenderingToTarget() const
        {
            return m_renderingToTarget;
        }

    private:
        FrameBufferData* m_boundFrameBuffer{nullptr};
        FrameBufferData* m_backBuffer{nullptr};
        uint16_t m_nextId{0};
        bool m_renderingToTarget{false};
    };

    struct TextureData final
    {
        ~TextureData()
        {
            if (bgfx::isValid(Handle))
            {
                bgfx::destroy(Handle);
            }
        }

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

    struct ImageData final
    {
        ~ImageData()
        {
            if (Image)
            {
                bimg::imageFree(Image.get());
            }
        }
        std::unique_ptr<bimg::ImageContainer> Image;
    };

    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()
        {
            bgfx::destroy(Program);
        }

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

        bgfx::ProgramHandle Program{};

        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& vertexBuffer : vertexBuffers)
            {
                bgfx::destroy(vertexBuffer.vertexLayoutHandle);
            }
        }

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

        IndexBuffer indexBuffer{};

        struct VertexBuffer
        {
            const VertexBufferData* data{};
            uint32_t startVertex{};
            bgfx::VertexLayoutHandle vertexLayoutHandle{};
        };

        std::vector<VertexBuffer> vertexBuffers{};
    };

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

    public:
        NativeEngine(const Napi::CallbackInfo& info);
        NativeEngine(const Napi::CallbackInfo& info, JsRuntime& runtime, Plugins::Internal::NativeWindow& nativeWindow);
        ~NativeEngine();

        static void Initialize(Napi::Env, bool autoRender);

        FrameBufferManager& GetFrameBufferManager();
        void Dispatch(std::function<void()>);

        void ScheduleRender();

        const bool AutomaticRenderingEnabled{};
        JsRuntimeScheduler RuntimeScheduler;

    private:
        void Dispose();

        void Dispose(const Napi::CallbackInfo& info);
        Napi::Value GetEngine(const Napi::CallbackInfo& info); // TODO: Hack, temporary method. Remove as part of the change to get rid of NapiBridge.
        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);
        Napi::Value CreateDepthTexture(const Napi::CallbackInfo& info);
        void LoadTexture(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);
        void ClearColor(const Napi::CallbackInfo& info);
        void ClearStencil(const Napi::CallbackInfo& info);
        void ClearDepth(const Napi::CallbackInfo& info);
        Napi::Value GetRenderWidth(const Napi::CallbackInfo& info);
        Napi::Value GetRenderHeight(const Napi::CallbackInfo& info);
        void SetViewPort(const Napi::CallbackInfo& info);
        void GetFramebufferData(const Napi::CallbackInfo& info);
        Napi::Value GetRenderAPI(const Napi::CallbackInfo& info);

        void UpdateSize(size_t width, size_t height);

        template<typename SchedulerT>
        arcana::task<void, std::exception_ptr> GetRequestAnimationFrameTask(SchedulerT&);

        bool m_isRenderScheduled{false};

        arcana::cancellation_source m_cancelSource{};

        ShaderCompiler m_shaderCompiler;

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

        JsRuntime& m_runtime;
        Graphics::Impl& m_graphicsImpl;

        bx::DefaultAllocator m_allocator;
        uint64_t m_engineState;

        FrameBufferManager m_frameBufferManager{};

        Plugins::Internal::NativeWindow::NativeWindow::OnResizeCallbackTicket m_resizeCallbackTicket;

        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{};

        Napi::FunctionReference m_requestAnimationFrameCallback{};

        // webgl/opengl draw call parameters allow to set first index and number of indices used for that call
        // but with bgfx, those parameters must be set when binding the index buffer
        // at the time of webgl binding, we don't know those values yet
        // so a pointer to the to-bind buffer is kept and the buffer is bound to bgfx at the time of the drawcall
        const IndexBufferData* m_currentBoundIndexBuffer{};
    };
}


#ifndef Dark_Arts_Exception_h
#define Dark_Arts_Exception_h

#include "Exception_Types.h"
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include <petsc.h>

class Dark_Arts_Exception
{
public:
  Dark_Arts_Exception( EXCEPTION_TYPE ex_type , const std::string& ex_message);
  Dark_Arts_Exception( EXCEPTION_TYPE ex_type , const std::stringstream& ex_message);
  Dark_Arts_Exception();
  virtual ~Dark_Arts_Exception(){}

  void message(void) const;
  void testing_message(void) const;

private:
  std::string error_message;
};

#endif


#pragma once

#include <bgfx/bgfx.h>
#include <napi/napi.h>
#include <gsl/gsl>

#include <optional>

namespace Babylon
{
    class IndexBuffer final
    {
    public:
        IndexBuffer(gsl::span<uint8_t> bytes, uint16_t flags, bool dynamic);
        ~IndexBuffer();

        void Dispose();

        void Update(Napi::Env env, gsl::span<uint8_t> bytes, uint32_t startIndex);
        bool CreateHandle();
        void Set(bgfx::Encoder* encoder, uint32_t firstIndex, uint32_t numIndices);

    private:
        std::optional<std::vector<uint8_t>> m_bytes{};
        uint16_t m_flags{};
        bool m_dynamic{};

        union
        {
            bgfx::IndexBufferHandle m_handle{bgfx::kInvalidHandle};
            bgfx::DynamicIndexBufferHandle m_dynamicHandle;
        };

        bool m_disposed{};
    };
}


//          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 "keystate.h"
#include <gsl/gsl>
#include <string>
#include <cstdint>

struct Midi_Output {
    std::string id;
    std::string name;
};

enum Midi_Message_Flag {
    Midi_Message_Is_First = 1,
};

///
class Midi_Instrument {
public:
    Midi_Instrument();
    virtual ~Midi_Instrument() {}
    void send_message(const uint8_t *data, unsigned len, double ts, uint8_t flags);
    void initialize();
    void all_sound_off();

    const Keyboard_State &keyboard_state() const noexcept { return kbs_; }

    virtual void flush_events() {}

    virtual void open_midi_output(gsl::cstring_span id) = 0;
    virtual void close_midi_output() = 0;

    virtual bool is_synth() const { return false; }

protected:
    virtual void handle_send_message(const uint8_t *data, unsigned len, double ts, uint8_t flags) = 0;

private:
    Keyboard_State kbs_;
};


#pragma once

#include "Cesium3DTiles/BoundingVolume.h"
#include "Cesium3DTiles/Gltf.h"
#include "Cesium3DTiles/Library.h"
#include "Cesium3DTiles/TileContentLoadResult.h"
#include "Cesium3DTiles/TileContentLoader.h"
#include "Cesium3DTiles/TileID.h"
#include "Cesium3DTiles/TileRefine.h"
#include "CesiumGltf/GltfReader.h"
#include <cstddef>
#include <glm/mat4x4.hpp>
#include <gsl/span>
#include <spdlog/fwd.h>

namespace Cesium3DTiles {

class Tileset;

/**
 * @brief Creates {@link TileContentLoadResult} from glTF data.
 */
class CESIUM3DTILES_API GltfContent final : public TileContentLoader {
public:
  /**
   * @copydoc TileContentLoader::load
   *
   * The result will only contain the `model`. Other fields will be
   * empty or have default values.
   */
  std::unique_ptr<TileContentLoadResult>
  load(const TileContentLoadInput& input) override;

  /**
   * @brief Create a {@link TileContentLoadResult} from the given data.
   *
   * (Only public to be called from `Batched3DModelContent`)
   *
   * @param pLogger Only used for logging
   * @param url The URL, only used for logging
   * @param data The actual glTF data
   * @return The {@link TileContentLoadResult}
   */
  static std::unique_ptr<TileContentLoadResult> load(
      const std::shared_ptr<spdlog::logger>& pLogger,
      const std::string& url,
      const gsl::span<const std::byte>& data);

  /**
   * @brief Creates texture coordinates for raster tiles that are mapped to 3D
   * tiles.
   *
   * This is not supposed to be called by clients.
   *
   * It will be called for all {@link RasterMappedTo3DTile} objects of a
   * {@link Tile}, and extend the accessors of the given glTF model with
   * accessors that contain the texture coordinate sets for different
   * projections. Further details are not specified here.
   *
   * @param gltf The glTF model.
   * @param textureCoordinateID The texture coordinate ID.
   * @param projection The {@link CesiumGeospatial::Projection}.
   * @param rectangle The {@link CesiumGeometry::Rectangle}.
   * @return The bounding region.
   */
  static CesiumGeospatial::BoundingRegion createRasterOverlayTextureCoordinates(
      CesiumGltf::Model& gltf,
      uint32_t textureCoordinateID,
      const CesiumGeospatial::Projection& projection,
      const CesiumGeometry::Rectangle& rectangle);

private:
  static CesiumGltf::GltfReader _gltfReader;
};

} // namespace Cesium3DTiles


/*
 *  Copyright (C) 2021 FISCO BCOS.
 *  SPDX-License-Identifier: Apache-2.0
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 * @brief interface for BlockHeader
 * @file BlockHeader.h
 * @author: yujiechen
 * @date: 2021-03-22
 */
#pragma once
#include "Exceptions.h"
#include "ProtocolTypeDef.h"
#include <bcos-crypto/interfaces/crypto/CryptoSuite.h>
#include <bcos-utilities/DataConvertUtility.h>
#include <gsl/span>

namespace bcos
{
namespace protocol
{
class BlockHeader
{
public:
    using Ptr = std::shared_ptr<BlockHeader>;
    using ConstPtr = std::shared_ptr<const BlockHeader>;
    using BlockHeadersPtr = std::shared_ptr<std::vector<BlockHeader::Ptr> >;
    explicit BlockHeader(bcos::crypto::CryptoSuite::Ptr _cryptoSuite) : m_cryptoSuite(_cryptoSuite)
    {}

    virtual ~BlockHeader() {}

    virtual void decode(bytesConstRef _data) = 0;
    virtual void encode(bytes& _encodeData) const = 0;

    virtual bcos::crypto::HashType hash() const { return {}; }

    virtual void populateFromParents(BlockHeadersPtr _parents, BlockNumber _number)
    {
        // set parentInfo
        ParentInfoList parentInfoList;
        for (auto parentHeader : *_parents)
        {
            ParentInfo parentInfo;
            parentInfo.blockNumber = parentHeader->number();
            parentInfo.blockHash = parentHeader->hash();
            parentInfoList.emplace_back(parentInfo);
        }
        setParentInfo(std::move(parentInfoList));
        setNumber(_number);
    }

    virtual void clear() = 0;

    // verifySignatureList verifys the signatureList
    virtual void verifySignatureList() const
    {
        auto signatures = signatureList();
        auto sealers = sealerList();
        if (signatures.size() < sealers.size())
        {
            BOOST_THROW_EXCEPTION(InvalidBlockHeader() << errinfo_comment(
                                      "Invalid blockHeader for the size of sealerList "
                                      "is smaller than the size of signatureList"));
        }
        for (auto signature : signatures)
        {
            auto sealerIndex = signature.index;
            auto signatureData = signature.signature;
            if (!m_cryptoSuite->signatureImpl()->verify(
                    std::shared_ptr<const bytes>(&((sealers)[sealerIndex]), [](const bytes*) {}),
                    hash(), bytesConstRef(signatureData.data(), signatureData.size())))
            {
                BOOST_THROW_EXCEPTION(
                    InvalidSignatureList()
                    << errinfo_comment("Invalid signatureList for verify failed, signatureData:" +
                                       *toHexString(signatureData)));
            }
        }
    }
    virtual void populateEmptyBlock(
        BlockNumber _number, int64_t _sealerId, int64_t _timestamp = utcTime())
    {
        setNumber(_number);
        setSealer(_sealerId);
        setTimestamp(_timestamp);
    }

    // version returns the version of the blockHeader
    virtual int32_t version() const = 0;
    // parentInfo returns the parent information, including (parentBlockNumber, parentHash)
    virtual gsl::span<const ParentInfo> parentInfo() const = 0;
    // txsRoot returns the txsRoot of the current block
    virtual bcos::crypto::HashType txsRoot() const = 0;
    // receiptsRoot returns the receiptsRoot of the current block
    virtual bcos::crypto::HashType receiptsRoot() const = 0;
    // stateRoot returns the stateRoot of the current block
    virtual bcos::crypto::HashType stateRoot() const = 0;
    // number returns the number of the current block
    virtual BlockNumber number() const = 0;
    virtual u256 gasUsed() const = 0;
    virtual int64_t timestamp() const = 0;
    // sealer returns the sealer that generate this block
    virtual int64_t sealer() const = 0;
    // sealerList returns the current sealer list
    virtual gsl::span<const bytes> sealerList() const = 0;
    virtual bytesConstRef extraData() const = 0;
    virtual gsl::span<const Signature> signatureList() const = 0;
    virtual gsl::span<const uint64_t> consensusWeights() const = 0;

    virtual void setVersion(int32_t _version) = 0;
    virtual void setParentInfo(gsl::span<const ParentInfo> const& _parentInfo) = 0;
    virtual void setParentInfo(ParentInfoList&& _parentInfo) = 0;

    virtual void setTxsRoot(bcos::crypto::HashType _txsRoot) = 0;
    virtual void setReceiptsRoot(bcos::crypto::HashType _receiptsRoot) = 0;
    virtual void setStateRoot(bcos::crypto::HashType _stateRoot) = 0;
    virtual void setNumber(BlockNumber _blockNumber) = 0;
    virtual void setGasUsed(u256 _gasUsed) = 0;
    virtual void setTimestamp(int64_t _timestamp) = 0;
    virtual void setSealer(int64_t _sealerId) = 0;

    virtual void setSealerList(gsl::span<const bytes> const& _sealerList) = 0;
    virtual void setSealerList(std::vector<bytes>&& _sealerList) = 0;

    virtual void setConsensusWeights(gsl::span<const uint64_t> const& _weightList) = 0;
    virtual void setConsensusWeights(std::vector<uint64_t>&& _weightList) = 0;

    virtual void setExtraData(bytes const& _extraData) = 0;
    virtual void setExtraData(bytes&& _extraData) = 0;

    virtual void setSignatureList(gsl::span<const Signature> const& _signatureList) = 0;
    virtual void setSignatureList(SignatureList&& _signatureList) = 0;
    virtual bcos::crypto::CryptoSuite::Ptr cryptoSuite() { return m_cryptoSuite; }

protected:
    bcos::crypto::CryptoSuite::Ptr m_cryptoSuite;
};
}  // namespace protocol
}  // namespace bcos


#ifndef __GSL_BLOCK_H__
#define __GSL_BLOCK_H__

#include <gsl/gsl_block_complex_long_double.h>
#include <gsl/gsl_block_complex_double.h>
#include <gsl/gsl_block_complex_float.h>

#include <gsl/gsl_block_long_double.h>
#include <gsl/gsl_block_double.h>
#include <gsl/gsl_block_float.h>

#include <gsl/gsl_block_ulong.h>
#include <gsl/gsl_block_long.h>

#include <gsl/gsl_block_uint.h>
#include <gsl/gsl_block_int.h>

#include <gsl/gsl_block_ushort.h>
#include <gsl/gsl_block_short.h>

#include <gsl/gsl_block_uchar.h>
#include <gsl/gsl_block_char.h>

#endif /* __GSL_BLOCK_H__ */


#pragma once

#include <memory>
#include <string>

#include <gsl/gsl>

#include "chainerx/backend.h"
#include "chainerx/device.h"
#include "chainerx/kernel_registry.h"

namespace chainerx {
namespace native {

class NativeDevice;
class NativeBackend;

namespace native_internal {

// Creates a device instance.
// This function is meant to be used from the backend class. Never use it for other purpose.
// This is defined in internal namespace in order to make it a friend of NativeDevice
// class.
NativeDevice* CreateDevice(NativeBackend& backend, int index);

}  // namespace native_internal

class NativeBackend : public Backend {
public:
    static constexpr const char* kDefaultName = "native";

    using Backend::Backend;

    std::string GetName() const override;

    int GetDeviceCount() const override;

    bool SupportsTransfer(Device& src_device, Device& dst_device) override;

    static KernelRegistry& GetGlobalKernelRegistry() {
        static gsl::owner<KernelRegistry*> global_kernel_registry = new KernelRegistry{};
        return *global_kernel_registry;
    }

protected:
    KernelRegistry& GetParentKernelRegistry() override { return GetGlobalKernelRegistry(); }

private:
    std::unique_ptr<Device> CreateDevice(int index) override;
};

}  // namespace native
}  // namespace chainerx


#pragma once

#include "RTTI.h"
#include <d3d11.h>
#include <stack>
#include <gsl\gsl>
#include <vector>

namespace Library
{
	class RenderTarget : public RTTI
	{
		RTTI_DECLARATIONS(RenderTarget, RTTI)

	public:
		RenderTarget() = default;
		RenderTarget(const RenderTarget&) = delete;
		RenderTarget(RenderTarget&&) = default;
		RenderTarget& operator=(const RenderTarget&) = delete;
		RenderTarget& operator=(RenderTarget&&) = default;
		virtual ~RenderTarget() = default;

		virtual void Begin() = 0;
		virtual void End() = 0;

	protected:
		struct RenderTargetData
		{
			uint32_t ViewCount() const { return gsl::narrow_cast<uint32_t>(RenderTargetViews.size()); }

			std::vector<ID3D11RenderTargetView*> RenderTargetViews;
			gsl::not_null<ID3D11DepthStencilView*> DepthStencilView;
			D3D11_VIEWPORT Viewport;

			RenderTargetData(const gsl::span<ID3D11RenderTargetView*>& renderTargetViews, gsl::not_null<ID3D11DepthStencilView*> depthStencilView, const D3D11_VIEWPORT& viewport) :
				RenderTargetViews(renderTargetViews.begin(), renderTargetViews.end()), DepthStencilView(depthStencilView), Viewport(viewport) { }
		};

		void Begin(gsl::not_null<ID3D11DeviceContext*> deviceContext, const gsl::span<ID3D11RenderTargetView*>& renderTargetViews, gsl::not_null<ID3D11DepthStencilView*> depthStencilView, const D3D11_VIEWPORT& viewport);
		void End(gsl::not_null<ID3D11DeviceContext*> deviceContext);
		void RebindCurrentRenderTargets(gsl::not_null<ID3D11DeviceContext*> deviceContext);

	private:
		static std::stack<RenderTargetData> sRenderTargetStack;
	};
}


/*
 *  Copyright (C) 2021 FISCO BCOS.
 *  SPDX-License-Identifier: Apache-2.0
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 * @brief interface of Table
 * @file Table.h
 * @author: xingqiangbai
 * @date: 2021-04-07
 */
#pragma once

#include "../../interfaces/protocol/ProtocolTypeDef.h"
#include "../../libutilities/Error.h"
#include "boost/algorithm/string.hpp"
#include "tbb/spin_mutex.h"
#include "tbb/spin_rw_mutex.h"
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <any>
#include <cstdlib>
#include <gsl/span>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#define STORAGE_LOG(LEVEL) BCOS_LOG(LEVEL) << "[STORAGE]"

namespace bcos
{
namespace storage
{
enum StorageError
{
    UnknownError = -60000,
    TableNotExists,
    SystemTableNotExists,
    TableExists,
    UnknownEntryType,
    ReadError,
    WriteError,
    EmptyStorage,
    ReadOnly,
};

struct Condition
{
    Condition() = default;
    ~Condition() = default;
    void NE(const std::string& value) { m_conditions.emplace_back(Comparator::NE, value); }
    // string compare, "2" > "12"
    void GT(const std::string& value) { m_conditions.emplace_back(Comparator::GT, value); }
    void GE(const std::string& value) { m_conditions.emplace_back(Comparator::GE, value); }
    // string compare, "12" < "2"
    void LT(const std::string& value) { m_conditions.emplace_back(Comparator::LT, value); }
    void LE(const std::string& value) { m_conditions.emplace_back(Comparator::LE, value); }
    void limit(size_t start, size_t end) { m_limit = std::pair<size_t, size_t>(start, end); }

    std::pair<size_t, size_t> getLimit() const { return m_limit; }

    bool isValid(const std::string_view& key) const
    {  // all conditions must be satisfied
        for (auto& cond : m_conditions)
        {  // conditions should few, so not parallel check for now
            switch (cond.cmp)
            {
            case Comparator::NE:
                if (key == cond.value)
                {
                    return false;
                }
                break;
            case Comparator::GT:
                if (key <= cond.value)
                {
                    return false;
                }
                break;
            case Comparator::GE:
                if (key < cond.value)
                {
                    return false;
                }
                break;
            case Comparator::LT:
                if (key >= cond.value)
                {
                    return false;
                }
                break;
            case Comparator::LE:
                if (key > cond.value)
                {
                    return false;
                }
                break;
            default:
                // undefined Comparator
                break;
            }
        }
        return true;
    }

    enum class Comparator
    {
        EQ,
        NE,
        GT,
        GE,
        LT,
        LE,
    };
    struct cond
    {
        cond(Comparator _cmp, const std::string& _value) : cmp(_cmp), value(_value) {}
        Comparator cmp;
        std::string value;
    };

    std::vector<cond> m_conditions;
    std::pair<size_t, size_t> m_limit;
};

class TableInfo
{
public:
    using Ptr = std::shared_ptr<TableInfo>;
    using ConstPtr = std::shared_ptr<const TableInfo>;

    TableInfo(std::string name, std::vector<std::string> fields)
      : m_name(std::move(name)), m_fields(std::move(fields))
    {
        m_order.reserve(m_fields.size());
        for (size_t i = 0; i < m_fields.size(); ++i)
        {
            m_order.push_back({m_fields[i], i});
        }
        std::sort(m_order.begin(), m_order.end(),
            [](auto&& lhs, auto&& rhs) { return std::get<0>(lhs) < std::get<0>(rhs); });
    }

    std::string_view name() const { return m_name; }

    const std::vector<std::string>& fields() const { return m_fields; }

    size_t fieldIndex(const std::string_view& field) const
    {
        auto it = std::lower_bound(m_order.begin(), m_order.end(), field,
            [](auto&& lhs, auto&& rhs) { return std::get<0>(lhs) < rhs; });
        if (it != m_order.end() && std::get<0>(*it) == field)
        {
            return std::get<1>(*it);
        }
        else
        {
            BOOST_THROW_EXCEPTION(
                BCOS_ERROR(-1, std::string("Can't find field: ") + std::string(field)));
        }
    }

private:
    std::string m_name;
    std::vector<std::string> m_fields;
    std::vector<std::tuple<std::string_view, size_t>> m_order;

private:
    void* operator new(size_t s) { return malloc(s); };
    void operator delete(void* p) { free(p); };
};

}  // namespace storage
}  // namespace bcos


// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// 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 <gsl/gsl-lite.hpp>
#include <units/bits/external/hacks.h>
#include <utility>

inline constexpr struct validated_tag {
} validated;

template<std::movable T, std::predicate<T> Validator>
class validated_type {
  T value_;
public:
  using value_type = T;

  static constexpr bool validate(const T& value) { return Validator()(value); }

  constexpr explicit validated_type(const T& value) noexcept(std::is_nothrow_copy_constructible_v<T>)
    requires std::copyable<T>
  : value_(value)
  {
    gsl_Expects(validate(value_));
  }

  constexpr explicit validated_type(T&& value) noexcept(std::is_nothrow_move_constructible_v<T>) :
      value_(std::move(value))
  {
    gsl_Expects(validate(value_));
  }

  constexpr validated_type(const T& value, validated_tag) noexcept(std::is_nothrow_copy_constructible_v<T>)
    requires std::copyable<T>
  : value_(value)
  {
  }

  constexpr validated_type(T&& value, validated_tag) noexcept(std::is_nothrow_move_constructible_v<T>) :
      value_(std::move(value))
  {
  }

  constexpr explicit(false) operator T() const noexcept(std::is_nothrow_copy_constructible_v<T>)
    requires std::copyable<T>
  {
    return value_;
  }

  constexpr T& value() & noexcept = delete;
  constexpr const T& value() const& noexcept { return value_; }
  constexpr T&& value() && noexcept { return std::move(value_); }
  constexpr const T&& value() const&& noexcept { return std::move(value_); }

  bool operator==(const validated_type&) const
    requires std::equality_comparable<T>
  = default;
  auto operator<=>(const validated_type&) const
    requires std::three_way_comparable<T>
  = default;
};


#pragma once
#include "halley/utils/utils.h"
#include "halley/text/halleystring.h"
#include <memory>
#include <gsl/span>
#include "halley/resources/resource_data.h"

namespace Halley {
	enum class AssetType;
	class Deserializer;
	class Serializer;
	class AssetDatabase;
	class ResourceData;
	class ResourceDataReader;

	struct AssetPackHeader {
		std::array<char, 8> identifier;
		std::array<char, 16> iv;
		uint64_t assetDbStartPos;
		uint64_t dataStartPos;

		void init(size_t assetDbSize);
	};

    class AssetPack {
    public:
		AssetPack();
		AssetPack(const AssetPack& other) = delete;
		AssetPack(AssetPack&& other) noexcept;
		AssetPack(std::unique_ptr<ResourceDataReader> reader, const String& encryptionKey = "", bool preLoad = false);
		~AssetPack();

		AssetPack& operator=(const AssetPack& other) = delete;
		AssetPack& operator=(AssetPack&& other) noexcept;

		AssetDatabase& getAssetDatabase();
		const AssetDatabase& getAssetDatabase() const;
		Bytes& getData();
		const Bytes& getData() const;

		Bytes writeOut() const;

		std::unique_ptr<ResourceData> getData(const String& asset, AssetType type, bool stream);

		void readToMemory();
		void encrypt(const String& key);
		void decrypt(const String& key);

    	void readData(size_t pos, gsl::span<gsl::byte> dst);

		std::unique_ptr<ResourceDataReader> extractReader();

    private:
		std::unique_ptr<AssetDatabase> assetDb;
		std::unique_ptr<ResourceDataReader> reader;
		std::atomic<bool> hasReader;
		std::mutex readerMutex;
		size_t dataOffset = 0;
		Bytes data;
		std::array<char, 16> iv;
    };

	class PackDataReader final : public ResourceDataReader {
	public:
		PackDataReader(AssetPack& pack, size_t startPos, size_t fileSize);

		size_t size() const override;
		int read(gsl::span<gsl::byte> dst) override;
		void seek(int64_t pos, int whence) override;
		size_t tell() const override;
		void close() override;

	private:
		AssetPack& pack;
		const size_t startPos;
		const size_t fileSize;
		size_t curPos = 0;
		mutable std::mutex mutex;
	};
}


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <gsl/gsl_rng.h>
#include <time.h>
#include <assert.h>

#include "core_allvars.h"
#include "core_proto.h"
#include "temporal_array.h"

void init_galaxy(int p, int halonr, int treenr, int32_t filenr)
{
  int32_t j, step, status;

	assert(halonr == Halo[halonr].FirstHaloInFOFgroup);

  Gal[p].FileNr = filenr;

  Gal[p].Type = 0;
  Gal[p].TreeNr = treenr;

  Gal[p].GalaxyNr = GalaxyCounter;
  GalaxyCounter++;

  Gal[p].HaloNr = halonr;

  Gal[p].MostBoundID = Halo[halonr].MostBoundID;
  //Gal[p].MostBoundID = -1;
  Gal[p].SnapNum = Halo[halonr].SnapNum - 1;

  Gal[p].mergeType = 0;
  Gal[p].mergeIntoID = -1;
  Gal[p].mergeIntoSnapNum = -1;
  Gal[p].dT = -1.0;

  for(j = 0; j < 3; j++)
  {
    Gal[p].Pos[j] = Halo[halonr].Pos[j];
    Gal[p].Vel[j] = Halo[halonr].Vel[j];
  }

  Gal[p].Len = Halo[halonr].Len;
  Gal[p].Vmax = Halo[halonr].Vmax;
  Gal[p].Vvir = get_virial_velocity(halonr);
  Gal[p].Mvir = get_virial_mass(halonr);
  Gal[p].Rvir = get_virial_radius(halonr);

  Gal[p].deltaMvir = 0.0;

  Gal[p].ColdGas = 0.0;
  Gal[p].StellarMass = 0.0;
  Gal[p].BulgeMass = 0.0;
  Gal[p].HotGas = 0.0;
  Gal[p].EjectedMass = 0.0;
  Gal[p].EjectedMassSN = 0.0;
  Gal[p].EjectedMassQSO = 0.0;
  Gal[p].BlackHoleMass = 0.0;
  Gal[p].ICS = 0.0;

  Gal[p].MetalsColdGas = 0.0;
  Gal[p].MetalsStellarMass = 0.0;
  Gal[p].MetalsBulgeMass = 0.0;
  Gal[p].MetalsHotGas = 0.0;
  Gal[p].MetalsEjectedMass = 0.0;
  Gal[p].MetalsICS = 0.0;

  for(step = 0; step < STEPS; step++)
  {
    Gal[p].SfrDisk[step] = 0.0;
    Gal[p].SfrBulge[step] = 0.0;
    Gal[p].SfrDiskColdGas[step] = 0.0;
    Gal[p].SfrDiskColdGasMetals[step] = 0.0;
    Gal[p].SfrBulgeColdGas[step] = 0.0;
    Gal[p].SfrBulgeColdGasMetals[step] = 0.0;
  }

  Gal[p].DiskScaleRadius = get_disk_radius(halonr, p);
  Gal[p].MergTime = 999.9;
  Gal[p].Cooling = 0.0;
  Gal[p].Heating = 0.0;
  Gal[p].r_heat = 0.0;
  Gal[p].QuasarModeBHaccretionMass = 0.0;
  Gal[p].TimeOfLastMajorMerger = -1.0;
  Gal[p].TimeOfLastMinorMerger = -1.0;
  Gal[p].OutflowRate = 0.0;
	Gal[p].TotalSatelliteBaryons = 0.0;
	// infall properties
  Gal[p].infallMvir = -1.0;
  Gal[p].infallVvir = -1.0;
  Gal[p].infallVmax = -1.0;

  Gal[p].IsMerged = -1;

  status = malloc_temporal_arrays(&Gal[p]);
  if (status == EXIT_FAILURE)
  {
    ABORT(EXIT_FAILURE);
  }
  ++gal_mallocs;

  for (j = 0; j < MAXSNAPS; ++j)
  {
    Gal[p].GridType[j] = -1;
    Gal[p].GridFoFHaloNr[j] = -1;
    Gal[p].GridHistory[j] = -1;
    Gal[p].GridColdGas[j] = 0.0;
    Gal[p].GridHotGas[j] = 0.0;
    Gal[p].GridEjectedMass[j] = 0.0;
    Gal[p].GridDustColdGas[j] = 0.0;
    Gal[p].GridDustHotGas[j] = 0.0;
    Gal[p].GridDustEjectedMass[j] = 0.0;
    Gal[p].GridStellarMass[j] = 0.0;
    Gal[p].GridBHMass[j] = 0.0;
    Gal[p].GridSFR[j] = 0.0;
    Gal[p].GridZ[j] = 0.0;
    Gal[p].GridFoFMass[j] = 0.0;
    Gal[p].GridHaloMass[j] = 0.0;
    Gal[p].EjectedFraction[j] = 0.0;
    Gal[p].EjectedFractionSN[j] = 0.0;
    Gal[p].EjectedFractionQSO[j] = 0.0;
    Gal[p].LenHistory[j] = -1;
    Gal[p].GridOutflowRate[j] = 0.0;
    Gal[p].GridInfallRate[j] = 0.0;
    Gal[p].QuasarActivity[j] = 0;
    Gal[p].QuasarSubstep[j] = -1;
    Gal[p].DynamicalTime[j] = 0.0;
    Gal[p].LenMergerGal[j] = -1;
    Gal[p].GridReionMod[j] = -1.0;
    Gal[p].GridNgamma_HI[j] = 0.0;
    Gal[p].Gridfesc[j] = 0.0;
    Gal[p].ColdCrit[j] = 0.0;
    Gal[p].MUV[j] = 999.99;
  }

  Gal[p].GrandSum = 0.0;

  Gal[p].StellarAge_Numerator = 0.0;
  Gal[p].StellarAge_Denominator = 0.0;

  Gal[p].reheated_mass = 0.0;
  Gal[p].ejected_mass = 0.0;
  Gal[p].mass_stars_recycled = 0.0;
  Gal[p].mass_metals_new = 0.0;
  Gal[p].NSN = 0.0;

  if (IRA == 0)
  {
    for (j = 0; j < SN_Array_Len; ++j)
    {
      Gal[p].SN_Stars[j] = 0.0;
    }
  }
  Gal[p].Total_SN_SF_Time = 0.0;
  Gal[p].Total_SN_Stars = 0.0;

  // Dust Reservoirs.

  Gal[p].DustColdGas = 0.0;
  Gal[p].DustHotGas = 0.0;
  Gal[p].DustEjectedMass = 0.0;

  // Quasar Activity Tracking

  Gal[p].QuasarActivityToggle = 0;
  Gal[p].TargetQuasarTime = 0.0;
  Gal[p].QuasarBoostActiveTime = 0.0;
  Gal[p].QuasarFractionalPhotons = 0.0;

  // Stellar Age Tracking

  if (PhotonPrescription == 1)
  {
    for (j = 0; j < StellarTracking_Len; ++j)
    {
      Gal[p].Stellar_Stars[j] = 0.0;
    }
  }
  Gal[p].Total_Stellar_SF_Time = 0.0;
  Gal[p].Total_Stellar_Stars = 0.0;

}

double get_disk_radius(int halonr, int p)
{
  double SpinMagnitude, SpinParameter;

	if(Gal[p].Vvir > 0.0 && Gal[p].Rvir > 0.0)
	{
		// See Mo, Shude & White (1998) eq12, and using a Bullock style lambda.
		SpinMagnitude = sqrt(Halo[halonr].Spin[0] * Halo[halonr].Spin[0] +
			Halo[halonr].Spin[1] * Halo[halonr].Spin[1] + Halo[halonr].Spin[2] * Halo[halonr].Spin[2]);

		SpinParameter = SpinMagnitude / (1.414 * Gal[p].Vvir * Gal[p].Rvir);
		return (SpinParameter / 1.414) * Gal[p].Rvir;
	}
	else
		return 0.1 * Gal[p].Rvir;

}

double get_metallicity(double gas, double metals)
{
  double metallicity;

  if(gas > 0.0 && metals > 0.0)
  {
    metallicity = metals / gas;
    if(metallicity < 1.0)
      return metallicity;
    else
      return 1.0;
  }
  else
    return 0.0;

}

double get_dust_fraction(double gas, double dust)
{

  double dust_fraction;
  if (gas > 0.0 && dust > 0.0)
  {
    dust_fraction = dust / gas;
    if (dust_fraction < 1.0)
      return dust_fraction;
    else
      return 1.0;
  }
  else
  {
    return 0.0;
  }

}

double dmax(double x, double y)
{
  if(x > y)
    return x;
  else
    return y;
}

double get_virial_mass(int halonr)
{
  if(halonr == Halo[halonr].FirstHaloInFOFgroup && Halo[halonr].Mvir >= 0.0)
  {
    ++count_Mvir;
    return Halo[halonr].Mvir;   /* take spherical overdensity mass estimate */
  }
  else
  {
    ++count_Len;
    return Halo[halonr].Len * PartMass;
  }
}

double get_virial_velocity(int halonr)
{
	double Rvir;

	Rvir = get_virial_radius(halonr);

  if(Rvir > 0.0)
		return sqrt(sage_G * get_virial_mass(halonr) / Rvir);
	else
		return 0.0;
}

double get_virial_radius(int halonr)
{
  // return Halo[halonr].Rvir;  // Used for Bolshoi

  double zplus1, hubble_of_z_sq, rhocrit, fac;

  zplus1 = 1 + ZZ[Halo[halonr].SnapNum];
  hubble_of_z_sq =
    sage_Hubble * sage_Hubble *(Omega * zplus1 * zplus1 * zplus1 + (1 - Omega - OmegaLambda) * zplus1 * zplus1 +
    OmegaLambda);

  rhocrit = 3 * hubble_of_z_sq / (8 * M_PI * sage_G);
  fac = 1 / (200 * 4 * M_PI / 3.0 * rhocrit);

  return cbrt(get_virial_mass(halonr) * fac);
}

int32_t determine_1D_idx(float pos_x, float pos_y, float pos_z, int32_t *grid_1D)
{

  int32_t x_grid, y_grid, z_grid;

  x_grid = round(pos_x * GridSize/BoxSize);
  if (x_grid == GridSize)
    --x_grid;

  y_grid = round(pos_y * GridSize/BoxSize);
  if (y_grid == GridSize)
    --y_grid;

  z_grid = round(pos_z * GridSize/BoxSize);
  if (z_grid == GridSize)
    --z_grid;

  *grid_1D = (z_grid*GridSize+y_grid)*GridSize+x_grid; // Convert the grid (x,y,z) to a 1D value.

  if(*grid_1D > CUBE(GridSize) || *grid_1D < 0) // Sanity check to ensure that no Grid Positions are outside the box.
  {
    fprintf(stderr, "Found a Grid Position outside the bounds of the box or negative\nPos[0] = %.4f\tPos[1] = %.4f\tPos[2] = %.4f\n", pos_x, pos_y, pos_z);
    fprintf(stderr, "Grid indices were x = %d\ty = %d\tz = %d\t1D = %d\tMaximum Allowed = %d\n", x_grid, y_grid, z_grid, *grid_1D, CUBE(GridSize) - 1);

    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}


#pragma once
#include <gsl/gsl>
#include <map>
#include "halley/text/halleystring.h"
#include "halley/maths/vector4.h"

namespace Halley
{
	class Path;
	class Image;
	struct ImageData;

	class AsepriteReader
	{
	public:
		static std::vector<ImageData> importAseprite(String baseName, gsl::span<const gsl::byte> fileData, bool trim);
	};
}


#pragma once

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

namespace Library
{
	class Game;

	class RenderStateHelper final
	{
	public:
		RenderStateHelper(Game& game);
		RenderStateHelper(const RenderStateHelper&) = delete;
		RenderStateHelper(RenderStateHelper&&) = default;
		RenderStateHelper& operator=(const RenderStateHelper&) = delete;
		RenderStateHelper& operator=(RenderStateHelper&&) = default;
		~RenderStateHelper() = default;

		static void ResetAll(gsl::not_null<ID3D11DeviceContext*> deviceContext);
		static void ResetRasterizerState(gsl::not_null<ID3D11DeviceContext*> deviceContext);
		static void ResetBlendState(gsl::not_null<ID3D11DeviceContext*> deviceContext);
		static void ResetDepthStencilState(gsl::not_null<ID3D11DeviceContext*> deviceContext);

		ID3D11RasterizerState* RasterizerState();
		ID3D11BlendState* BlendState();
		ID3D11DepthStencilState* DepthStencilState();

		void SaveRasterizerState();
		void RestoreRasterizerState() const;

		void SaveBlendState();
		void RestoreBlendState() const;

		void SaveDepthStencilState();
		void RestoreDepthStencilState() const;

		void SaveAll();
		void RestoreAll() const;
		void ClearAll();

	private:
		Game& mGame;

		winrt::com_ptr<ID3D11RasterizerState> mRasterizerState;
		winrt::com_ptr<ID3D11BlendState> mBlendState;
		std::array<float, 4> mBlendFactor;
		std::uint32_t mSampleMask{ std::numeric_limits<std::uint32_t>::max() };
		winrt::com_ptr<ID3D11DepthStencilState> mDepthStencilState;
		std::uint32_t mStencilRef{ std::numeric_limits<std::uint32_t>::max() };
	};
}


#pragma once

#include "continuation_scheduler.h"

#include <arcana/threading/cancellation.h>
#include <arcana/threading/task.h>

#include <gsl/gsl>

#include <condition_variable>
#include <mutex>
#include <optional>

namespace Babylon::Graphics
{
    class SafeTimespanGuarantor
    {
    public:
        SafeTimespanGuarantor(std::optional<arcana::cancellation_source>&);

        continuation_scheduler<>& OpenScheduler()
        {
            return m_openDispatcher.scheduler();
        }

        continuation_scheduler<>& CloseScheduler()
        {
            return m_closeDispatcher.scheduler();
        }

        using SafetyGuarantee = gsl::final_action<std::function<void()>>;
        SafetyGuarantee GetSafetyGuarantee();

        void Open();
        void RequestClose();
        void Lock();
        void Unlock();

    private:
        enum class State
        {
            Open,
            Closing,
            Closed,
            Locked
        };

        std::optional<arcana::cancellation_source>& m_cancellation;
        State m_state{State::Locked};
        uint32_t m_count{};
        std::mutex m_mutex{};
        std::condition_variable m_condition_variable{};
        continuation_dispatcher<> m_openDispatcher{};
        continuation_dispatcher<> m_closeDispatcher{};
    };
}


#pragma once

#include "icode_generator.h"
#include <halley/data_structures/hash_map.h>
#include <gsl/gsl>
#include "halley/file/path.h"

namespace YAML
{
	class Node;
}

namespace Halley
{
	class ECSData;
	class ComponentSchema;
	class SystemSchema;
	class MessageSchema;
	class CustomTypeSchema;

	class Codegen
	{
		struct Stats
		{
			int written = 0;
			int skipped = 0;
			std::vector<Path> files;
		};

	public:
		using ProgressReporter = std::function<bool(float, String)>;

		static void run(Path inDir, Path outDir);
		static std::vector<Path> generateCode(const ECSData& data, Path directory);

	private:
		static bool writeFile(Path path, const char* data, size_t dataSize, bool stub);
		static void writeFiles(Path directory, const CodeGenResult& files, Stats& stats);
	};
}


#pragma once

#include <tuple>

#include "arcana/threading/dispatcher.h"

#include "router.h"

#include <gsl/gsl>

namespace arcana
{
    //
    // A mediator is an event pool that ensures all events are sent
    // through the right dispatcher (execution context).
    // This is usefull when you want anyone to be able to send
    // events but only want to process the events from one thread.
    //
    template<typename DispatcherT, typename... EventTs>
    class mediator
    {
        using router_t = router<EventTs...>;

    public:
        using dispatcher_t = DispatcherT;

        explicit mediator(dispatcher_t& dispatcher)
            : m_dispatcher{ dispatcher }
        {}

        template<typename T>
        void send(T&& evt)
        {
            m_dispatcher.queue([ this, evt = std::forward<T>(evt) ]() { m_router.fire(evt); });
        }

        template<typename EventT, typename T>
        ticket add_listener(T&& listener)
        {
            GSL_CONTRACT_CHECK("thread affinity", m_dispatcher.get_affinity().check());
            return m_router.template add_listener<EventT>(std::forward<T>(listener));
        }

        dispatcher_t& dispatcher()
        {
            return m_dispatcher;
        }

    private:
        dispatcher_t& m_dispatcher;
        router_t m_router;
    };
}


/*
 * 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 file_d50c3538_0c5e_49a3_bc6f_5d6bc6144520_h
#define file_d50c3538_0c5e_49a3_bc6f_5d6bc6144520_h

#include <stdio.h>
#include <gslib/config.h>
#include <gslib/string.h>

__gslib_begin__

typedef FILE*   fileptr;
typedef fpos_t  fpos;

class file
{
protected:
    fileptr     _file;

public:
    file(): _file(0) {}
    file(const gchar* name, const gchar* mode): _file(0) { open(name, mode); }
    ~file() { close(); }

#ifndef _UNICODE

    void open(const gchar* name, const gchar* mode) { fopen_s(&_file, name, mode); }
    void open_text(const gchar* name, bool readonly)
    {
        readonly ? fopen_s(&_file, name, _t("r")) :
            fopen_s(&_file, name, _t("w"));
    }
    int read(gchar buf[], int len)
    {
        assert(buf && len);
        return fgets(buf, len, _file) ? strlen(buf) : 0;
    }
    int write(const gchar str[])
    {
        assert(str);
        return (int)fputs(str, _file);
    }

#else

    void open(const gchar* name, const gchar* mode) { _wfopen_s(&_file, name, mode); }
    void open_text(const gchar* name, bool readonly)
    {
        readonly ? _wfopen_s(&_file, name, _t("r,ccs=UNICODE")) :
            _wfopen_s(&_file, name, _t("w,ccs=UNICODE"));
    }
    int read(gchar buf[], int len)
    {
        assert(buf && len);
        return fgetws(buf, len, _file) ? wcslen(buf) : 0;
    }
    int write(const gchar str[])
    {
        assert(str);
        return fputws(str, _file);
    }

#endif

    bool is_valid() const { return _file != 0; }
    void flush() { fflush(_file); }
    void rewind() { ::rewind(_file); }
    int current() const { return ftell(_file); }
    int seek(int offset, int sps) { return fseek(_file, offset, sps); }
    int size()
    {
        int old = current();
        seek(0, SEEK_END);
        int pos = current();
        seek(old, SEEK_SET);
        return pos;
    }
    void close()
    {
        if (_file) {
            fclose(_file);
            _file = 0;
        }
    }
    int read_fillup(gchar buf[], int len)
    {
        assert(buf && len > 0);
        int acc = 0;
        while(acc < len) {
            int r = read(buf + acc, len - acc);
            if(r <= 0)
                break;
            acc += r;
        }
        return acc;
    }
    int read(string& buf, int start, int len)
    {
        int lento = start + len;
        if(lento && buf.size() < lento)
            buf.resize(lento);
        return read(&buf.front() + start, len);
    }
    void read_all(string& buf)
    {
        int total = size() + 1;     /* a weird problem about fgetws. */
        if(buf.size() < total)
            buf.resize(total);
        for(int i = 0, j; j = read(buf, i, total-i); i += j);
        /* right trim */
        int p = buf.find_last_not_of(_t('\0'));
        if(p != string::npos) {
            p += 1;
            if(p <= buf.length())
                buf.resize(p);
        }
    }
    int write(const string& buf) { return write(&buf.front()); }
    int get(byte buf[], int len) { return (int)fread_s(buf, len, 1, len, _file); }
    int get(word buf[], int len) { return (int)fread_s(buf, len * 2, 2, len, _file); }
    int get(dword buf[], int len) { return (int)fread_s(buf, len * 4, 4, len, _file); }
    int get(qword buf[], int len) { return (int)fread_s(buf, len * 8, 8, len, _file); }
    int put(const byte buf[], int len) { return (int)fwrite(buf, 1, len, _file); }
    int put(const word buf[], int len) { return (int)fwrite(buf, 2, len, _file); }
    int put(const dword buf[], int len) { return (int)fwrite(buf, 4, len, _file); }
    int put(const qword buf[], int len) { return (int)fwrite(buf, 8, len, _file); }

public:
    template<int _szelem>
    int put_elem(const void* buf, int len) {}
    template<>
    int put_elem<1>(const void* buf, int len) { return put((const byte*)buf, len); }
    template<>
    int put_elem<2>(const void* buf, int len) { return put((const word*)buf, len); }
    template<>
    int put_elem<4>(const void* buf, int len) { return put((const dword*)buf, len); }
    template<>
    int put_elem<8>(const void* buf, int len) { return put((const qword*)buf, len); }
};

__gslib_end__

#endif