/*******************************************************************************
 * Copyright (c) 2014, Jan Koester jan.koester@gmx.net
 * All rights reserved.
 * * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the <organization> nor the
 * names of its contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

#include <mutex>
#include <vector>
#include <memory>
#include <atomic>
#include <limits>
#include <type_traits>

#include <cstddef>

#pragma once

namespace netplus {
        class eventapi;
        class pollapi;
        class socket; // forward declaration added

        template<typename T>
        struct condata_traits {
            using reference = T &;
            using const_reference = const T &;
        };

        template<>
        struct condata_traits<void> {
        };

        template <class T>
        class condataAlloc : public condata_traits<T>{
        public:
            // type definitions
            typedef T        value_type;
            typedef T* pointer;
            typedef const T* const_pointer;
            typedef T&       reference;
            typedef const T& const_reference;
            typedef std::size_t    size_type;
            typedef std::ptrdiff_t difference_type;

            // rebind allocator to type U
            template <class U>
            struct rebind {
                typedef condataAlloc<U> other;
            };

            // return address of values
            pointer address (reference value) const {
                return &value;
            }
            const_pointer address (const_reference value) const {
                return &value;
            }

            /* constructors and destructor
             * - nothing to do because the allocator has no state
             */
            condataAlloc() throw() {
            }
            condataAlloc(const condataAlloc&) throw() {
            }
            template <class U>
            condataAlloc (const condataAlloc<U>&) throw() {
            }
            ~condataAlloc() throw() {
            }

            // return maximum number of elements that can be allocated
            size_type max_size () const throw() {
                return (std::numeric_limits<std::size_t>::max)() / sizeof(T);
            }

            // allocate but don't initialize num elements of type T
            pointer allocate (size_type num, const void* = 0) {
                // ::operator new throws std::bad_alloc on failure, making this compliant.
                pointer ret = (pointer)(::operator new(num*sizeof(T)));
                return ret;
            }

            // initialize elements of allocated storage p with value value
            void construct (pointer p, const T& value) noexcept { // ADDED noexcept
                new((void*)p)T(value);
            }

            // destroy elements of initialized storage p
            void destroy (pointer p) noexcept { // ADDED noexcept
                p->~T();
            }

            // deallocate storage p of deleted elements
            void deallocate (pointer p, size_type num) noexcept { // ADDED noexcept
                ::operator delete((void*)p);
            }
        };

        // return that all specializations of this allocator are interchangeable
        template <class T1, class T2>
        bool operator== (const condataAlloc<T1>&,
                         const condataAlloc<T2>&) throw() {
                             return true;
        }
        template <class T1, class T2>
        bool operator!= (const condataAlloc<T1>&,
                         const condataAlloc<T2>&) throw() {
                             return false;
        }

        template <typename T>
        class condata;

        template <> class condata<char> : public std::vector<char,condataAlloc<char>>{
        public:
            condata();
            condata(const condata<char> &src);
            condata(const std::vector<char> &src);

            typedef std::vector<char,condataAlloc<char>>::iterator iterator;
            typedef std::vector<char,condataAlloc<char>>::const_iterator const_iterator;

            iterator begin();
            const_iterator begin() const;
            iterator end();
            const_iterator end() const;

            /*postion for worker*/
            size_t     pos=0;

            void        resize(size_t size_c)=delete;
            void        append(const char *data,size_t datalen);
            size_t      search(const char *word);
            size_t      search(const char *word,size_t pos);
        };

        // Per-sub-connection state.  TCP/SSL connections use a single slot;
        // QUIC packs every child connection into additional slots so they
        // all share the parent con's event_mutex.
        struct ConSlot {
            std::unique_ptr<socket> csock;
            size_t SendOff = 0;

            std::atomic_bool WritePending{ false };
            std::atomic_bool ReadPending{ false };
            std::atomic_bool PeerClosed{ false };
            std::atomic_bool Closing{ false };
            std::atomic_bool ResponsePending{ false };
            std::atomic_int  PendingOps{ 0 };
        };

        class con {
        public:

            con(eventapi *event);
            con(const netplus::con&) =delete;
            virtual ~con();

            // --- Sub-connection slots ---
            std::vector<ConSlot> slots;   // slot[0] = primary / listening socket
            condata<char> RecvData;
            condata<char> SendData;

            int DebugId=0;

            // Application-defined extension data.
            // Allows frameworks to attach per-connection state without external maps.
            std::unique_ptr<void, void(*)(void*)> extension{nullptr, +[](void*){}};

            std::recursive_mutex event_mutex;

             time_t lasteventime;

            // Proactively write out whatever is currently queued in SendData,
            // instead of waiting for the event loop's post-RequestEvent drain.
            // Safe to call from within a RequestEvent handler on the same
            // thread (re-locks event_mutex, which is recursive). Returns true
            // if SendData was fully drained, false if the socket would block
            // (caller may retry later; the framework's normal EPOLLOUT re-arm
            // still applies for whatever's left queued).
            bool flushSendData();
        protected:
            con();
            friend class poll;
        };
};
