#pragma once

#include <mutex>
#include <memory>
#include <string>
#include <stdexcept>
#include <chrono>
#include <boost/asio.hpp>
#include <boost/intrusive/list.hpp>
#include <boost/noncopyable.hpp>

namespace smackbio{
	namespace logserver{

		namespace asio = boost::asio;
		using boost::asio::ip::tcp;
		using boost::system::error_code;
		namespace intrusive = boost::intrusive;
		using std::chrono::system_clock;

		struct TerminalList;

		class Terminal
			: public intrusive::list_base_hook<>
			, private boost::noncopyable
		{
		private:
			Terminal();
			~Terminal();

		public:
			static std::shared_ptr<Terminal> create(TerminalList*, const std::shared_ptr<tcp::socket>& sock);

			std::shared_ptr<Terminal> try_hold() const { return weak_self_.lock(); }
			std::shared_ptr<Terminal> hold() const
			{
				auto p = try_hold();
				if (!p) throw std::runtime_error("Terminal has been disposed.");
				return p;
			}

			void disconnect();
			system_clock::duration inactive_time() const;

		private:
			TerminalList* list_ = nullptr;
			std::weak_ptr<Terminal> weak_self_;
			std::shared_ptr<tcp::socket> socket_;
			system_clock::time_point last_active_;

			static const size_t MaxMessageSize = 2048;		// Maximum message size
			unsigned char recv_buf_[MaxMessageSize];
			unsigned char send_buf_[MaxMessageSize];
			size_t recv_pos_ = 0;
			size_t find_null_pos_ = 0;

		private:
			void begin_receive();
			bool process_messages();
		};

		typedef size_t(__stdcall *OnMessageCallback)(void* context, const char* msg, size_t msg_len, char* reply, size_t reply_len);

		struct TerminalList
		{
			intrusive::list<Terminal> terminals;
			std::mutex mutex;
			OnMessageCallback on_message;
			void* on_message_context;
		};
	}
}
