#pragma once

#include "Common.h"
#include "System/Object.h"
#include "System/String.h"
#include "System/SmartPointer.h"
#include "System/Action.h"
#include "System/Func.h"
#include "System/IServiceProvider.h"
#include "WebAppCore/Http/HttpContext.h"
#include "WebAppCore/WebSockets/WebSocketContext.h"
#include "System/Collections/Generic/Dictionary.h"
#include "System/Collections/Generic/List.h"
#include "System/Net/Sockets/TcpListener.h"

namespace DotNetDupe {
    namespace WebAppCore {
        namespace Builder {

            class WebApplicationBuilder;

            class WebApplication : public virtual DotNetDupe::System::Object {
            public:
                using ControllerRegistrar = DotNetDupe::System::Action<const DotNetDupe::System::SmartPointer<WebApplication>&>;

                DOTNETDUPE_API explicit WebApplication(const DotNetDupe::System::SmartPointer<DotNetDupe::System::IServiceProvider>& spServices);
                DOTNETDUPE_API ~WebApplication() override;

                WebApplication(const WebApplication&) = delete;
                WebApplication& operator=(const WebApplication&) = delete;
                DOTNETDUPE_API WebApplication(WebApplication&&) noexcept;
                DOTNETDUPE_API WebApplication& operator=(WebApplication&&) noexcept;

                DOTNETDUPE_API static DotNetDupe::System::SmartPointer<WebApplicationBuilder> CreateBuilder();
                
                DOTNETDUPE_API DotNetDupe::System::SmartPointer<DotNetDupe::System::IServiceProvider> GetServices() const { return m_spServices; }

                DOTNETDUPE_API void MapGet(const DotNetDupe::System::String& pattern, DotNetDupe::System::Func<DotNetDupe::System::String, DotNetDupe::System::SmartPointer<Http::HttpContext>> handler);
                DOTNETDUPE_API void MapPost(const DotNetDupe::System::String& pattern, DotNetDupe::System::Func<DotNetDupe::System::String, DotNetDupe::System::SmartPointer<Http::HttpContext>> handler);
                DOTNETDUPE_API void MapPut(const DotNetDupe::System::String& pattern, DotNetDupe::System::Func<DotNetDupe::System::String, DotNetDupe::System::SmartPointer<Http::HttpContext>> handler);
                DOTNETDUPE_API void MapDelete(const DotNetDupe::System::String& pattern, DotNetDupe::System::Func<DotNetDupe::System::String, DotNetDupe::System::SmartPointer<Http::HttpContext>> handler);
                DOTNETDUPE_API void MapWebSocket(const DotNetDupe::System::String& pattern, DotNetDupe::System::SmartPointer<WebSockets::IWebSocketHandler> handler);
                DOTNETDUPE_API DotNetDupe::System::Collections::Generic::List<DotNetDupe::System::String> GetWebSocketRoutes() const;
                DOTNETDUPE_API bool HasWebSocketRoute(const DotNetDupe::System::String& path) const;

                DOTNETDUPE_API void MapControllers();

                DOTNETDUPE_API void Run(const DotNetDupe::System::String& url = "http://127.0.0.1:5000", int threadCount = 10);
                DOTNETDUPE_API void Stop();

            private:
                friend class WebApplicationBuilder;

                void SetControllerRegistrars(DotNetDupe::System::Collections::Generic::List<ControllerRegistrar> registrars) {
                    m_controllerRegistrars = std::move(registrars);
                }

                void SetSelfPointer(const DotNetDupe::System::SmartPointer<WebApplication>& spSelf) {
                    m_spSelf = spSelf;
                }

                void HandleConnection(DotNetDupe::System::SmartPointer<DotNetDupe::System::Net::Sockets::TcpClient> spClient);
                void QueueAcceptedClient(DotNetDupe::System::SmartPointer<DotNetDupe::System::Net::Sockets::TcpClient> pClient);
                void StartServerLoop(const DotNetDupe::System::String& host, int port);

                DotNetDupe::System::SmartPointer<DotNetDupe::System::IServiceProvider> m_spServices;
                DotNetDupe::System::Collections::Generic::Dictionary<DotNetDupe::System::String, DotNetDupe::System::Func<DotNetDupe::System::String, DotNetDupe::System::SmartPointer<Http::HttpContext>>> m_getHandlers;
                DotNetDupe::System::Collections::Generic::Dictionary<DotNetDupe::System::String, DotNetDupe::System::Func<DotNetDupe::System::String, DotNetDupe::System::SmartPointer<Http::HttpContext>>> m_postHandlers;
                DotNetDupe::System::Collections::Generic::Dictionary<DotNetDupe::System::String, DotNetDupe::System::Func<DotNetDupe::System::String, DotNetDupe::System::SmartPointer<Http::HttpContext>>> m_putHandlers;
                DotNetDupe::System::Collections::Generic::Dictionary<DotNetDupe::System::String, DotNetDupe::System::Func<DotNetDupe::System::String, DotNetDupe::System::SmartPointer<Http::HttpContext>>> m_deleteHandlers;
                DotNetDupe::System::Collections::Generic::Dictionary<DotNetDupe::System::String, DotNetDupe::System::SmartPointer<WebSockets::IWebSocketHandler>> m_wsHandlers;
                
                DotNetDupe::System::SmartPointer<DotNetDupe::System::Net::Sockets::TcpListener> m_pListener;
                bool m_bRunning;
                DotNetDupe::System::String m_sHost;
                int m_nPort;
                DotNetDupe::System::Collections::Generic::List<ControllerRegistrar> m_controllerRegistrars;
                DotNetDupe::System::SmartPointer<WebApplication> m_spSelf;
            };

        }
    }
}

Generated by OpenCppCoverage (Version: 0.9.9.0)