#pragma once

#include <Babylon/JsRuntime.h>
#include <napi/env.h>
#include <gsl/gsl>
#include <cassert>

namespace Babylon
{
    class NativeDataStream final : public Napi::ObjectWrap<NativeDataStream>
    {
        static constexpr auto JS_CLASS_NAME = "_NativeDataStream";
        static constexpr auto JS_ENGINE_CONSTRUCTOR_NAME = "NativeDataStream";

        static constexpr auto VALIDATION_ENABLED = false;

        enum class ValidationType : uint32_t
        {
            Uint32,
            Int32,
            Float32,
            Uint32Array,
            Int32Array,
            Float32Array,
            NativeData,
            Boolean,
        };

        template<ValidationType T, typename ReaderT>
        static inline void Validate(ReaderT& reader)
        {
            if constexpr (VALIDATION_ENABLED)
            {
                uint32_t value{reader.template Read<uint32_t>()};
                if (value != static_cast<uint32_t>(T))
                {
                    throw std::runtime_error{"Data stream validation error: data type mismatch."};
                }
            }
        }

    public:
        class Reader final
        {
        public:
            Reader(const Reader&) = delete;
            Reader(Reader&&) = delete;
            Reader operator=(const Reader&) = delete;
            Reader operator=(const Reader&&) = delete;

            bool CanRead() const
            {
                assert(m_position <= static_cast<size_t>(m_buffer.size()));
                return m_position < static_cast<size_t>(m_buffer.size());
            }

            uint32_t ReadUint32()
            {
                Validate<ValidationType::Uint32>(*this);
                return Read<uint32_t>();
            }

            int32_t ReadInt32()
            {
                Validate<ValidationType::Int32>(*this);
                return Read<int32_t>();
            }

            float ReadFloat32()
            {
                Validate<ValidationType::Float32>(*this);
                return Read<float>();
            }

            gsl::span<uint32_t> ReadUint32Array()
            {
                Validate<ValidationType::Uint32Array>(*this);
                return ReadArray<uint32_t>();
            }

            gsl::span<int32_t> ReadInt32Array()
            {
                Validate<ValidationType::Int32Array>(*this);
                return ReadArray<int32_t>();
            }

            gsl::span<float> ReadFloat32Array()
            {
                Validate<ValidationType::Float32Array>(*this);
                return ReadArray<float>();
            }

            template<typename T>
            T ReadNativeData()
            {
                Validate<ValidationType::NativeData>(*this);
                static_assert(sizeof(T) % 4 == 0);
                auto span = gsl::make_span(reinterpret_cast<uint32_t*>(m_buffer.data() + m_position), sizeof(T) / 4);
                m_position += sizeof(T) / 4;
                return *reinterpret_cast<T*>(span.data());
            }

            template<typename T, class = typename std::enable_if<!std::is_pointer<T>::value>::type>
            auto ReadPointer()
            {
                return ReadNativeData<typename std::conditional<std::is_member_pointer<T>::value, T, T*>::type>();
            }

        private:
            gsl::span<uint32_t> m_buffer{};
            size_t m_position{0};
            const gsl::final_action<std::function<void()>> m_scopeGuard;

            friend class NativeDataStream;

            template<typename CallableT>
            Reader(gsl::span<uint32_t> buffer, CallableT&& callable)
                : m_buffer{buffer}
                , m_scopeGuard{std::forward<CallableT>(callable)}
            {
            }

            template<typename T>
            T Read()
            {
                static_assert(sizeof(T) % 4 == 0);
                T t{*reinterpret_cast<T*>(m_buffer.data() + m_position)};
                m_position += sizeof(T) / 4;
                return t;
            }

            template<typename T>
            gsl::span<T> ReadArray()
            {
                static_assert(sizeof(T) % 4 == 0);

                // The first 32 bit number is a length
                uint32_t length = Read<uint32_t>();

                auto span = gsl::make_span<T>(reinterpret_cast<T*>(m_buffer.data() + m_position), length * (sizeof(T) / 4));
                m_position += length;
                return span;
            }
        };

        static void Initialize(Napi::Env env)
        {
            Napi::HandleScope scope{env};
            if constexpr (VALIDATION_ENABLED)
            {
                Napi::Function func = DefineClass(
                    env,
                    JS_CLASS_NAME,
                    {
                        InstanceMethod("writeBuffer", &NativeDataStream::WriteBuffer),

                        StaticValue("VALIDATION_ENABLED", Napi::Boolean::From(env, VALIDATION_ENABLED)),
                        StaticValue("VALIDATION_UINT_32", Napi::Number::From(env, static_cast<uint32_t>(ValidationType::Uint32))),
                        StaticValue("VALIDATION_INT_32", Napi::Number::From(env, static_cast<uint32_t>(ValidationType::Int32))),
                        StaticValue("VALIDATION_FLOAT_32", Napi::Number::From(env, static_cast<uint32_t>(ValidationType::Float32))),
                        StaticValue("VALIDATION_UINT_32_ARRAY", Napi::Number::From(env, static_cast<uint32_t>(ValidationType::Uint32Array))),
                        StaticValue("VALIDATION_INT_32_ARRAY", Napi::Number::From(env, static_cast<uint32_t>(ValidationType::Int32Array))),
                        StaticValue("VALIDATION_FLOAT_32_ARRAY", Napi::Number::From(env, static_cast<uint32_t>(ValidationType::Float32Array))),
                        StaticValue("VALIDATION_NATIVE_DATA", Napi::Number::From(env, static_cast<uint32_t>(ValidationType::NativeData))),
                        StaticValue("VALIDATION_BOOLEAN", Napi::Number::From(env, static_cast<uint32_t>(ValidationType::Boolean))),
                    });
                JsRuntime::NativeObject::GetFromJavaScript(env).Set(JS_ENGINE_CONSTRUCTOR_NAME, func);
            }
            else
            {
                Napi::Function func = DefineClass(
                    env,
                    JS_CLASS_NAME,
                    {
                        InstanceMethod("writeBuffer", &NativeDataStream::WriteBuffer)
                    });
                JsRuntime::NativeObject::GetFromJavaScript(env).Set(JS_ENGINE_CONSTRUCTOR_NAME, func);
            }
        }

        NativeDataStream(const Napi::CallbackInfo& info)
            : Napi::ObjectWrap<NativeDataStream>(info)
            , m_requestFlushCallback{Napi::Persistent(info[0].As<Napi::Function>())}
        {
        }

        void WriteBuffer(const Napi::CallbackInfo& info)
        {
            assert(!m_locked); // Cannot write bytes while the stream is locked for reading.

            const auto& buffer = info[0].As<Napi::ArrayBuffer>();
            const auto& length = info[1].ToNumber().Uint32Value();

            auto span = gsl::make_span(reinterpret_cast<uint32_t*>(buffer.Data()), static_cast<ptrdiff_t>(length));
            m_buffer.insert(m_buffer.end(), span.begin(), span.end());
        }

        Reader GetReader()
        {
            assert(!m_locked);
            m_requestFlushCallback.Call({});
            m_locked = true;
            return {m_buffer, [this]() {
                m_buffer.clear();
                m_locked = false;
            }};
        }

    private:
        std::vector<uint32_t> m_buffer{};
        Napi::FunctionReference m_requestFlushCallback{};
        bool m_locked{false};
    };
}


#pragma once

#include "ui_MaterialVisualizationWidget.h"

#include <mitkDataNode.h>
#include <vtkDataObject.h>

#include <array>
#include <gsl.h>

namespace mitk
{
class DataNode;
class TransferFunction;
}

/*! \brief   A widget for editing transfer function. */
class MaterialVisualizationWidget : public QWidget
{
    Q_OBJECT
public:
    MaterialVisualizationWidget(QWidget* parent = nullptr, Qt::WindowFlags f = 0);
    ~MaterialVisualizationWidget();

    /*!
     * \brief   Sets the data node whose transfer function is to be edited.
     *
     * \param   node                The data node.
     * \param   dataSet             The vtkDataSet stored in the data node (the access may differ for mitk::Surface and mitk::UnstructuredGrid).
     * \param   tfPropertyName      Name of the transfer function property used by the renderer.
     * \param   attributeType       Type of the attribute to be shown (vtkDataObject::POINT or vtkDataObject::CELL).
     * \param   propertyStorageNode If non-null, the node where to store various transfer functions to be re-used later. If null, the 'node' will be used.
     */
    void setDataNode(mitk::DataNode* node, vtkDataSet* dataSet, gsl::cstring_span<> tfPropertyName,
                     vtkDataObject::AttributeTypes attributeType = vtkDataObject::POINT,
                     mitk::DataNode* propertyStorageNode = nullptr);
    /*! \brief   Resets the data node to null. */
    void resetDataNode() { setDataNode(nullptr, nullptr, ""); }

    /*! \brief   Gets data node. */
    mitk::DataNode* getDataNode() const { return _node; }

private slots:
    void _setCurrentArray(const QString& arrayName);
    void _setCurrentComponent(int comboBoxIndex);
    void _resetTF();
    void _setNanColor(QColor c);

    void _setColorSpace(int colorSpace);
    void _loadTF();
    void _saveTF();

private:
    void _dataNodeDeleted();
    std::string _getCurrentTFPropName();
    void _setupDataComboBoxes();
    void _setTransferFunction(bool reset = false);
    static void _setupTFProperties(mitk::TransferFunction* tf, int componentIndex);
    static void _generateTF(mitk::TransferFunction* tf, const std::array<double, 2>& range);
    static void _rescaleTF(mitk::TransferFunction* tf, const std::array<double, 2>& range);
    QColor _getNanColor();
    void _addNodeObserver();
    void _removeNodeObserver();

    mitk::DataNode* _node = nullptr;
    vtkDataSet* _dataSet = nullptr;
    std::string _tfPropertyName;
    vtkDataObject::AttributeTypes _attributeType = vtkDataObject::POINT;
    mitk::DataNode* _propertyStorageNode = nullptr;
    Ui::MaterialVisualizationWidget _UI;
    unsigned long _nodeObserverTag = -1;
};


#ifndef __UTIL_H
#define __UTIL_H

#include <glib.h>
#include <gsl/gsl_matrix.h>

struct _CLArgumentEntry {
  GString *block;
  char *label;
};

struct _LabeledMatrix {
  gsl_matrix *mat;
  char **labels1;
  char **labels2;
};

typedef struct _LabeledMatrix LabeledMatrix ;
typedef struct _CLArgumentEntry CLArgumentEntry ;

char *complearn_make_temp_dir_name(void);
char *complearn_make_temp_dir(void);
int make_directory(const char *name);
int complearn_make_directory_if_necessary(const char *name);
GString *complearn_read_whole_file(const char *fname);
int complearn_count_strings(const char * const * str);
int complearn_remove_directory_recursively(const char *dirname, int f_err_out);
GString *complearn_read_whole_file_ptr(FILE *fp);
GString *complearn_read_whole_file_io(GIOChannel *gio);
GSList *complearn_read_directory_of_files(const char *dirname);
GSList *complearn_read_list_of_files(const char *filename);
GSList *complearn_read_list_of_strings(const char *filename);
gsl_matrix *complearn_average_matrix(gsl_matrix *a);
gsl_matrix *complearn_svd_project(gsl_matrix *a);
CLArgumentEntry *complearn_new_arg(GString *block, const char *label);
int complearn_get_pid(void);
char *complearn_get_hostname();
char ** complearn_dupe_strings(const char * const * str);
char ** complearn_fix_labels(char **inp);
char *complearn_make_temp_file_name(void);
char *complearn_chdir(const char *newdir);
int complearn_write_file(const char *fname, const GString *f);
void complearn_mrbreaker(void);

