#include <functional>
#include <thread>
#include <memory>
#include <ev++.h>
#include "zio.h"
#include "log.h"
#include "zloop.h"
#include "web-client.h"

struct web_client_http:ev::io
{
	char*m_buff;
	int m_pos,m_size;
	int m_fd,m_status;

	web_client_http()
	{
		m_fd=-1;
		m_pos=0;
		m_size=4096;
		m_buff=(char*)malloc(m_size);
	}

	int connect_tcp(const char*ip,int port)
	{
		int fd=zio::build_stream();
		if(zio::connect(fd,"127.0.0.1",4000))
		{
			zio::close(fd);
			return m_fd=-1;
		}

		zio::setiobuf(fd,16<<10,16<<10);
		zio::setblocking(fd,false);

		return m_fd=fd;
	}

	int connect_ws(const char*ip,int port)
	{
		const char*fmt=
				"GET / HTTP/1.1\n"
				"Connection:Upgrade\n"
				"Host:127.0.0.1:8088\n"
				"Sec-WebSocket-Extensions:x-webkit-deflate-frame\n"
				"Sec-WebSocket-Key:puVOuWb7rel6z2AVZBKnfw==\n"
				"Sec-WebSocket-Version:13\n"
				"Upgrade:webet\n";

		if(connect_tcp(ip,port)<0)	
			return -1;

		int len=strlen(fmt);
		if(len!=zio::writev(m_fd,fmt,len))
		{
			close();
			return -1;
		}

		for(;;)
		{
			len=zio::read(m_fd,m_buff+m_pos,m_size-m_pos);
			if(len==-1)
			{
				close();
				return -1;
			}

			if(len==-2)
				continue;

			m_pos+=len;
			m_buff[m_pos]=0;
			if(strstr(m_buff,"\n\n"))
				break;
		}

		log_info("http debug:%s",m_buff);
	}

	void close()
	{
		zio::close(m_fd);
	}

	~web_client_http()
	{
		close();
		::free(m_buff);
	}
};

struct web_client_net_impl: web_client,zloop_base
{
	std::unique_ptr<std::thread> m_thread;

	std::mutex m_mutex;
	std::list<std::string> m_req_list;

	ev::timer m_check_timer;

	std::string m_ip;
	int m_port;

	web_client_net_impl ()
	{
		m_thread.reset(new std::thread(std::bind(&web_client_net_impl::run,this)));
	}

	virtual void on_async_0()
	{
		if(check_stop_flag()) 
			return;

		std::list<std::string> async_list;
		{
			std::unique_lock<std::mutex> _lock(m_mutex);
			m_req_list.swap(async_list);
		}
		on_async(async_list);
	}

	void on_async(const std::list<std::string>&req)
	{
	
	}


	void on_check_timer(ev::timer&t,int)
	{
	
	}

	void run()
	{
		m_check_timer.set(*this);
		m_check_timer.set<web_client_net_impl,&web_client_net_impl::on_check_timer>(this);
		m_check_timer.start(0.,1.);

		ev::dynamic_loop::run(0);
		log_info("web_client_net_impl exit.");
	}

	void post(const char*m,int len)
	{
		{
			std::unique_lock<std::mutex> _lock(m_mutex);
			m_req_list.push_back(std::string(m,len));
		}

		m_async.send();
	}

	void stop()
	{
		async_stop();
		m_thread->join();
	}

	std::atomic<bool> m_start_flag{false};
	void start()
	{
		if(m_start_flag.load())
			return;

		m_start_flag.store(true);
	}
};

web_client*web_client::instance(const char*ip,int port,const char*path)
{
	static web_client_net_impl impl;
	impl.start();
	return &impl;
}