#endif


#pragma once

#include "rev/gl/Context.h"
#include "rev/gl/Resource.h"
#include "rev/gl/Uniform.h"

#include <array>
#include <gsl/gsl_assert>
#include <string>

namespace rev {

template <GLenum shaderType>
GLuint createShader()
{
    return glCreateShader(shaderType);
}

namespace detail {
    template <void (*propertyGetter)(GLuint, GLenum, GLint*),
        void (*logGetter)(GLuint, GLsizei, GLsizei*, GLchar*)>
    std::string extractLog(GLuint objectId)
    {
        GLint logLength;
        propertyGetter(objectId, GL_INFO_LOG_LENGTH, &logLength);

        std::string log;
        log.resize(logLength);

        GLint fetchedLength;
        logGetter(objectId, logLength, &fetchedLength, log.data());

        log.resize(fetchedLength);

        return log;
    }
} // namespace detail

template <GLenum shaderType>
class Shader : public Resource<createShader<shaderType>, gl::deleteShader> {
public:
    void setSource(const std::string_view& source)
    {
        setSource(std::array<std::string_view, 1>{ source });
    }

    template <size_t arrayLength>
    void setSource(const std::array<std::string_view, arrayLength>& source)
    {
        std::array<const char*, arrayLength> pointers;
        std::array<GLint, arrayLength> lengths;
        for (size_t i = 0; i < arrayLength; i++) {
            pointers[i] = source[i].data();
            lengths[i] = static_cast<GLint>(source[i].size());
            Expects(source[i].size() <= std::numeric_limits<GLint>::max());
        }
        glShaderSource(this->getId(), arrayLength, pointers.data(), lengths.data());
    }

    void compile() { glCompileShader(this->getId()); }

    bool getCompileStatus()
    {
        GLint status;
        glGetShaderiv(this->getId(), GL_COMPILE_STATUS, &status);
        return (status == GL_TRUE);
    }

    std::string getCompileLog()
    {
        return detail::extractLog<gl::getShaderiv, gl::getShaderInfoLog>(this->getId());
    }
};

using VertexShader = Shader<GL_VERTEX_SHADER>;
using FragmentShader = Shader<GL_FRAGMENT_SHADER>;

class ProgramResource : public Resource<gl::createProgram, gl::deleteProgram> {
public:
    template <GLenum shaderType>
    void attachShader(const Shader<shaderType>& shader)
    {
        glAttachShader(getId(), shader.getId());
    }

    void link() { glLinkProgram(getId()); }

    bool getLinkStatus()
    {
        GLint status;
        glGetProgramiv(getId(), GL_LINK_STATUS, &status);
        return (status == GL_TRUE);
    }

    std::string getLinkLog()
    {
        return detail::extractLog<gl::getProgramiv, gl::getProgramInfoLog>(getId());
    }

    template <typename VertexSourceType, typename FragmentSourceType>
    void buildWithSource(
        const VertexSourceType& vertexSource, const FragmentSourceType& fragmentSource)
    {
        VertexShader vShader;
        vShader.setSource(vertexSource);
        vShader.compile();
        if (!vShader.getCompileStatus()) {
            throw vShader.getCompileLog();
        }

        FragmentShader fShader;
        fShader.setSource(fragmentSource);
        fShader.compile();
        if (!fShader.getCompileStatus()) {
            throw fShader.getCompileLog();
        }

        attachShader(vShader);
        attachShader(fShader);
        link();
        if (!getLinkStatus()) {
            throw getLinkLog();
        }
    }

    template <typename VariableType>
    Uniform<VariableType> getUniform(const char* name)
    {
        GLint location = glGetUniformLocation(getId(), name);

        return Uniform<VariableType>(location);
    }
};

using ProgramContext = ResourceContext<ProgramResource, gl::useProgram>;

} // namespace rev


#pragma once

#include <gsl\gsl>
#include <winrt\Windows.Foundation.h>
#include <d3d11.h>
#include <map>
#include "DrawableGameComponent.h"
#include "FullScreenRenderTarget.h"
#include "Bloom.h"

namespace Rendering
{
	class DiffuseLightingDemo;

	class BloomDemo final : public Library::DrawableGameComponent
	{
	public:
		BloomDemo(Library::Game& game, const std::shared_ptr<Library::Camera>& camera);
		BloomDemo(const BloomDemo&) = delete;
		BloomDemo(BloomDemo&&) = default;
		BloomDemo& operator=(const BloomDemo&) = default;
		BloomDemo& operator=(BloomDemo&&) = default;
		~BloomDemo();

		std::shared_ptr<DiffuseLightingDemo> DiffuseLighting() const;

		bool BloomEnabled() const;
		void SetBloomEnabled(bool enabled);
		void ToggleBloom();

		Library::BloomDrawModes DrawMode() const;
		const std::string& DrawModeString() const;
		void SetDrawMode(Library::BloomDrawModes drawMode);

		const Library::BloomSettings& GetBloomSettings() const;
		void SetBloomSettings(Library::BloomSettings& settings);

		virtual void Initialize() override;
		virtual void Update(const Library::GameTime& gameTime) override;
		virtual void Draw(const Library::GameTime& gameTime) override;

	private:
		std::shared_ptr<DiffuseLightingDemo> mDiffuseLightingDemo;
		Library::FullScreenRenderTarget mRenderTarget;
		Library::Bloom mBloom;
		bool mBloomEnabled{ true };
	};
}


#ifndef PETSC4PY_COMPAT_H
#define PETSC4PY_COMPAT_H

#include <petsc.h>
#include "compat/mpi.h"
#include "compat/hdf5.h"
#include "compat/tao.h"

#endif/*PETSC4PY_COMPAT_H*/


//  This matrix class is a C++ wrapper for the GNU Scientific Library
//  Copyright (C)  ULP-IPB Strasbourg

//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.

//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.

//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#ifndef _vector_float_h
#define _vector_float_h

#ifdef __HP_aCC
#include <iostream.h>
#else
#include <iostream>
#endif

#include <gsl/gsl_math.h>
#include <gsl/gsl_vector_float.h>
#include <gsl/gsl_blas.h>
#include <gslwrap/vector_double.h>

//#define NDEBUG 0

#include <assert.h>
namespace gsl
{

#ifndef __HP_aCC
	using std::ostream;
//using std::string;
//using std::runtime_error;
#endif

class vector_float_view;

class vector_float
{
protected:
	gsl_vector_float *gsldata;
	void free(){if(gsldata) gsl_vector_float_free(gsldata);gsldata=NULL;}
	void alloc(size_t n) {gsldata=gsl_vector_float_alloc(n);}
	void calloc(size_t n){gsldata=gsl_vector_float_calloc(n);}
public:
	typedef float value_type;
	vector_float() : gsldata(NULL) {;}
	vector_float( const vector_float &other ):gsldata(NULL) {copy(other);}
	template<class oclass>
	vector_float( const oclass &other ):gsldata(NULL) {copy(other);}
	~vector_float(){free();}
	vector_float(const size_t& n,bool clear=true)
	{
	   this->gsldata = NULL;
		if(clear){this->calloc(n);}
		else     {this->alloc(n);}
	}
	vector_float(const int& n,bool clear=true)
	{
	   this->gsldata = NULL;
		if(clear){this->calloc(n);}
		else     {this->alloc(n);}
	}

	void resize(size_t n);

	template <class oclass>
		void copy(const oclass &other)
		{
			if ( static_cast<const void *>( this ) == static_cast<const void *>( &other ) )
				return;

			if (!other.is_set())
			{
				gsldata=NULL;
				return;
			}
			resize(other.size());
			for (size_t i=0;i<size();i++)
			{
				gsl_vector_float_set(gsldata, i, (float)other[i]);
			}
		}
	void copy(const vector_float& other);
	bool is_set() const{if (gsldata) return true; else return false;}
//	void clone(vector_float& other);

//	size_t size() const {if (!gsldata) {cout << "vector_float::size vector not initialized" << endl; exit(-1);}return gsldata->size;}
	size_t size() const {assert (gsldata); return gsldata->size;}

	/** for interfacing with gsl c */
/*  	gsl_vector_float       *gslobj()       {if (!gsldata){cout << "vector_float::gslobj ERROR, data not initialized!! " << endl; exit(-1);}return gsldata;} */
/*  	const gsl_vector_float *gslobj() const {if (!gsldata){cout << "vector_float::gslobj ERROR, data not initialized!! " << endl; exit(-1);}return gsldata;} */
	gsl_vector_float       *gslobj()       {assert(gsldata);return gsldata;}
	const gsl_vector_float *gslobj() const {assert(gsldata);return gsldata;}

	static vector_float_view create_vector_view( const gsl_vector_float_view &other );

// ********Accessing vector elements

//  Unlike FORTRAN compilers, C compilers do not usually provide support for range checking of vectors and matrices (2). However, the functions gsl_vector_float_get and gsl_vector_float_set can perform range checking for you and report an error if you attempt to access elements outside the allowed range.

//  The functions for accessing the elements of a vector or matrix are defined in `gsl_vector_float.h' and declared extern inline to eliminate function-call overhead. If necessary you can turn off range checking completely without modifying any source files by recompiling your program with the preprocessor definition GSL_RANGE_CHECK_OFF. Provided your compiler supports inline functions the effect of turning off range checking is to replace calls to gsl_vector_float_get(v,i) by v->data[i*v->stride] and and calls to gsl_vector_float_set(v,i,x) by v->data[i*v->stride]=x. Thus there should be no performance penalty for using the range checking functions when range checking is turned off.

//      This function returns the i-th element of a vector v. If i lies outside the allowed range of 0 to n-1 then the error handler is invoked and 0 is returned.
	float get(size_t i) const {return gsl_vector_float_get(gsldata,i);}

//      This function sets the value of the i-th element of a vector v to x. If i lies outside the allowed range of 0 to n-1 then the error handler is invoked.
	void  set(size_t i,float x){gsl_vector_float_set(gsldata,i,x);}

//      These functions return a pointer to the i-th element of a vector v. If i lies outside the allowed range of 0 to n-1 then the error handler is invoked
	float       &operator[](size_t i)       { return *gsl_vector_float_ptr(gsldata,i);}
	const float &operator[](size_t i) const { return *gsl_vector_float_ptr(gsldata,i);}

	float       &operator()(size_t i)       { return *gsl_vector_float_ptr(gsldata,i);}
	const float &operator()(size_t i) const { return *gsl_vector_float_ptr(gsldata,i);}

//  ***** Initializing vector elements

//      This function sets all the elements of the vector v to the value x.
	void set_all(float x){gsl_vector_float_set_all (gsldata,x);}
//      This function sets all the elements of the vector v to zero.
	void set_zero(){gsl_vector_float_set_zero (gsldata);}

//      This function makes a basis vector by setting all the elements of the vector v to zero except for the i-th element which is set to one.
	int set_basis (size_t i) {return gsl_vector_float_set_basis (gsldata,i);}

//  **** Reading and writing vectors

//  The library provides functions for reading and writing vectors to a file as binary data or formatted text.

//      This function writes the elements of the vector v to the stream stream in binary format. The return value is 0 for success and GSL_EFAILED if there was a problem writing to the file. Since the data is written in the native binary format it may not be portable between different architectures.
	int fwrite (FILE * stream) const {return gsl_vector_float_fwrite (stream, gsldata);}

//      This function reads into the vector v from the open stream stream in binary format. The vector v must be preallocated with the correct length since the function uses the size of v to determine how many bytes to read. The return value is 0 for success and GSL_EFAILED if there was a problem reading from the file. The data is assumed to have been written in the native binary format on the same architecture.
	int fread (FILE * stream) {return gsl_vector_float_fread (stream, gsldata);}

	void load( const char *filename );
	///
	void save( const char *filename ) const;

//      This function writes the elements of the vector v line-by-line to the stream stream using the format specifier format, which should be one of the %g, %e or %f formats for floating point numbers and %d for integers. The function returns 0 for success and GSL_EFAILED if there was a problem writing to the file.
	int fprintf (FILE * stream, const char * format) const {return gsl_vector_float_fprintf (stream, gsldata,format) ;}

//      This function reads formatted data from the stream stream into the vector v. The vector v must be preallocated with the correct length since the function uses the size of v to determine how many numbers to read. The function returns 0 for success and GSL_EFAILED if there was a problem reading from the file.
	int fscanf (FILE * stream)  {return gsl_vector_float_fscanf (stream, gsldata); }

//  ******* Vector views

//  In addition to creating vectors from slices of blocks it is also possible to slice vectors and create vector views. For example, a subvector of another vector can be described with a view, or two views can be made which provide access to the even and odd elements of a vector.

//  A vector view is a temporary object, stored on the stack, which can be used to operate on a subset of vector elements. Vector views can be defined for both constant and non-constant vectors, using separate types that preserve constness. A vector view has the type gsl_vector_float_view and a constant vector view has the type gsl_vector_float_const_view. In both cases the elements of the view can be accessed as a gsl_vector_float using the vector component of the view object. A pointer to a vector of type gsl_vector_float * or const gsl_vector_float * can be obtained by taking the address of this component with the & operator.

//      These functions return a vector view of a subvector of another vector v. The start of the new vector is offset by offset elements from the start of the original
//      vector. The new vector has n elements. Mathematically, the i-th element of the new vector v' is given by,

//      v'(i) = v->data[(offset + i)*v->stride]

//      where the index i runs from 0 to n-1.

//      The data pointer of the returned vector struct is set to null if the combined parameters (offset,n) overrun the end of the original vector.

//      The new vector is only a view of the block underlying the original vector, v. The block containing the elements of v is not owned by the new vector. When the
//      new vector goes out of scope the original vector v and its block will continue to exist. The original memory can only be deallocated by freeing the original vector.
//      Of course, the original vector should not be deallocated while the new vector is still in use.

//      The function gsl_vector_float_const_subvector is equivalent to gsl_vector_float_subvector but can be used for vectors which are declared const.
	vector_float_view subvector (size_t offset, size_t n);
	const vector_float_view subvector (size_t offset, size_t n) const;
//	vector_float_const_view subvector (size_t offset, size_t n) const;

//  	class view
//  	{
//  		gsl_vector_float_view *gsldata;
//  	public:
//  		view();
//  	};
//  	view subvector(size_t offset, size_t n)
//  	{
//  		return view(gsl_vector_float_subvector(gsldata,offset,n);
//  	}
//  	const view subvector(size_t offset, size_t n) const
//  	{
//  		return view(gsl_vector_float_const_subvector(gsldata,offset,n);
//  	}

//  Function: gsl_vector_float gsl_vector_float_subvector_with_stride (gsl_vector_float *v, size_t offset, size_t stride, size_t n)
//  Function: gsl_vector_float_const_view gsl_vector_float_const_subvector_with_stride (const gsl_vector_float * v, size_t offset, size_t stride, size_t n)
//      These functions return a vector view of a subvector of another vector v with an additional stride argument. The subvector is formed in the same way as for
//      gsl_vector_float_subvector but the new vector has n elements with a step-size of stride from one element to the next in the original vector. Mathematically,
//      the i-th element of the new vector v' is given by,

//      v'(i) = v->data[(offset + i*stride)*v->stride]

//      where the index i runs from 0 to n-1.

//      Note that subvector views give direct access to the underlying elements of the original vector. For example, the following code will zero the even elements of the
//      vector v of length n, while leaving the odd elements untouched,

//      gsl_vector_float_view v_even = gsl_vector_float_subvector_with_stride (v, 0, 2, n/2);
//      gsl_vector_float_set_zero (&v_even.vector);

//      A vector view can be passed to any subroutine which takes a vector argument just as a directly allocated vector would be, using &view.vector. For example, the
//      following code computes the norm of odd elements of v using the BLAS routine DNRM2,

//      gsl_vector_float_view v_odd = gsl_vector_float_subvector_with_stride (v, 1, 2, n/2);
//      double r = gsl_blas_dnrm2 (&v_odd.vector);

//      The function gsl_vector_float_const_subvector_with_stride is equivalent to gsl_vector_float_subvector_with_stride but can be used for
//      vectors which are declared const.

//  Function: gsl_vector_float_view gsl_vector_float_complex_real (gsl_vector_float_complex *v)
//  Function: gsl_vector_float_const_view gsl_vector_float_complex_const_real (const gsl_vector_float_complex *v)
//      These functions return a vector view of the real parts of the complex vector v.

//      The function gsl_vector_float_complex_const_real is equivalent to gsl_vector_float_complex_real but can be used for vectors which are declared
//      const.

//  Function: gsl_vector_float_view gsl_vector_float_complex_imag (gsl_vector_float_complex *v)
//  Function: gsl_vector_float_const_view gsl_vector_float_complex_const_imag (const gsl_vector_float_complex *v)
//      These functions return a vector view of the imaginary parts of the complex vector v.

//      The function gsl_vector_float_complex_const_imag is equivalent to gsl_vector_float_complex_imag but can be used for vectors which are declared
//      const.

//  Function: gsl_vector_float_view gsl_vector_float_view_array (double *base, size_t n)
//  Function: gsl_vector_float_const_view gsl_vector_float_const_view_array (const double *base, size_t n)
//      These functions return a vector view of an array. The start of the new vector is given by base and has n elements. Mathematically, the i-th element of the new
//      vector v' is given by,

//      v'(i) = base[i]

//      where the index i runs from 0 to n-1.

//      The array containing the elements of v is not owned by the new vector view. When the view goes out of scope the original array will continue to exist. The
//      original memory can only be deallocated by freeing the original pointer base. Of course, the original array should not be deallocated while the view is still in use.

//      The function gsl_vector_float_const_view_array is equivalent to gsl_vector_float_view_array but can be used for vectors which are declared const.

//  Function: gsl_vector_float_view gsl_vector_float_view_array_with_stride (double * base, size_t stride, size_t n)
//  Function: gsl_vector_float_const_view gsl_vector_float_const_view_array_with_stride (const double * base, size_t stride, size_t n)
//      These functions return a vector view of an array base with an additional stride argument. The subvector is formed in the same way as for
//      gsl_vector_float_view_array but the new vector has n elements with a step-size of stride from one element to the next in the original array. Mathematically,
//      the i-th element of the new vector v' is given by,

//      v'(i) = base[i*stride]

//      where the index i runs from 0 to n-1.

//      Note that the view gives direct access to the underlying elements of the original array. A vector view can be passed to any subroutine which takes a vector
//      argument just as a directly allocated vector would be, using &view.vector.

//      The function gsl_vector_float_const_view_array_with_stride is equivalent to gsl_vector_float_view_array_with_stride but can be used for
//      arrays which are declared const.

//  ************* Copying vectors

//  Common operations on vectors such as addition and multiplication are available in the BLAS part of the library (see section BLAS Support). However, it is useful to have a small number of utility functions which do not require the full BLAS code. The following functions fall into this category.

//      This function copies the elements of the vector src into the vector dest.
	vector_float& operator=(const vector_float& other){copy(other);return (*this);}

//  Function: int gsl_vector_float_swap (gsl_vector_float * v, gsl_vector_float * w)
//      This function exchanges the elements of the vectors v and w by copying. The two vectors must have the same length.

//  ***** Exchanging elements

//  The following function can be used to exchange, or permute, the elements of a vector.

//  Function: int gsl_vector_float_swap_elements (gsl_vector_float * v, size_t i, size_t j)
//      This function exchanges the i-th and j-th elements of the vector v in-place.
	int swap_elements (size_t i, size_t j) {return gsl_vector_float_swap_elements (gsldata, i,j);}

//  Function: int gsl_vector_float_reverse (gsl_vector_float * v)
//      This function reverses the order of the elements of the vector v.
	int reverse () {return  gsl_vector_float_reverse (gsldata) ;}

// ******* Vector operations

//  The following operations are only defined for real vectors.

//      This function adds the elements of vector b to the elements of vector a, a'_i = a_i + b_i. The two vectors must have the same length.
	int operator+=(const vector_float &other) {return gsl_vector_float_add (gsldata, other.gsldata);}

//      This function subtracts the elements of vector b from the elements of vector a, a'_i = a_i - b_i. The two vectors must have the same length.
	int operator-=(const vector_float &other) {return gsl_vector_float_sub (gsldata, other.gsldata);}

//  Function: int gsl_vector_float_mul (gsl_vector_float * a, const gsl_vector_float * b)
//      This function multiplies the elements of vector a by the elements of vector b, a'_i = a_i * b_i. The two vectors must have the same length.
	int operator*=(const vector_float &other) {return gsl_vector_float_mul (gsldata, other.gsldata);}

//      This function divides the elements of vector a by the elements of vector b, a'_i = a_i / b_i. The two vectors must have the same length.
	int operator/=(const vector_float &other) {return gsl_vector_float_div (gsldata, other.gsldata);}

//      This function multiplies the elements of vector a by the constant factor x, a'_i = x a_i.
	int operator*=(float x) {return gsl_vector_float_scale (gsldata, x);}

//  Function: int gsl_vector_float_add_constant (gsl_vector_float * a, const double x)
//      This function adds the constant value x to the elements of the vector a, a'_i = a_i + x.
	int operator+=(float x) {return gsl_vector_float_add_constant (gsldata,x);}

//      This function multiplies the elements of vector a by the constant factor x, a'_i = x a_i.
	int operator/=(float x) {return gsl_vector_float_scale (gsldata, 1/x);}

// bool operators:
	bool operator==(const vector_float& other) const;
	bool operator!=(const vector_float& other) const { return (!((*this)==other));}

// stream output:
//	friend ostream& operator<< ( ostream& os, const vector_float& vect );
	/** returns sum of all the vector elements. */
    float sum() const;
	// returns sqrt(v.t*v);
    double norm2() const;

// **** Finding maximum and minimum elements of vectors

//      This function returns the maximum value in the vector v.
    double max() const{return gsl_vector_float_max (gsldata) ;}

//  Function: double gsl_vector_float_min (const gsl_vector_float * v)
//      This function returns the minimum value in the vector v.
    double min() const{return gsl_vector_float_min (gsldata) ;}

//  Function: void gsl_vector_float_minmax (const gsl_vector_float * v, double * min_out, double * max_out)
//      This function returns the minimum and maximum values in the vector v, storing them in min_out and max_out.

//      This function returns the index of the maximum value in the vector v. When there are several equal maximum elements then the lowest index is returned.
	size_t max_index(){return gsl_vector_float_max_index (gsldata);}

//  Function: size_t gsl_vector_float_min_index (const gsl_vector_float * v)
//      This function returns the index of the minimum value in the vector v. When there are several equal minimum elements then the lowest index is returned.
	size_t min_index(){return gsl_vector_float_min_index (gsldata);}

//  Function: void gsl_vector_float_minmax_index (const gsl_vector_float * v, size_t * imin, size_t * imax)
//      This function returns the indices of the minimum and maximum values in the vector v, storing them in imin and imax. When there are several equal minimum
//      or maximum elements then the lowest indices are returned.

//  Vector properties

//  Function: int gsl_vector_float_isnull (const gsl_vector_float * v)
//      This function returns 1 if all the elements of the vector v are zero, and 0 otherwise. };
	bool isnull(){return gsl_vector_float_isnull (gsldata);}
};

// When you add create a view it will stick to its with the view until you call change_view
// ex:
// matrix_float m(5,5);
// vector_float v(5);
// // ...
// m.column(3) = v; //the 3rd column of the matrix m will equal v.
class vector_float_view : public vector_float
{
 public:
	vector_float_view(const vector_float&     other) :vector_float(){init(other);}
	vector_float_view(const vector_float_view& other):vector_float(){init(other);}
	vector_float_view(const gsl_vector_float& gsl_other) : vector_float() {init_with_gsl_vector(gsl_other);}

	void init(const vector_float& other);
	void init_with_gsl_vector(const gsl_vector_float& gsl_other);
	void change_view(const vector_float& other){init(other);}
 private:
};

ostream& operator<< ( ostream& os, const vector_float & vect );

// vector_type<>::type is a template interface to vector_?
// it is usefull for in templated situations for getting the correct vector type
#define tmp_type_is_float
#ifdef tmp_type_is
typedef vector vector_double;
template<class T>
struct vector_type  {typedef vector_double   type;};

template<class T>
struct value_type  {typedef double   type;};

#else
template<> struct vector_type<float> {typedef vector_float type;};
#endif
#undef tmp_type_is_float

}
#endif// _vector_float_h


#pragma once

#include <memory>
#include <halley/maths/colour.h>
#include <halley/maths/vector2.h>
#include "halley/maths/rect.h"
#include "halley/data_structures/maybe.h"
#include <gsl/span>
#include <map>
#include "halley/core/graphics/sprite/sprite.h"
#include "halley/core/graphics/text/font.h"

namespace Halley
{
	class LocalisedString;
	class Painter;
	class Material;

	using ColourOverride = std::pair<size_t, std::optional<Colour4f>>;

	class TextRenderer
	{
	public:
		using SpriteFilter = std::function<void(gsl::span<Sprite>)>;

		TextRenderer();
		explicit TextRenderer(std::shared_ptr<const Font> font, String text = "", float size = 20, Colour colour = Colour(1, 1, 1, 1), float outline = 0, Colour outlineColour = Colour(0, 0, 0, 1));

		TextRenderer& setPosition(Vector2f pos);
		TextRenderer& setFont(std::shared_ptr<const Font> font);
		TextRenderer& setText(const String& text);
		TextRenderer& setText(const StringUTF32& text);
		TextRenderer& setText(const LocalisedString& text);
		TextRenderer& setSize(float size);
		TextRenderer& setColour(Colour colour);
		TextRenderer& setOutlineColour(Colour colour);
		TextRenderer& setOutline(float width);
		TextRenderer& setAlignment(float align);
		TextRenderer& setOffset(Vector2f align);
		TextRenderer& setClip(Rect4f clip);
		TextRenderer& setClip();
		TextRenderer& setSmoothness(float smoothness);
		TextRenderer& setPixelOffset(Vector2f offset);
		TextRenderer& setColourOverride(const std::vector<ColourOverride>& colOverride);
		TextRenderer& setLineSpacing(float spacing);

		TextRenderer clone() const;

		void generateSprites(std::vector<Sprite>& sprites) const;
		void draw(Painter& painter, const std::optional<Rect4f>& extClip = {}) const;

		void setSpriteFilter(SpriteFilter f);

		Vector2f getExtents() const;
		Vector2f getExtents(const StringUTF32& str) const;
		Vector2f getCharacterPosition(size_t character) const;
		Vector2f getCharacterPosition(size_t character, const StringUTF32& str) const;
		size_t getCharacterAt(const Vector2f& position) const;
		size_t getCharacterAt(const Vector2f& position, const StringUTF32& str) const;

		StringUTF32 split(const String& str, float width) const;
		StringUTF32 split(const StringUTF32& str, float width, std::function<bool(int32_t)> filter = {}) const;
		StringUTF32 split(float width) const;

		Vector2f getPosition() const;
		String getText() const;
		const StringUTF32& getTextUTF32() const;
		Colour getColour() const;
		float getOutline() const;
		Colour getOutlineColour() const;
		float getSmoothness() const;
		std::optional<Rect4f> getClip() const;
		float getLineHeight() const;
		float getAlignment() const;

		bool empty() const;

	private:
		std::shared_ptr<const Font> font;
		mutable std::map<const Font*, std::shared_ptr<Material>> materials;
		StringUTF32 text;
		SpriteFilter spriteFilter;

		float size = 20;
		float outline = 0;
		float align = 0;
		float smoothness = 1.0f;
		float lineSpacing = 0.0f;

		Vector2f position;
		Vector2f offset;
		Vector2f pixelOffset;
		Colour colour;
		Colour outlineColour;
		std::optional<Rect4f> clip;

		std::vector<ColourOverride> colourOverrides;

		mutable Vector<Sprite> spritesCache;
		mutable bool materialDirty = true;
		mutable bool glyphsDirty = true;
		mutable bool positionDirty = true;

		std::shared_ptr<Material> getMaterial(const Font& font) const;
		void updateMaterial(Material& material, const Font& font) const;
		void updateMaterialForFont(const Font& font) const;
		void updateMaterials() const;
		float getScale(const Font& font) const;
	};

	class ColourStringBuilder {
	public:
		void append(std::string_view text, std::optional<Colour4f> col = {});

		std::pair<String, std::vector<ColourOverride>> moveResults();

	private:
		std::vector<String> strings;
		std::vector<ColourOverride> colours;
		size_t len = 0;
	};
}


#ifndef BATCH_EXTRACTOR_H_IVH3CLLQ
#define BATCH_EXTRACTOR_H_IVH3CLLQ

#include <gsl/gsl>
#include <optional>
#include <sens_loc/util/correctness_util.h>
#include <string_view>

namespace sens_loc::apps {

/// \ingroup feature-plotter-driver
/// Defines a strongly typed switch for the color to use. Will be mapped
/// to the actual OpenCV-color using \c color_to_bgr.
enum class feature_color {
    green,
    blue,
    red,
    orange,
    purple,  ///< Nice purple.
    all      ///< Draws all keypoints with different colors.
};

/// Convert a color name to the corresponding \c feature_color.
/// The string must match with the enum-value, e.g. "green".
/// \ingroup feature-plotter-driver
inline feature_color str_to_color(std::string_view color_string) noexcept {

#define COLOR_SWITCH(COLOR)                                                    \
    if (color_string == #COLOR)                                                \
        return feature_color::COLOR;
    COLOR_SWITCH(all)
    COLOR_SWITCH(green)
    COLOR_SWITCH(blue)
    COLOR_SWITCH(red)
    COLOR_SWITCH(purple)
    COLOR_SWITCH(orange)

    UNREACHABLE("Unexpected color to convert");  // LCOV_EXCL_LINE
}

/// Provide a conversion from the \¢ feature_color to actual OpenCV colors.
/// \ingroup feature-plotter-driver
struct color_to_bgr {
    // Color Space in BGR.
    static cv::Scalar convert(feature_color c) {
        using cv::Scalar;
        switch (c) {
        case feature_color::all: return Scalar::all(-1);
        case feature_color::green: return Scalar(5, 117, 65);
        case feature_color::blue: return Scalar(226, 144, 74);
        case feature_color::red: return Scalar(27, 2, 208);
        case feature_color::purple: return Scalar(254, 19, 144);
        case feature_color::orange: return Scalar(35, 166, 245);
        }
        UNREACHABLE("Invalid enum-value!");  // LCOV_EXCL_LINE
    }
};

/// Helper class that visits a list of images plots keypoints onto them.
/// \ingroup feature-plotter-driver
class batch_plotter {
  public:
    batch_plotter(std::string_view                feature_file_pattern,
                  std::string_view                output_file_pattern,
                  feature_color                   color,
                  std::optional<std::string_view> target_image_file_pattern)
        : _feature_file_pattern{feature_file_pattern}
        , _ouput_file_pattern{output_file_pattern}
        , _color{color}
        , _target_image_file_pattern{target_image_file_pattern} {
        Expects(!_feature_file_pattern.empty());
        Expects(!_ouput_file_pattern.empty());
        if (_target_image_file_pattern)
            Expects(!_target_image_file_pattern->empty());
    }

    /// Process a whole batch of files in the range [start, end].
    [[nodiscard]] bool process_batch(int start, int end) const noexcept;

  private:
    /// Process a single feature file. Called in parallel from \c process_batch.
    [[nodiscard]] bool process_index(int idx) const noexcept;

    /// The feature-detector creates files with the keypoints. This file-pattern
    /// needs to be provided in order to plot those keypoints.
    std::string_view _feature_file_pattern;

    /// File pattern for the output image to be written to.
    /// These images are 8-bit RGB images!
    std::string_view _ouput_file_pattern;

    /// Color to draw the keypoints in.
    feature_color _color;

    /// Even though the feature-files should have a path to the original image,
    /// the features were detected on, this path might not be the desired target
    /// for plotting. This is the case for plotting multiple feature keypoints
    /// or if the path to the file is incorrect.
    std::optional<std::string_view> _target_image_file_pattern;
};
}  // namespace sens_loc::apps

#endif /* end of include guard: BATCH_EXTRACTOR_H_IVH3CLLQ */


#ifndef OPENMC_TALLIES_FILTER_SURFACE_H
#define OPENMC_TALLIES_FILTER_SURFACE_H

#include <cstdint>
#include <unordered_map>

#include <gsl/gsl>

#include "openmc/tallies/filter.h"
#include "openmc/vector.h"

namespace openmc {

//==============================================================================
//! Specifies which surface particles are crossing
//==============================================================================

class SurfaceFilter : public Filter {
public:
  //----------------------------------------------------------------------------
  // Constructors, destructors

  ~SurfaceFilter() = default;

  //----------------------------------------------------------------------------
  // Methods

  std::string type() const override { return "surface"; }

  void from_xml(pugi::xml_node node) override;

  void get_all_bins(const Particle& p, TallyEstimator estimator,
    FilterMatch& match) const override;

  void to_statepoint(hid_t filter_group) const override;

  std::string text_label(int bin) const override;

  //----------------------------------------------------------------------------
  // Accessors

  void set_surfaces(gsl::span<int32_t> surfaces);

private:
  //----------------------------------------------------------------------------
  // Data members

  //! The indices of the surfaces binned by this filter.
  vector<int32_t> surfaces_;

  //! A map from surface indices to filter bin indices.
  std::unordered_map<int32_t, int> map_;
};

} // namespace openmc
#endif // OPENMC_TALLIES_FILTER_SURFACE_H


#include <stdlib.h>
#include <gsl/block/gsl_block.h>

#define BASE_DOUBLE
#include <gsl/templates_on.h>
#include <gsl/block/init_source.c>
#include <gsl/templates_off.h>
#undef BASE_DOUBLE


/**
* Copyright 2017 BitTorrent Inc.
*
* 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.
*/
#pragma once

#include <okui/config.h>

#include <okui/opengl/Framebuffer.h>
#include <okui/shaders/ColorShader.h>
#include <okui/shaders/DistanceFieldShader.h>
#include <okui/shaders/TextureShader.h>
#include <okui/Application.h>
#include <okui/Color.h>
#include <okui/Point.h>
#include <okui/Rectangle.h>
#include <okui/RenderTarget.h>
#include <okui/Relation.h>
#include <okui/Responder.h>
#include <okui/ShaderCache.h>
#include <okui/TextureHandle.h>
#include <okui/TouchpadFocus.h>
#include <okui/WeakTexture.h>

#include <scraps/AbstractTaskScheduler.h>
#include <scraps/TreeNode.h>
#include <scraps/utility.h>

#include <stdts/optional.h>

#include <gsl.h>

#include <list>
#include <typeindex>
#include <unordered_map>

namespace okui {

class Application;
class BitmapFont;
class Window;

/**
* View rendering can be cached or buffered to a texture. One reason this may be done is to apply post-rendering
* effects such as tinting or reflection. When this is done, the contents of the view are clipped to its bounds.
*/
class View : public Responder, private scraps::TreeNode<View> {
public:
    using Relation = okui::Relation;

    View() = default;
    explicit View(std::string name) : _name{std::move(name)} {}
    View(const View&) = delete;
    View(View&&) = delete;
    View& operator=(const View&) = delete;
    View& operator=(View&&) = delete;

    /**
    * It is an error to destroy a focused view. Remove the view first if needed.
    */
    virtual ~View();

    std::string name() const       { return _name.empty() ? scraps::Demangle(typeid(*this).name()) : _name; }
    void setName(std::string name) { _name = std::move(name); }

    void addSubview(View* view);
    template <typename... Views>
    void addSubviews(View* view, Views&&... views)  { _addSubviews(view, std::forward<Views>(views)...); }
    void addHiddenSubview(View* view);
    void removeSubview(View* view);
    template <typename... Views>
    void removeSubviews(View* view, Views&&... views) { _removeSubviews(view, std::forward<Views>(views)...); }
    void removeSubviews();

    Window* window() const                    { return _window; }
    Application* application() const;

    const View* superview() const             { return parent(); }
    View* superview()                         { return parent(); }
    const std::list<View*>& subviews() const  { return children(); }

    const Rectangle<double>& bounds() const   { return _bounds; }
    math::Vector<double, 2> size() const      { return _bounds.size(); }
    Point<double> position() const            { return _bounds.position(); }

    double width() const                      { return _bounds.width; }
    double height() const                     { return _bounds.height; }

    template <typename... Args>
    void setBounds(Args&&... args)            { _setBounds(Rectangle<double>(std::forward<Args>(args)...)); }

    void setPosition(double x, double y)      { _setBounds({x, y, _bounds.width, _bounds.height}); }
    void setPosition(const Point<double>& p)  { setPosition(p.x, p.y); }

    void setSize(double width, double height) { _setBounds({_bounds.x, _bounds.y, width, height}); }
    void setSize(const math::Vector<double, 2>& s) { setSize(s.x, s.y); }

    Rectangle<double> windowBounds() const;

    /**
    * Sets bounds as a percent of superview bounds (0-1)
    */
    void setBoundsRelative(double x, double y, double width, double height);

    void setInterceptsInteractions(bool intercepts);
    void setInterceptsInteractions(bool intercepts, bool childrenIntercept);
    void setChildrenInterceptInteractions(bool childrenIntercept);

    ShaderCache* shaderCache();

    void setIsVisible(bool isVisible = true);
    bool isVisible() const { return _isVisible; }

    void show() { setIsVisible(); }
    void hide() { setIsVisible(false); }

    /**
    * Allows scaling of the view by a particular factor.
    */
    void setScale(double scale) { setScale(scale, scale); }
    void setScale(double scaleX, double scaleY);

    /**
    * Sets the view's background color.
    */
    void setBackgroundColor(const Color& color) { _backgroundColor = color; }
    const Color& backgroundColor() const        { return _backgroundColor; }

    /**
    * Sets the view's tint. If this is anything but opaque white, this is a post-rendering effect that
    * clips the view's contents.
    */
    void setTintColor(const Color& color);
    const Color& tintColor() const        { return _tintColor; }

    /**
    * Sets the view's opacity. If this is anything but 1, this is a post-rendering effect that
    * clips the view's contents.
    *
    * This effectively sets the alpha component of the view's tint color.
    */
    void setOpacity(double opacity)  { setTintColor(_tintColor.withAlphaF(opacity)); }
    double opacity() const           { return _tintColor.alphaF(); }

    /**
    * Returns true if the view's ancestors are visible or if the view has no ancestors.
    */
    bool ancestorsAreVisible() const;

    /**
    * Returns true if the view and its ancestors are visible and in an open window.
    */
    bool isVisibleInOpenWindow() const;

    /**
    * Arranges the view so it's behind all of its current siblings.
    */
    void sendToBack();

    /**
    * Arranges the view so it's in front of all of its current siblings.
    */
    void bringToFront();

    /**
    * Override this if the view can become focused.
    */
    virtual bool canBecomeDirectFocus() { return false; }

    /**
    * Makes the view the current focus. If the view has a preferred focus, the preferred focus will
    * become the focus instead.
    */
    void focus();

    /**
    * Returns the view that would become focused if an attempt to give focus to this view is made.
    */
    View* expectedFocus();

    /**
    * Sets the focus to the next ancestor that can be focused which doesn't result in this view
    * retaining focus (which would otherwise happen if your ancestor's preferred focus was you)
    */
    void focusAncestor();

    /**
    * If the view or any of its children are focused, unfocuses them.
    */
    void unfocus();

    /**
    * If this view would receive focus and has a preferred focus, the preferred focus will become focus instead.
    */
    View* preferredFocus() const       { return _preferredFocus; }
    void setPreferredFocus(View* view) { _preferredFocus = view; }

    View* nextFocus() const     { return _nextFocus; }
    View* previousFocus() const { return _previousFocus; }

    /**
    * If the view receives an unhandled tab key down, focus will change to the given
    * view (and shift+tab will do the opposite).
    */
    void setNextFocus(View* view);

    /**
    * Returns the next available visible and focusable view if there is one.
    */
    View* nextAvailableFocus();

    /**
    * Returns the previous available visible and focusable view.
    */
    View* previousAvailableFocus();

    /**
    * Returns true if the view or any of its children has focus.
    */
    bool isFocus() const;

    TouchpadFocus& touchpadFocus() { return _touchpadFocus; }

    /**
    * @param rendersToTexture if true, the view is rendered to a texture, making it available via renderTexture
    */
    void setRendersToTexture(bool rendersToTexture = true) { _rendersToTexture = rendersToTexture; }

    /**
    * If the view is set to render to a texture, this can be used to obtain said texture.
    */
    std::shared_ptr<TextureInterface> renderTexture() const;

    /**
    * @param caches if true, the view will render to a texture and the render() method will only be called when
    *               the cache is invalid
    */
    void setCachesRender(bool cachesRender = true) { _cachesRender = cachesRender; }

    /**
    * Invalidates the view's render cache.
    */
    void invalidateRenderCache();

    /**
    * @param clipsToBounds if true, the view will not render itself or any subviews outside of its bounds
    */
    void setClipsToBounds(bool clipsToBounds = true) { _clipsToBounds = clipsToBounds; }

    /**
    * @return if true, the view will not render itself or any subviews outside of its bounds
    */
    bool clipsToBounds() const { return _clipsToBounds; }

    /**
    * Returns true if the mouse is hovering directly over this view.
    */
    bool hasMouse() const;

    shaders::ColorShader* colorShader() { return shader<shaders::ColorShader>("color shader"); }
    shaders::TextureShader* textureShader() { return shader<shaders::TextureShader>("texture shader"); }
    shaders::DistanceFieldShader* distanceFieldShader() { return shader<shaders::DistanceFieldShader>("distance field shader"); }

    /**
    * Begins loading a texture associated with the view. When the texture is loaded, the view's
    * render cache will be invalidated. If the texture should not be associated with the view,
    * use Window::loadTexture* instead.
    */
    TextureHandle loadTextureResource(const std::string& name);
    TextureHandle loadTextureFromMemory(std::shared_ptr<const std::string> data);
    TextureHandle loadTextureFromURL(const std::string& url);

    /**
    * Get or create a shader cached via the window's shader cache.
    */
    template <typename T>
    T* shader(const char* identifier);

    const AffineTransformation& renderTransformation() const { return _renderTransformation; }

    /**
    * Converts a point from local coordinates to superview coordinates.
    */
    Point<double> localToSuperview(double x, double y) const { return localToAncestor(x, y, superview()); }
    Point<double> localToSuperview(const Point<double>& p) const { return localToSuperview(p.x, p.y); }

    /**
    * Converts a point from local coordinates to the coordinates of an ancestor.
    */
    Point<double> localToAncestor(double x, double y, const View* ancestor) const;
    Point<double> localToAncestor(const Point<double>& p, const View* ancestor) const { return localToAncestor(p.x, p.y, ancestor); }

    /**
    * Converts a point from super coordinates to local coordinates.
    */
    Point<double> superviewToLocal(double x, double y) const;
    Point<double> superviewToLocal(const Point<double>& p) const;

    /**
    * Converts a point from local coordinates to window coordinates.
    */
    Point<double> localToWindow(double x, double y) const;
    Point<double> localToWindow(const Point<double>& p) const;

    /**
    * Returns true if this view has the given relation to the given view.
    *
    * For example, hasRelation(kDescendant, superview()) should return true.
    */
    bool hasRelation(Relation relation, const View* view) const;

    /**
    * Returns the first view that both views have in their hierarchy, if any.
    */
    const View* commonView(const View* other) const { return commonNode(other); }

    using TreeNode::isDescendantOf;
    using TreeNode::isAncestorOf;

    /**
    * Posts a message to listeners with the given relation. The view and its potential listeners must have an
    * associated application for the message to be delivered.
    *
    * For example, post(message, Relation::kAncestor) posts the message to listeners that are ancestors of this view.
    */
    template <typename T>
    void post(T& message, Relation relation = Relation::kHierarchy) {
        _post(std::type_index(typeid(typename std::decay_t<T>)), &message, relation);
    }
    template <typename T>
    void post(T&& message, Relation relation = Relation::kHierarchy) {
        T m = std::move(message);
        _post(std::type_index(typeid(typename std::decay_t<T>)), &m, relation);
    }

    template <typename T>
    struct ListenerAction : ListenerAction<decltype(&T::operator())> {};

    template <typename C, typename R, typename... Args>
    struct ListenerAction<R(C::*)(Args...) const> {
        using ArgumentTuple = std::tuple<Args...>;
        using ArgumentCount = std::tuple_size<ArgumentTuple>;
        using MessageType = typename std::decay<typename std::tuple_element<0, ArgumentTuple>::type>::type;
    };

    /**
    * Listens for messages from senders with the given relation.
    *
    * For example, listen([](const Message& message) {}, Relation::kAncestor) listens for messages from posters that
    * are ancestors of this view.
    *
    * @param action an action that takes a constant reference to the message type to listen for and optionally a View pointer to the sender
    */
    template <typename Action>
    auto listen(Action&& action, Relation relation = Relation::kHierarchy) -> typename std::enable_if<ListenerAction<Action>::ArgumentCount::value == 1, void>::type {
        using MessageType = typename ListenerAction<Action>::MessageType;
        _listen(std::type_index(typeid(MessageType)),
            [action = std::forward<Action>(action)](const void* message, View* sender) {
                action(*reinterpret_cast<const MessageType*>(message));
            }, relation
        );
    }

    template <typename Action>
    auto listen(Action&& action, Relation relation = Relation::kHierarchy) -> typename std::enable_if<ListenerAction<Action>::ArgumentCount::value == 2, void>::type {
        using MessageType = typename ListenerAction<Action>::MessageType;
        _listen(std::type_index(typeid(MessageType)),
            [action = std::forward<Action>(action)](const void* message, View* sender) {
                action(*reinterpret_cast<const MessageType*>(message), sender);
            }, relation
        );
    }

    /**
    * Makes the given object available via get(). This can be used to store arbitrary state with the view.
    *
    * @param relation the object will only be available to views of the given relation
    */
    template <typename T>
    auto set(T&& object, Relation relation = Relation::kHierarchy) {
        _provisions.emplace_front(std::forward<T>(object), relation);
        return stdts::any_cast<std::decay_t<T>>(&_provisions.front().object);
    }

    /**
    * Finds an object provided via provide. It will return a pointer to the first object it finds of the
    * specified type. If more than one objects of the given type has been provided, it is undefined
    * which one will be returned.
    *
    * @param relation only objects from views of the given relation will be returned
    */
    template <typename T>
    T* find(Relation relation = Relation::kHierarchy);

    template <typename T>
    T* get() { return find<T>(Relation::kSelf); }

    template <typename T>
    T* inherit() { return find<T>(Relation::kAncestor); }

    /**
    * Asynchronously schedules a function to be invoked using the application's task scheduler.
    *
    * If the view is destroyed, the invocation will be canceled.
    */
    template <typename... Args>
    auto async(Args&&... args) -> decltype(std::declval<scraps::AbstractTaskScheduler>().async(std::forward<Args>(args)...)) {
        return _taskScheduler()->async(_taskScope, std::forward<Args>(args)...);
    }

    /**
    * Asynchronously schedules a function to be invoked after a delay using the application's task scheduler.
    *
    * If the view is destroyed, the invocation will be canceled.
    */
    template <typename... Args>
    auto asyncAfter(Args&&... args) -> decltype(std::declval<scraps::AbstractTaskScheduler>().asyncAfter(std::forward<Args>(args)...)) {
        return _taskScheduler()->asyncAfter(_taskScope, std::forward<Args>(args)...);
    }

    /**
    * Asynchronously schedules a function to be invoked at a time using the application's task scheduler.
    *
    * If the view is destroyed, the invocation will be canceled.
    */
    template <typename... Args>
    auto asyncAt(Args&&... args) -> decltype(std::declval<scraps::AbstractTaskScheduler>().asyncAt(std::forward<Args>(args)...)) {
        return _taskScheduler()->asyncAt(_taskScope, std::forward<Args>(args)...);
    }

    /**
    * The hook provided here will be called before rendering each frame.
    */
    void addUpdateHook(const std::string& handle, std::function<void()> hook);

    /**
    * The hook provided here will no longer be called.
    */
    void removeUpdateHook(const std::string& handle);

    /**
    * Override this to do drawing.
    */
    virtual void render() {}

    virtual void render(const RenderTarget* renderTarget, const Rectangle<int>& area) { render(); }

    /**
    * Override this to implement custom post-render effects. For this method to be called, the view must be
    * set to render to texture. The default implementation provides the built-in effects such as tint and
    * opacity. If this is overridden, you will need to provide those effects in your implementation in
    * order to use them.
    *
    * @param texture the view, rendered to a texture with premultiplied alpha
    */
    virtual void postRender(std::shared_ptr<TextureInterface> texture, const AffineTransformation& transformation);

    /**
    * Override this to lay out subviews whenever the view is resized.
    */
    virtual void layout() {}

    /**
    * Override this to do any sort of setup that requires the view to be attached to a window.
    */
    virtual void windowChanged() {}

    /**
    * Override this if you want odd-shaped views to have accurate hit boxes.
    */
    virtual bool hitTest(double x, double y);
    bool hitTest(const Point<double>& p) { return hitTest(p.x, p.y); }

    /**
    * Return the most descendant visible view which intersects with (x, y)
    */
    View* hitTestView(double x, double y);
    View* hitTestView(const Point<double>& p) { return hitTestView(p.x, p.y); }

    /**
    * Override these to handle mouse events. Call the base implementation to pass on the event.
    */
    virtual void mouseDown(MouseButton button, double x, double y);
    virtual void mouseUp(MouseButton button, double startX, double startY, double x, double y);
    virtual void mouseWheel(double xPos, double yPos, int xWheel, int yWheel);
    virtual void mouseDrag(double startX, double startY, double x, double y);
    virtual void mouseMovement(double x, double y);
    virtual void mouseEnter() {}
    virtual void mouseExit() {}

    /**
    * Called whenever the view or one of its subviews gains focus.
    */
    virtual void focusGained() {}

    /**
    * Called whenever the view and its subviews lose focus.
    */
    virtual void focusLost() {}

    /**
    * Called whenever the view or any subview gains or loses focus.
    */
    virtual void focusChanged() {}

    /**
    * Called before the view and all of its ancestors become visible in the window.
    */
    virtual void willAppear() {}

    /**
    * Called when the view and all of its ancestors become visible in the window.
    */
    virtual void appeared() {}

    /**
    * Called before the view or one of its ancestors become invisible in the window.
    */
    virtual void willDisappear() {}

    /**
    * Called when the view or one of its ancestors become invisible in the window.
    */
    virtual void disappeared() {}

    /**
    * Renders the view and its subviews.
    *
    * @param area the area within the target to render to. the view will fill this area
    * @param clipBounds the bounds within the target to clip rendering of the view and its children to
    */
    void renderAndRenderSubviews(const RenderTarget* target, const Rectangle<int>& area, stdts::optional<Rectangle<int>> clipBounds = stdts::nullopt);

    bool dispatchMouseDown(MouseButton button, double x, double y);
    bool dispatchMouseUp(MouseButton button, double startX, double startY, double x, double y);
    bool dispatchMouseMovement(double x, double y);
    bool dispatchMouseWheel(double xPos, double yPos, int xWheel, int yWheel);
    void dispatchUpdate(std::chrono::high_resolution_clock::duration elapsed);

    // Responder overrides
    virtual Responder* nextResponder() override;
    virtual void keyDown(KeyCode key, KeyModifiers mod, bool repeat) override;
    virtual void touchUp(size_t finger, Point<double> position, double pressure) override;
    virtual void touchDown(size_t finger, Point<double> position, double pressure) override;
    virtual void touchMovement(size_t finger, Point<double> position, Point<double> distance, double pressure) override;

private:
    friend class scraps::TreeNode<View>;
    friend class Window;

    struct Listener {
        Listener(std::type_index index, std::function<void(const void*, View*)> action, Relation relation)
            : index{index}, action{std::move(action)}, relation{relation} {}

        std::type_index index;
        std::function<void(const void*, View*)> action;
        Relation relation;
    };

    struct Provision {
        Provision(stdts::any object, Relation relation)
            : object{std::move(object)}, relation{relation} {}

        stdts::any object;
        Relation relation;
    };

    void _addSubviews() {}
    template <typename... Views>
    void _addSubviews(View* view, Views&&... views);

    void _removeSubviews() {}
    template <typename... Views>
    void _removeSubviews(View* view, Views&&... views);

    void _setBounds(const Rectangle<double>& bounds);

    void _invalidateSuperviewRenderCache();

    void _dispatchFutureVisibilityChange(bool visible);
    void _dispatchVisibilityChange(bool visible);
    void _dispatchWindowChange(Window* window);
    void _mouseExit();

    void _updateFocusableRegions(std::vector<std::tuple<View*, Rectangle<double>>>& regions);

    bool _requiresTextureRendering();
    void _renderAndRenderSubviews(const RenderTarget* target, const Rectangle<int>& area, bool shouldClear = false, stdts::optional<Rectangle<int>> clipBounds = stdts::nullopt);

    void _post(std::type_index index, const void* ptr, Relation relation);
    void _listen(std::type_index index, std::function<void(const void*, View*)> action, Relation relation);

    template <typename F>
    void _traverseRelation(Relation relation, F&& function);

    std::vector<View*> _topViewsForRelation(Relation relation);

    scraps::AbstractTaskScheduler* _taskScheduler() const;
    void _updateTouchFocus(std::chrono::high_resolution_clock::duration elapsed);

    void _checkUpdateSubscription();
    bool _shouldSubscribeToUpdates();

    std::string _name;
    bool _isVisible                     = true;
    bool _rendersToTexture              = false;
    bool _cachesRender                  = false;
    bool _hasCachedRender               = false;
    bool _clipsToBounds                 = true;
    bool _interceptsInteractions        = true;
    bool _childrenInterceptInteractions = true;

    Window* _window                     = nullptr;
    View*   _subviewWithMouse           = nullptr;
    View*   _nextFocus                  = nullptr;
    View*   _previousFocus              = nullptr;
    View*   _preferredFocus             = nullptr;

    Rectangle<double>    _bounds;
    Point<double>        _scale{1.0, 1.0};
    Color                _backgroundColor = Color::kTransparentBlack;
    Color                _tintColor = Color::kWhite;
    AffineTransformation _renderTransformation;

    std::unique_ptr<opengl::Framebuffer> _renderCache;
    opengl::Framebuffer::Attachment*     _renderCacheColorAttachment = nullptr;
    std::shared_ptr<WeakTexture>         _renderCacheTexture = std::make_shared<WeakTexture>();

    std::list<Listener>                               _listeners;
    std::list<Provision>                              _provisions;
    TouchpadFocus                                     _touchpadFocus;
    std::unordered_map<size_t, std::function<void()>> _updateHooks;

    scraps::AbstractTaskScheduler::TaskScope          _taskScope; /* must be the last member */
};

template <typename... Views>
void View::_addSubviews(View* view, Views&&... views) {
    addSubview(view);
    _addSubviews(std::forward<Views>(views)...);
}

template <typename... Views>
void View::_removeSubviews(View* view, Views&&... views) {
    removeSubview(view);
    _removeSubviews(std::forward<Views>(views)...);
}

template <typename T>
T* View::shader(const char* identifier) {
    auto s = shaderCache()->get(std::string(identifier));
    if (!s) {
        s = shaderCache()->add(std::make_unique<T>(), std::string(identifier), ShaderCache::Policy::kKeepForever);
    }
    auto ret = dynamic_cast<T*>(s->get());
    ret->setTransformation(renderTransformation());
    return ret;
}

template <typename T>
T* View::find(Relation relation) {
    T* ret = nullptr;
    _traverseRelation(relation, [&](View* view, bool* shouldContinue) {
        for (auto& provision : view->_provisions) {
            if (!hasRelation(provision.relation, view)) { continue; }
            if (auto object = stdts::any_cast<T>(&provision.object)) {
                ret = object;
                *shouldContinue = false;
                return 1;
            }
            if (auto pointer = stdts::any_cast<T*>(&provision.object)) {
                ret = *pointer;
                *shouldContinue = false;
                return 1;
            }
        }
        return 0;
    });
    if (!ret && application() && (relation == Relation::kHierarchy || relation == Relation::kAny || relation == Relation::kAncestor)) {
        return application()->get<T>();
    }
    return ret;
}

template <typename F>
void View::_traverseRelation(Relation relation, F&& function) {
    switch (relation) {
        case Relation::kAny: {
            bool shouldContinue = true;
            for (auto& v : _topViewsForRelation(relation)) {
                v->TreeNode::traverseRelation(TreeNode::Relation::kCommonRoot, function, 0, &shouldContinue);
            }
            break;
        }
        case Relation::kHierarchy:  TreeNode::traverseRelation(TreeNode::Relation::kCommonRoot, function, 0); break;
        case Relation::kDescendant: TreeNode::traverseRelation(TreeNode::Relation::kDescendant, function, 0); break;
        case Relation::kAncestor:   TreeNode::traverseRelation(TreeNode::Relation::kAncestor,   function, 0); break;
        case Relation::kSibling:    TreeNode::traverseRelation(TreeNode::Relation::kSibling,    function, 0); break;
        case Relation::kSelf:       TreeNode::traverseRelation(TreeNode::Relation::kSelf,       function, 0); break;
    }
}

} // namespace okui


#pragma once

#include <cstdint>
#include <functional>
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

#include <gsl/gsl>
#include <nonstd/optional.hpp>

#include "chainerx/array_body.h"
#include "chainerx/array_fwd.h"
#include "chainerx/array_index.h"
#include "chainerx/array_node.h"
#include "chainerx/array_repr.h"
#include "chainerx/axes.h"
#include "chainerx/constant.h"
#include "chainerx/context.h"
#include "chainerx/device.h"
#include "chainerx/dtype.h"
#include "chainerx/enum.h"
#include "chainerx/error.h"
#include "chainerx/graph.h"
#include "chainerx/scalar.h"
#include "chainerx/shape.h"
#include "chainerx/strides.h"

namespace chainerx {
namespace internal {

BackpropId GetArrayBackpropId(const Array& array, const nonstd::optional<BackpropId>& backprop_id);

Array MakeArray(const Shape& shape, const Strides& strides, Dtype dtype, Device& device, std::shared_ptr<void> data, int64_t offset = 0);

inline const std::shared_ptr<ArrayBody>& GetArrayBody(const Array& array);

inline std::shared_ptr<ArrayBody>&& MoveArrayBody(Array&& array);

}  // namespace internal

// The user interface of multi-dimensional arrays.
//
// This wraps an ArrayBody, providing accessors, an interface for graph operations and differentiable operations.
class Array {
public:
    Array() = default;

    // TODO(hvy): Consider making this contructor private and prohibit body from being null (assert that given body is not null).
    explicit Array(std::shared_ptr<internal::ArrayBody> body) : body_{std::move(body)} {
        if (body_ == nullptr) {
            throw ChainerxError{"Cannot create an array from null."};
        }
    }

    // Copy constructor that copies the pointer to the body instead of the body itself.
    //
    // Use MakeView if you want to clone the body.
    Array(const Array& other) = default;
    Array(Array&& other) = default;

    // Assign operators just replace the body. They do not copy data between arrays.
    Array& operator=(const Array&) = default;
    Array& operator=(Array&& other) = default;

    Array operator-() const;

    Array operator==(const Array& rhs) const;
    Array operator!=(const Array& rhs) const;
    Array operator>(const Array& rhs) const;
    Array operator>=(const Array& rhs) const;
    Array operator<(const Array& rhs) const;
    Array operator<=(const Array& rhs) const;

    Array& operator+=(const Array& rhs);
    Array& operator+=(Scalar rhs);
    Array& operator-=(const Array& rhs);
    Array& operator-=(Scalar rhs);
    Array& operator*=(const Array& rhs);
    Array& operator*=(Scalar rhs);
    Array& operator/=(const Array& rhs);
    Array& operator/=(Scalar rhs);

    const Array& operator+=(const Array& rhs) const;
    const Array& operator+=(Scalar rhs) const;
    const Array& operator-=(const Array& rhs) const;
    const Array& operator-=(Scalar rhs) const;
    const Array& operator*=(const Array& rhs) const;
    const Array& operator*=(Scalar rhs) const;
    const Array& operator/=(const Array& rhs) const;
    const Array& operator/=(Scalar rhs) const;

    Array operator+(const Array& rhs) const;
    Array operator+(Scalar rhs) const;
    Array operator-(const Array& rhs) const;
    Array operator-(Scalar rhs) const;
    Array operator*(const Array& rhs) const;
    Array operator*(Scalar rhs) const;
    Array operator/(const Array& rhs) const;
    Array operator/(Scalar rhs) const;

    // Returns a view selected with the indices.
    Array At(const std::vector<ArrayIndex>& indices) const;

    // Returns a transposed view of the array.
    Array Transpose(const OptionalAxes& axes = nonstd::nullopt) const;

    // Returns a reshaped array.
    // TODO(niboshi): Support shape with dimension -1.
    Array Reshape(const Shape& newshape) const;

    // Returns a squeezed array with unit-length axes removed.
    //
    // If no axes are specified, all axes of unit-lengths are removed.
    // If no axes can be removed, an array with aliased data is returned.
    Array Squeeze(const OptionalAxes& axis = nonstd::nullopt) const;

    // Broadcasts the array to the specified shape.
    // Returned array is always a view to this array.
    Array BroadcastTo(const Shape& shape) const;

    // Returns the indices of the maximum values along the given axis.
    Array ArgMax(const OptionalAxes& axis = nonstd::nullopt) const;

    // Returns a sum of the array.
    // If `axis` is set, it will be summed over the specified axes.
    // Otherwise, it will be summed over all the existing axes.
    // Note: When implementing chainerx::Sum(), be careful of the semantics of the default value of `keepdims`. See NumPy documentation.
    Array Sum(const OptionalAxes& axis = nonstd::nullopt, bool keepdims = false) const;

    // Returns the maximum value of the array.
    // If `axis` is set, the maximum value is chosen along the specified axes.
    // Otherwise, all the elements are searched at once.
    Array Max(const OptionalAxes& axis = nonstd::nullopt, bool keepdims = false) const;

    Array Mean(const OptionalAxes& axis = nonstd::nullopt, bool keepdims = false) const;

    Array Var(const OptionalAxes& axis = nonstd::nullopt, bool keepdims = false) const;

    // Returns a dot product of the array with another one.
    Array Dot(const Array& b) const;

    // Takes elements specified by indices from the array.
    //
    // TODO(niboshi): Support Scalar and StackVector as indices.
    // TODO(niboshi): Support axis=None behavior in NumPy.
    // TODO(niboshi): Support indices dtype other than int64.
    Array Take(const Array& indices, int8_t axis) const;

    // Creates a copy.
    // It will be connected to all the graphs.
    // It will be always C-contiguous.
    Array Copy() const;

    // Creates a view.
    // It creates a new array node and connects graphs.
    Array MakeView() const;

    // Transfers the array to another device. It will be connected to all the graphs.
    //
    // If the destination is the same device, an array with aliased data is returned.
    // Otherwise, a C-contiguous Array will be created on the target device.
    // TODO(niboshi): Currently control over whether to make an alias is not supported.
    Array ToDevice(Device& dst_device) const;

    // Transfer the array to the native device. It will be connected to all the graphs.
    //
    // This is a wrapper function which calls Array::ToDevice with the native:0 device.
    // See also: Array::ToDevice();
    Array ToNative() const;

    // Creates a copy or a view. It will be disconnected from all the graphs.
    // If `kind` is `CopyKind::kCopy`, the returned array will be always C-contiguous.
    Array AsGradStopped(CopyKind kind = CopyKind::kView) const;

    // Creates a copy or a view. It will be disconnected from the specified graphs.
    // If `kind` is `CopyKind::kCopy`, the returned array will be always C-contiguous.
    Array AsGradStopped(gsl::span<const BackpropId> backprop_ids, CopyKind kind = CopyKind::kView) const;
    Array AsGradStopped(std::initializer_list<const BackpropId> backprop_ids, CopyKind kind = CopyKind::kView) const {
        return AsGradStopped(gsl::span<const BackpropId>{backprop_ids.begin(), backprop_ids.end()}, kind);
    }

    // Casts to a specified type.
    // By default, always returns a newly allocated array. If `copy` is false,
    // and the dtype requirement is satisfied, the input array is returned instead of a copy.
    Array AsType(Dtype dtype, bool copy = true) const;

    void Fill(Scalar value) const;

    // Returns the gradient of the array.
    //
    // ChainerxError is thrown if the array is constant with respect to the computation for the specified backprop ID.
    // ChainerxError is thrown if the array is not flagged as requiring gradient.
    // This function ignores no/force-backprop mode.
    const nonstd::optional<Array>& GetGrad(const nonstd::optional<BackpropId>& backprop_id = nonstd::nullopt) const;

    // Sets the gradient of the array.
    // This function also flags the array as requiring gradient, so that preceding GetGrad() can return the gradient.
    //
    // ChainerxError is thrown if the array is constant with respect to the computation for the specified backprop ID.
    // This function ignores no/force-backprop mode.
    void SetGrad(Array grad, const nonstd::optional<BackpropId>& backprop_id = nonstd::nullopt) const;

    // Clears the gradient of the array if set.
    // This function does not change the state of the array other than that. For example, if the array is flagged as requiring gradient,
    // that will not change.
    //
    // ChainerxError is thrown if the array is constant with respect to the computation for the specified backprop ID.
    // This function ignores no/force-backprop mode.
    void ClearGrad(const nonstd::optional<BackpropId>& backprop_id = nonstd::nullopt) const;

    // Returns whether the array needs to backprop.
    //
    // If no-backprop mode is set with respect to the specified backprop ID, this function returns false.
    bool IsBackpropRequired(const nonstd::optional<BackpropId>& backprop_id = nonstd::nullopt) const;
    bool IsBackpropRequired(AnyGraph any_graph) const;

    // Returns whether the array is flagged to compute the gradient during backprop.
    //
    // This function ignores no/force-backprop mode.
    bool IsGradRequired(const nonstd::optional<BackpropId>& backprop_id = nonstd::nullopt) const;

    // Flags the array to compute the gradient during backprop.
    // If the array is constant with respect to the computation of the backprop ID, this function makes the array non-constant.
    //
    // This function ignores no/force-backprop mode.
    const Array& RequireGrad(const nonstd::optional<BackpropId>& backprop_id = nonstd::nullopt) const {
        return RequireGradImpl(*this, backprop_id);
    }

    Array& RequireGrad(const nonstd::optional<BackpropId>& backprop_id = nonstd::nullopt) { return RequireGradImpl(*this, backprop_id); }

    int64_t GetTotalSize() const { return body_->GetTotalSize(); }

    int64_t GetNBytes() const { return body_->GetNBytes(); }

    int64_t GetItemSize() const { return body_->GetItemSize(); }

    bool IsContiguous() const { return body_->IsContiguous(); }

    std::string ToString() const;

    Context& context() const { return body_->device().context(); }

    Dtype dtype() const { return body_->dtype(); }

    Device& device() const { return body_->device(); }

    int8_t ndim() const { return body_->ndim(); }

    const Shape& shape() const { return body_->shape(); }

    const Strides& strides() const { return body_->strides(); }

    const std::shared_ptr<void>& data() const { return body_->data(); }

    void* raw_data() const { return body_->data().get(); }

    int64_t offset() const { return body_->offset(); }

private:
    friend Array internal::MakeArray(
            const Shape& shape, const Strides& strides, Dtype dtype, Device& device, std::shared_ptr<void> data, int64_t offset);
    friend const std::shared_ptr<internal::ArrayBody>& internal::GetArrayBody(const Array& array);
    friend std::shared_ptr<internal::ArrayBody>&& internal::MoveArrayBody(Array&& array);

    Array(const Shape& shape, const Strides& strides, Dtype dtype, Device& device, std::shared_ptr<void> data, int64_t offset = 0);

    template <typename T>
    static T& RequireGradImpl(T& array, const nonstd::optional<BackpropId>& backprop_id);

    std::shared_ptr<internal::ArrayBody> body_;
};

Array operator+(Scalar lhs, const Array& rhs);
Array operator-(Scalar lhs, const Array& rhs);
Array operator*(Scalar lhs, const Array& rhs);
// TODO(hvy): Implement Scalar / Array using e.g. multiplication with reciprocal.

namespace internal {

inline const std::shared_ptr<ArrayBody>& GetArrayBody(const Array& array) { return array.body_; }

inline std::shared_ptr<ArrayBody>&& MoveArrayBody(Array&& array) { return std::move(array.body_); }

std::vector<std::shared_ptr<ArrayBody>> MoveArrayBodies(std::vector<Array>&& arrays);

std::vector<std::shared_ptr<ArrayBody>> MoveArrayBodies(std::vector<nonstd::optional<Array>>&& arrays);

}  // namespace internal

void DebugDumpComputationalGraph(
        std::ostream& os,
        const Array& array,
        const nonstd::optional<BackpropId>& backprop_id,
        int indent = 0,
        const std::vector<std::pair<ConstArrayRef, std::string>>& array_name_map = {});

}  // namespace chainerx


#ifndef TTT_GS_GAMESTATESTACK_H
#define TTT_GS_GAMESTATESTACK_H

#include "GameState.h"
#include "../Utilities/Utilities.h"

#include <gsl/util>
#include <gsl/assert>

#include <deque>
#include <memory>
#include <optional>

namespace ttt::gs
{
	class GameStateStack final
	{
	public:
		using SizeType = gsl::index;

		template<typename T, typename... Arg>
		void emplace(Arg &&...args) noexcept(std::is_nothrow_constructible_v<T, Arg...>);
		void pop() noexcept;
		void clear() noexcept;

		void update();
		void render() const noexcept;

		void setBackgroundRender(const std::optional<SizeType> &index) noexcept;
		void setBackgroundUpdate(const std::optional<SizeType> &index) noexcept;

		[[nodiscard]] SizeType getSize() const noexcept;
		[[nodiscard]] SizeType getMaxSize() const noexcept;

	private:
		std::deque<std::unique_ptr<GameState>> gameStates;
		std::optional<SizeType> bgUpdateIndex;
		std::optional<SizeType> bgRenderIndex;

		SizeType popIndex{-1};
		SizeType queuedForPop{0};
	};

	template<typename T, typename... Arg>
	void GameStateStack::emplace(Arg &&...args) noexcept(std::is_nothrow_constructible_v<T, Arg...>)
	{
		gameStates.emplace_back(std::make_unique<T>(std::forward<Arg>(args)...));
	}

	inline void GameStateStack::setBackgroundUpdate(const std::optional<SizeType> &index) noexcept
	{
		Expects(!index || *index < util::getSize(gameStates));
		bgUpdateIndex = index;
	}

	inline void GameStateStack::setBackgroundRender(const std::optional<SizeType> &index) noexcept
	{
		Expects(!index || *index < util::getSize(gameStates));
		bgRenderIndex = index;
	}

	inline GameStateStack::SizeType GameStateStack::getSize() const noexcept { return gameStates.size(); }
	inline GameStateStack::SizeType GameStateStack::getMaxSize() const noexcept { return gameStates.max_size(); }
}

#endif


// SPDX-License-Identifier: MIT
// The MIT License (MIT)
//
// Copyright (c) 2014-2018, Institute for Software & Systems Engineering
// Copyright (c) 2018-2019, Johannes Leupolz
//
// 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.

#ifndef PEMC_LMC_LMC_H_
#define PEMC_LMC_LMC_H_

#include <atomic>
#include <functional>
#include <gsl/span>
#include <string>
#include <vector>

#include "pemc/basic/dll_defines.h"
#include "pemc/basic/label.h"
#include "pemc/basic/model_capacity.h"
#include "pemc/basic/probability.h"
#include "pemc/basic/tsc_index.h"
#include "pemc/formula/formula.h"

namespace pemc {

struct LmcStateEntry {
  TransitionIndex from;
  int32_t elements;
};

// Transition = Target + Probability
struct LmcTransitionEntry {
  Probability probability;
  Label label;
  StateIndex state;

  LmcTransitionEntry() = default;
  LmcTransitionEntry(Probability _probability, Label _label, StateIndex _state)
      : probability(_probability), label(_label), state(_state) {}
};

class Lmc {
 private:
  TransitionIndex maxNumberOfTransitions = 0;
  std::atomic<TransitionIndex> transitionCount{0};
  std::vector<LmcTransitionEntry> transitions;
  TransitionIndex initialTransitionFrom =
      -1;  // is uninitialized at first, but may be something else than 0
  int32_t initialTransitionElements = 0;

  StateIndex maxNumberOfStates = 0;
  StateIndex stateCount = 0;
  std::vector<LmcStateEntry> states;

  std::vector<std::string> labelIdentifier;

  TransitionIndex getPlaceForNewTransitionEntries(NoOfElements number);

 public:
  Lmc();

  gsl::span<LmcStateEntry> getStates();

  gsl::span<std::string> getLabelIdentifier();
  void setLabelIdentifier(const std::vector<std::string>& _labelIdentifier);
  std::function<bool(TransitionIndex)> createLabelBasedFormulaEvaluator(
      Formula* formula);

  gsl::span<LmcTransitionEntry> getTransitions();
  gsl::span<LmcTransitionEntry> getInitialTransitions();
  std::tuple<TransitionIndex, TransitionIndex> getInitialTransitionIndexes();
  gsl::span<LmcTransitionEntry> getTransitionsOfState(StateIndex state);
  std::tuple<TransitionIndex, TransitionIndex> getTransitionIndexesOfState(
      StateIndex state);

  TransitionIndex getPlaceForNewTransitionEntriesOfState(StateIndex stateIndex,
                                                         NoOfElements number);
  TransitionIndex getPlaceForNewInitialTransitionEntries(NoOfElements number);
  void setLmcTransitionEntry(TransitionIndex index,
                             const LmcTransitionEntry& entry);
  void createStutteringState(StateIndex stutteringStateIndex);

  void initialize(ModelCapacity& modelCapacity);
  void finishCreation(StateIndex _stateCount);
  void validate();
};

}  // namespace pemc

#endif  // PEMC_LMC_LMC_H_


#pragma once

#include "gl_helpers.h"
#include "GL_Loader.h"
#include "MappedGL.h"
#include "Range.h"

#include <handy/Guard.h>

#include <gsl/span>

#include <type_traits>
#include <vector>

namespace ad
{

struct [[nodiscard]] VertexArrayObject : public ResourceGuard<GLuint>
{
    /// \note Deleting a bound VAO reverts the binding to zero
    VertexArrayObject() :
        ResourceGuard<GLuint>{reserve(glGenVertexArrays),
                              [](GLuint aIndex){glDeleteVertexArrays(1, &aIndex);}}
    {}
};

/// \TODO understand when glDisableVertexAttribArray should actually be called
///       (likely not specially before destruction, but more when rendering other objects
///        since it is a current(i.e. global) VAO state)
/// \Note Well note even that: Activated vertex attribute array are per VAO, so changing VAO
//        Already correctly handles that.
struct [[nodiscard]] VertexBufferObject : public ResourceGuard<GLuint>
{
    VertexBufferObject() :
        ResourceGuard<GLuint>{reserve(glGenBuffers),
                              [](GLuint aIndex){glDeleteBuffers(1, &aIndex);}}
    {}
};

/// \brief A VertexArray with a vector of VertexBuffers
struct [[nodiscard]] VertexSpecification
{
    VertexSpecification(VertexArrayObject aVertexArray={},
                        std::vector<VertexBufferObject> aVertexBuffers={}) :
        mVertexArray{std::move(aVertexArray)},
        mVertexBuffers{std::move(aVertexBuffers)}
    {}

    VertexArrayObject mVertexArray;
    std::vector<VertexBufferObject> mVertexBuffers;
};

/// \brief Describes the attribute access from the shader (layout id, value type, normalization)
struct Attribute
{
    enum class Access
    {
        Float,
        Integer,
    };

    constexpr Attribute(GLuint aValue) :
        mIndex(aValue)
    {}

    constexpr Attribute(GLuint aValue, Access aAccess, bool aNormalize=false) :
        mIndex(aValue),
        mTypeInShader(aAccess),
        mNormalize(aNormalize)
    {}

    GLuint mIndex;
    Access mTypeInShader{Access::Float};
    bool mNormalize{false};
};

/// \brief The complete description of an attribute expected by OpenGL
struct AttributeDescription : public Attribute
{
    GLuint mDimension;
    size_t mOffset;
    GLenum mDataType;
};

std::ostream & operator<<(std::ostream &aOut, const AttributeDescription & aDescription);

typedef std::initializer_list<AttributeDescription> AttributeDescriptionList;

template <class T_vertex>
VertexBufferObject loadVertexBuffer(const VertexArrayObject & aVertexArray,
                                    const AttributeDescriptionList & aAttributes,
                                    const gsl::span<T_vertex> aVertices,
                                    GLuint aAttributeDivisor = 0)
{
    glBindVertexArray(aVertexArray);

    if (aAttributeDivisor)
    {
        for(const auto & attribute : aAttributes)
        {
            glVertexAttribDivisor(attribute.mIndex, aAttributeDivisor);
        }
    }

    return makeLoadedVertexBuffer(aAttributes, aVertices);
}

template <class T_vertex>
void appendToVertexSpecification(VertexSpecification & aSpecification,
                                 const AttributeDescriptionList & aAttributes,
                                 const gsl::span<T_vertex> aVertices,
                                 GLuint aAttributeDivisor = 0)
{
    aSpecification.mVertexBuffers.push_back(
            loadVertexBuffer(aSpecification.mVertexArray,
                             aAttributes,
                             std::move(aVertices),
                             aAttributeDivisor));
}

/// \brief Create a VertexBufferObject with provided attributes, load it with data.
///
/// This is the lowest level overload, with explicit attribute description and raw data pointer.
/// Other overloads end-up calling it.
VertexBufferObject makeLoadedVertexBuffer(AttributeDescriptionList aAttributes,
                                          GLsizei aStride,
                                          size_t aSize,
                                          const GLvoid * aData);

template <class T_vertex>
VertexBufferObject makeLoadedVertexBuffer(AttributeDescriptionList aAttributes,
                                          const gsl::span<T_vertex> aVertices)
{
    return makeLoadedVertexBuffer(aAttributes,
                                  sizeof(T_vertex),
                                  aVertices.size_bytes(),
                                  aVertices.data());
}

/***
 * Buffer re-specification
 *
 * see: https://www.khronos.org/opengl/wiki/Buffer_Object_Streaming#Buffer_re-specification
 ***/

inline void respecifyBuffer(const VertexBufferObject & aVBO, const GLvoid * aData, GLsizei aSize)
{
    glBindBuffer(GL_ARRAY_BUFFER, aVBO);

    // Orphan the previous buffer
    glBufferData(GL_ARRAY_BUFFER, aSize, NULL, GL_STATIC_DRAW);

    // Copy value to new buffer
    glBufferSubData(GL_ARRAY_BUFFER, 0, aSize, aData);
}

/// \brief Respecify the buffer with the same size (allowing potential optimizations)
inline void respecifyBuffer(const VertexBufferObject & aVBO, const GLvoid * aData)
{
    GLint size;
    glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);

    respecifyBuffer(aVBO, aData, size);
}

template <class T_vertex>
void respecifyBuffer(const VertexBufferObject & aVBO, const gsl::span<T_vertex> aVertices)
{
    respecifyBuffer(aVBO,
                    aVertices.data(),
                    static_cast<GLsizei>(aVertices.size_bytes()));
}

} // namespace ad