#define BOOSTER_SOURCE

#include "reactor_config.h"

#include <string.h>

#ifdef AIO_HAVE_POSIX_SELECT
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>
#include <unistd.h>
#endif

#if defined AIO_HAVE_WIN32_SELECT || defined AIO_HAVE_WSAPOLL
#undef FD_SETSIZE
#define FD_SETSIZE 1024
#include <winsock2.h>
#include <map>
#include <algorithm>
#endif

#ifdef AIO_HAVE_POLL
#include <poll.h>
#include <unistd.h>
#endif
#ifdef AIO_HAVE_DEVPOLL
#include <sys/devpoll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif

#ifdef AIO_HAVE_EPOLL
#include <sys/epoll.h>
#include <unistd.h>
#endif

#ifdef AIO_HAVE_KQUEUE
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#endif

#include <booster/aio/reactor.h>
#include <booster/system_error.h>

#include <vector>
#include <iostream>

#include "category.h"

namespace booster {
namespace aio {
	class reactor_impl {
	public:
		virtual void select(native_type fd,int flags,int &error) = 0;
		virtual int poll(reactor::event *events,int n,int timeout,int &error) = 0;
		virtual std::string name() const = 0;
		virtual ~reactor_impl() {};
	};

	#if defined AIO_HAVE_POLL  || defined AIO_HAVE_DEVPOLL
	class base_poll_reactor : public reactor_impl {
	protected:
		int to_poll_events(int event)
		{
			int pe=0;
			if(event & reactor::in)
				pe|=POLLIN;
			if(event & reactor::out)
				pe|=POLLOUT;
			return pe;
		}
		int to_user_events(int event)
		{
			int ue=0;
			if(event & POLLIN)
				ue|=reactor::in;
			if(event & POLLOUT)
				ue|=reactor::out;
			if(event & (POLLERR | POLLHUP | POLLPRI))
				ue|=reactor::err;
			return ue;
		}
	};
	#endif

	#ifdef AIO_HAVE_POLL

	class poll_reactor : public base_poll_reactor {
	public:
		std::string name() const { return "poll"; }
		virtual void select(native_type fd,int flags,int &error)
		{
			if(!check(fd,error))
				return;
			if(flags == 0) {
				remove(fd);
				return;
			}
			entry(fd).events=to_poll_events(flags);
		}

		struct pollfd &entry(native_type fd)
		{
			if(map_.size() <= unsigned(fd)) {
				map_.resize(fd+1,-1);
			}
			if(map_[fd]==-1) {
				map_[fd]=pollfds_.size();
				pollfd tmp=pollfd();
				tmp.fd=fd;
				pollfds_.push_back(tmp);
			}
			return pollfds_[map_[fd]];

		}

		void remove(native_type fd)
		{
			if(fd >= int(map_.size()) || map_[fd]==-1)
				return;

			int index=map_[fd];
			std::swap(pollfds_[index],pollfds_.back());
			map_[pollfds_[index].fd]=index;
			pollfds_.resize(pollfds_.size()-1);
			map_[fd]=-1;
		}

		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			struct pollfd *pfd = pollfds_.size() > 0 ? &pollfds_.front() : 0;
			int size = pollfds_.size();

			int count = ::poll(pfd,size,timeout);
			if(count < 0)
				error = errno;
			int read=0;
			for(unsigned i=0;i<pollfds_.size() && read < count && read < n;i++) {
				if(pollfds_[i].revents == POLLNVAL) {
					remove(pollfds_[i].fd);
					count --;
					continue;
				}
				if(pollfds_[i].revents != 0) {
					events[read].events = to_user_events(pollfds_[i].revents);
					events[read].fd = pollfds_[i].fd;
					read ++;
				}
			}
			return read;
		}
	private:
		bool check(native_type fd,int &error)
		{
			if(fd < 0) {
				error=EBADF;
				return false;
			}
			return true;
		}
		std::vector<int> map_;
		std::vector< ::pollfd> pollfds_;
	};

	#endif // poll

	#if defined(AIO_HAVE_DEVPOLL) || defined(AIO_HAVE_EPOLL) || defined(AIO_HAVE_KQUEUE)
	class base_fast_reactor {
	protected:
		bool check(int fd,int &error)
		{
			if(fd < 0) {
				error=EINVAL;
				return false;
			}
			if(fd >= int(events_.size())) {
				events_.resize(fd+1,0);
			}
			return true;
		}

		std::vector<int> events_;
	};

	#endif

	#ifdef AIO_HAVE_DEVPOLL

	class devpoll_reactor : public base_poll_reactor, protected base_fast_reactor {
	public:
		std::string name() const { return "devpoll"; }

		devpoll_reactor()
		{
			pollfd_=::open("/dev/poll",O_RDWR);
			if(!pollfd_)
				throw system::system_error(errno,syscat,"Failed to open /dev/poll");
		}

		virtual ~devpoll_reactor()
		{
			::close(pollfd_);
		}
		virtual void select(native_type fd,int flags,int &error)
		{
			if(!check(fd,error))
				return;
			struct pollfd evs[2] = {0};
			int evs_count = 0;
			if(flags == events_[fd])
				return;

			if(events_[fd]) {
				evs[evs_count].fd=fd;
				evs[evs_count].events=POLLREMOVE;
				evs_count++;
			}
			if(flags!=0) {
				evs[evs_count].fd=fd;
				evs[evs_count].events=to_poll_events(flags);
				evs_count++;
			}
			if(evs_count > 0) {
				int size = sizeof(evs[0])*evs_count;
				if(::write(pollfd_,evs,size)!=size) {
					error=errno;
					return;
				}
			}
			events_[fd]=flags;
		}

		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			struct pollfd fds[128] = {{0}};
			struct dvpoll dvp={0};
			dvp.dp_timeout = timeout;
			dvp.dp_nfds = n > 128 ? 128 : n;
			dvp.dp_fds=fds;

			int size = ::ioctl(pollfd_,DP_POLL,&dvp);

			if(size < 0) {
				error = errno;
				return -1;
			}
			int read = 0;
			for(int i=0;i<size;i++) {
				events[read].events = to_user_events(fds[i].revents);
				events[read].fd = fds[i].fd;
				read ++;
			}
			return read;
		}
	private:

		int pollfd_;
	};

	#endif // /dev/poll

	#ifdef AIO_HAVE_EPOLL
	class epoll_reactor : public base_poll_reactor, public base_fast_reactor {
	public:
		std::string name() const { return "epoll"; }

		epoll_reactor()
		{
			pollfd_=::epoll_create(16);
			if(!pollfd_)
				throw system::system_error(errno,syscat,"Failed to create epoll descriptor");
		}
		virtual ~epoll_reactor()
		{
			::close(pollfd_);
		}
		virtual void select(native_type fd,int flags,int &error)
		{
			if(!check(fd,error))
				return;
			if(events_[fd]!=0 && flags==0)
				write_flag(fd,EPOLL_CTL_DEL,0,error);
			else if(events_[fd]==0 && flags!=0)
				write_flag(fd,EPOLL_CTL_ADD,to_poll_events(flags),error);
			else if(events_[fd]!=flags)
				write_flag(fd,EPOLL_CTL_MOD,to_poll_events(flags),error);
			events_[fd]=flags;

		}

		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			struct epoll_event fds[128] = {};
			if (n >128) n=128;

			int size = 0;
			size = ::epoll_wait(pollfd_,fds,n,timeout);

			if(size < 0) {
				error = errno;
				return -1;
			}
			int read = 0;
			for(int i=0;i<size;i++) {
				events[read].events = to_user_events(fds[i].events);
				events[read].fd = fds[i].data.fd;
				read ++;
			}
			return read;
		}
	private:
		int to_poll_events(int event)
		{
			int pe=0;
			if(event & reactor::in)
				pe|=EPOLLIN;
			if(event & reactor::out)
				pe|=EPOLLOUT;
			return pe;
		}

		int to_user_events(int event)
		{
			int ue=0;
			if(event & EPOLLIN)
				ue|=reactor::in;
			if(event & EPOLLOUT)
				ue|=reactor::out;
			if(event & (EPOLLERR | EPOLLPRI | EPOLLHUP))
				ue|=reactor::err;
			return ue;
		}

		void write_flag(int fd,int op,int flags,int &error)
		{
			struct epoll_event efd=epoll_event();
			efd.events=flags;
			efd.data.fd=fd;

			if(::epoll_ctl(pollfd_,op,fd,&efd) < 0) {
				error=errno;
				return;
			}
		}
		int pollfd_;
	};
	#endif // epoll

	#if defined AIO_HAVE_POSIX_SELECT
	class select_reactor : public reactor_impl {
	public:
		std::string name() const { return "select"; }
		select_reactor() :
			map_(FD_SETSIZE,-1)
		{
		}
		virtual void select(native_type fd,int flags,int &error)
		{
			if(!check(fd,error))
				return;
			if(flags == 0) {
				remove(fd);
				return;
			}
			entry(fd).events=flags;
		}

		void remove(native_type fd)
		{
			if(fd >= int(map_.size()) || map_[fd]==-1)
				return;
			int index=map_[fd];
			std::swap(pollfds_[index],pollfds_.back());
			map_[pollfds_[index].fd]=index;
			pollfds_.resize(pollfds_.size()-1);
			map_[fd]=-1;
		}
		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			fd_set rd,wr,er;
			FD_ZERO(&rd);
			FD_ZERO(&wr);
			FD_ZERO(&er);
			int max_fd=0;
			for(unsigned i=0;i<pollfds_.size();i++) {
				int flags=pollfds_[i].events;
				int fd=pollfds_[i].fd;
				if(flags & reactor::in)
					FD_SET(fd,&rd);
				if(flags & reactor::out)
					FD_SET(fd,&wr);
				FD_SET(fd,&er);
				if(fd +1> max_fd)
					max_fd = fd+1;
			}
			struct timeval tv,*ptv=0;
			if(timeout >=0) {
				tv.tv_sec = timeout / 1000;
				tv.tv_usec = (timeout % 1000)*1000;
				ptv=&tv;
			}
			int read=::select(max_fd,&rd,&wr,&er,ptv);
			if(read < 0) {
				error=errno;
				return -1;
			}

			int count = 0;

			for(unsigned i=0;read > 0 && i < pollfds_.size() ;i++) {
				int fd=pollfds_[i].fd;
				bool r = FD_ISSET(fd,&rd);
				read-=int(r);
				bool w = FD_ISSET(fd,&wr);
				read-=int(w);
				bool e = FD_ISSET(fd,&er);
				read-=int(e);
				if(r || w || e) {
					if(count >=n) {
						count ++;
						continue;
					}
					reactor::event &ev=events[count];
					ev.fd = fd;
					ev.events=0;
					if(r)
						ev.events |= reactor::in;
					if(w)
						ev.events |= reactor::out;
					if(e)
						ev.events |= reactor::err;
					count++;
				}
			}
			return count;
		}
	private:
		bool check_exists(native_type fd,int &error)
		{
			if(!check(fd,error))
				return false;
			if(map_[fd]==-1) {
				error = ENOENT;
				return false;
			}
			return true;
		}
		bool check(native_type fd,int &error)
		{
			if(fd < 0 || fd>=native_type(FD_SETSIZE)) {
				error=EBADF;
				return false;
			}
			return true;

		}
		struct ev {
			int fd;
			int events;
		};

		ev &entry(native_type fd)
		{
			if(map_.size() <= unsigned(fd)) {
				map_.resize(fd+1,-1);
			}
			if(map_[fd]==-1) {
				map_[fd]=pollfds_.size();
				ev tmp=ev();
				tmp.fd=fd;
				pollfds_.push_back(tmp);
				return pollfds_.back();
			}
			return pollfds_[map_[fd]];

		}

		std::vector<int> map_;
		std::vector<ev> pollfds_;
	};
	#endif // POSIX_SELECT

	#ifdef AIO_HAVE_KQUEUE
	class kqueue_reactor : public reactor_impl, protected base_fast_reactor  {
	public:
		std::string name() const { return "kqueue"; }
		kqueue_reactor() :
			kev_(::kqueue())
		{
			if(kev_ < 0)
				throw system::system_error(errno,syscat,"Failed to create kqueue");
		}
		void select(int fd,int new_flags,int &error)
		{
			if(!check(fd,error))
				return;

			struct kevent evs[2];
			int evs_count = 0;

			if((events_[fd] & reactor::in) && ! (new_flags & reactor::in)) {
				EV_SET(&evs[evs_count],fd,EVFILT_READ,EV_DELETE,0,0,0);
				evs_count++;
			}
			if((events_[fd] & reactor::out) && ! (new_flags & reactor::out)) {
				EV_SET(&evs[evs_count],fd,EVFILT_WRITE,EV_DELETE,0,0,0);
				evs_count++;
			}
			if(!(events_[fd] & reactor::in) && (new_flags & reactor::in)) {
				EV_SET(&evs[evs_count],fd,EVFILT_READ,EV_ADD,0,0,0);
				evs_count++;
			}
			if(!(events_[fd] & reactor::out) && (new_flags & reactor::out)) {
				EV_SET(&evs[evs_count],fd,EVFILT_WRITE,EV_ADD,0,0,0);
				evs_count++;
			}
			if(evs_count > 0) {
				if(::kevent(kev_,evs,evs_count,0,0,0) < 0) {
					error=errno;
					return;
				}
			}
			events_[fd]=new_flags;
		}

		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			struct kevent evs[128];
			struct timespec tv,*ptv=0;
			if(timeout >=0) {
				tv.tv_sec = timeout / 1000;
				tv.tv_nsec = (timeout % 1000)*1000000L;
				ptv=&tv;
			}
			int read=::kevent(kev_,0,0,evs,128,ptv);
			if(read < 0) {
				error=errno;
				return -1;
			}
			int count = 0;
			for(int i=0;i<read;i++) {
				if(evs[i].flags & EV_EOF)
					add(evs[i].ident,events,n,count,reactor::in);
				if(evs[i].flags & EV_ERROR)
					add(evs[i].ident,events,n,count,reactor::err);
				if(evs[i].filter == EVFILT_READ)
					add(evs[i].ident,events,n,count,reactor::in);
				if(evs[i].filter == EVFILT_WRITE)
					add(evs[i].ident,events,n,count,reactor::out);
			}

			return count;
		}
		virtual ~kqueue_reactor() { ::close(kev_); };
	private:
		void add(int fd,reactor::event *events,int n,int &count,int flags)
		{
			for(int i=0;i<count;i++) {
				if(events[i].fd==fd) {
					events[i].events|=flags;
					return;
				}
			}
			if(count < n) {
				events[count].fd=fd;
				events[count].events=flags;
				count++;
			}
		}

		int kev_;
	};
	#endif

	#if defined AIO_HAVE_WIN32_SELECT
	class w32_select_reactor : public reactor_impl {
	public:
		std::string name() const { return "select"; }
		w32_select_reactor()
		{
		}
		virtual void select(native_type fd,int flags,int &error)
		{
			if(fd==invalid_socket) {
				error=WSAEBADF;
				return;
			}
			if(flags==0)
				pollfds_.erase(fd);
			else
				pollfds_[fd]=flags;
		}

		void set(native_type fd,fd_set *s)
		{
			s->fd_array[s->fd_count++]=fd;
		}

		bool isset(native_type fd,fd_set *s)
		{
			return std::binary_search(s->fd_array,s->fd_array+s->fd_count,fd);
		}

		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			fd_set rd,wr,er;
			FD_ZERO(&rd);
			FD_ZERO(&wr);
			FD_ZERO(&er);
			int count=0;
			for(pollfds_type::iterator p=pollfds_.begin(),e=pollfds_.end();p!=e;++p) {
				int flags=p->second;
				native_type fd=p->first;
				if(flags==0)
					continue;
				count ++;
				if(count >= FD_SETSIZE) {
					error = WSAEINVAL;
					return -1;
				}
				if(flags & reactor::in)
					set(fd,&rd);
				if(flags & reactor::out)
					set(fd,&wr);
				set(fd,&er);
			}
			struct timeval tv,*ptv=0;
			if(timeout >=0) {
				tv.tv_sec = timeout / 1000;
				tv.tv_usec = (timeout % 1000)*1000;
				ptv=&tv;
			}

			int read=::select(0,&rd,&wr,&er,ptv);
			if(read < 0) {
				error=WSAGetLastError();
				return -1;
			}
			std::sort(rd.fd_array,rd.fd_array+rd.fd_count);
			std::sort(wr.fd_array,wr.fd_array+wr.fd_count);
			std::sort(er.fd_array,er.fd_array+er.fd_count);

			count = 0;

			for(pollfds_type::iterator p=pollfds_.begin(),end=pollfds_.end();read > 0 && p!=end;++p) {
				int fd=p->first;
				bool r = isset(fd,&rd);
				read-=int(r);
				bool w = isset(fd,&wr);
				read-=int(w);
				bool e = isset(fd,&er);
				read-=int(e);
				if(r || w || e) {
					if(count >=n) {
						count ++;
						continue;
					}
					reactor::event &ev=events[count];
					ev.fd = fd;
					ev.events=0;
					if(r)
						ev.events |= reactor::in;
					if(w)
						ev.events |= reactor::out;
					if(e)
						ev.events |= reactor::err;
					count++;
				}
			}
			return count;
		}
	private:
		typedef std::map<native_type,int> pollfds_type;
		pollfds_type pollfds_;
	};
	#endif // W32_SELECT

	#ifdef BOOSTER_WIN32
	namespace  {
		struct loader {
			loader() {
				WORD ver=MAKEWORD(2, 2);
				WSADATA data;
				if(WSAStartup(ver,&data) < 0) {
					throw booster::runtime_error("Failed to init winsock");
				}
			}
		} instance;
	}
	#endif

	#if defined _MSC_VER  && _MSC_VER  == 1600
	reactor::reactor(int /*hint*/)
	{
		impl_.reset(new w32_select_reactor());
	}
	#else // Normal compiler
	reactor::reactor(int hint)
	{
		static const int default_poll =
		#if defined AIO_HAVE_EPOLL
			use_epoll;
		#elif defined AIO_HAVE_DEVPOLL
			use_dev_poll;
		#elif defined AIO_HAVE_KQUEUE
			use_kqueue;
		#elif defined AIO_HAVE_POLL
			use_poll;
		#else
			use_select;
		#endif

		if(hint==use_default)
			hint=default_poll;

		for(;;) {
			switch(hint) {
			// select
			#if defined AIO_HAVE_POSIX_SELECT
			case use_select:
				impl_.reset(new select_reactor());
				return;
			#elif defined AIO_HAVE_WIN32_SELECT
			case use_select:
				impl_.reset(new w32_select_reactor());
				return;
			#endif
			// poll
			#if defined AIO_HAVE_POLL
			case use_poll:
				impl_.reset(new poll_reactor());
				return;
			#endif
			// epoll
			#if defined AIO_HAVE_EPOLL
			case use_epoll:
				impl_.reset(new epoll_reactor());
				return;
			#endif
			// devpoll
			#if defined AIO_HAVE_DEVPOLL
			case use_dev_poll:
				impl_.reset(new devpoll_reactor());
				return;
			#endif
			// kqueue
			#if defined AIO_HAVE_KQUEUE
			case use_kqueue:
				impl_.reset(new kqueue_reactor());
				return;
			#endif
			default:
				if(hint!=default_poll)
					hint=default_poll;
				else
					throw booster::runtime_error("Internal error - no poller found");
			}
		}
	}

	#endif

	reactor::~reactor()

	std::string reactor::name() const
	{
		return impl_->name();
	}

	void reactor::select(native_type fd,int flags)
	{
		system::error_code e;
		select(fd,flags,e);
		if(e) throw system::system_error(e);
	}

	void reactor::select(native_type fd,int flags,system::error_code &e)
	{
		int error = 0;
		impl_->select(fd,flags,error);
		if(error)
			e=system::error_code(error,syscat);
	}

	int reactor::poll(reactor::event *events,int n,int timeout)
	{
		system::error_code e;
		int r=poll(events,n,timeout,e);
		if(e)
			throw system::system_error(e);
		return r;
	}

	int reactor::poll(reactor::event *events,int n,int timeout,system::error_code &e)
	{
		int error = 0;
		int r=impl_->poll(events,n,timeout,error);
		if(error)
			e=system::error_code(error,syscat);
		return r;
	}

} // aio
} // booster


#define BOOSTER_SOURCE

#include "reactor_config.h"

#include <string.h>

#ifdef AIO_HAVE_POSIX_SELECT
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>
#include <unistd.h>
#endif

#if defined AIO_HAVE_WIN32_SELECT || defined AIO_HAVE_WSAPOLL
#undef FD_SETSIZE
#define FD_SETSIZE 1024
#include <winsock2.h>
#include <map>
#include <algorithm>
#endif

#ifdef AIO_HAVE_POLL
#include <poll.h>
#include <unistd.h>
#endif
#ifdef AIO_HAVE_DEVPOLL
#include <sys/devpoll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif

#ifdef AIO_HAVE_EPOLL
#include <sys/epoll.h>
#include <unistd.h>
#endif

#ifdef AIO_HAVE_KQUEUE
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#endif

#include <booster/aio/reactor.h>
#include <booster/system_error.h>

#include <vector>
#include <iostream>

#include "category.h"

namespace booster {
namespace aio {
	class reactor_impl {
	public:
		virtual void select(native_type fd,int flags,int &error) = 0;
		virtual int poll(reactor::event *events,int n,int timeout,int &error) = 0;
		virtual std::string name() const = 0;
		virtual ~reactor_impl() {};
	};

	#if defined AIO_HAVE_POLL  || defined AIO_HAVE_DEVPOLL
	class base_poll_reactor : public reactor_impl {
	protected:
		int to_poll_events(int event)
		{
			int pe=0;
			if(event & reactor::in)
				pe|=POLLIN;
			if(event & reactor::out)
				pe|=POLLOUT;
			return pe;
		}
		int to_user_events(int event)
		{
			int ue=0;
			if(event & POLLIN)
				ue|=reactor::in;
			if(event & POLLOUT)
				ue|=reactor::out;
			if(event & (POLLERR | POLLHUP | POLLPRI))
				ue|=reactor::err;
			return ue;
		}
	};
	#endif

	#ifdef AIO_HAVE_POLL

	class poll_reactor : public base_poll_reactor {
	public:
		std::string name() const { return "poll"; }
		virtual void select(native_type fd,int flags,int &error)
		{
			if(!check(fd,error))
				return;
			if(flags == 0) {
				remove(fd);
				return;
			}
			entry(fd).events=to_poll_events(flags);
		}

		struct pollfd &entry(native_type fd)
		{
			if(map_.size() <= unsigned(fd)) {
				map_.resize(fd+1,-1);
			}
			if(map_[fd]==-1) {
				map_[fd]=pollfds_.size();
				pollfd tmp=pollfd();
				tmp.fd=fd;
				pollfds_.push_back(tmp);
			}
			return pollfds_[map_[fd]];

		}

		void remove(native_type fd)
		{
			if(fd >= int(map_.size()) || map_[fd]==-1)
				return;

			int index=map_[fd];
			std::swap(pollfds_[index],pollfds_.back());
			map_[pollfds_[index].fd]=index;
			pollfds_.resize(pollfds_.size()-1);
			map_[fd]=-1;
		}

		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			struct pollfd *pfd = pollfds_.size() > 0 ? &pollfds_.front() : 0;
			int size = pollfds_.size();

			int count = ::poll(pfd,size,timeout);
			if(count < 0)
				error = errno;
			int read=0;
			for(unsigned i=0;i<pollfds_.size() && read < count && read < n;i++) {
				if(pollfds_[i].revents == POLLNVAL) {
					remove(pollfds_[i].fd);
					count --;
					continue;
				}
				if(pollfds_[i].revents != 0) {
					events[read].events = to_user_events(pollfds_[i].revents);
					events[read].fd = pollfds_[i].fd;
					read ++;
				}
			}
			return read;
		}
	private:
		bool check(native_type fd,int &error)
		{
			if(fd < 0) {
				error=EBADF;
				return false;
			}
			return true;
		}
		std::vector<int> map_;
		std::vector< ::pollfd> pollfds_;
	};

	#endif // poll

	#if defined(AIO_HAVE_DEVPOLL) || defined(AIO_HAVE_EPOLL) || defined(AIO_HAVE_KQUEUE)
	class base_fast_reactor {
	protected:
		bool check(int fd,int &error)
		{
			if(fd < 0) {
				error=EINVAL;
				return false;
			}
			if(fd >= int(events_.size())) {
				events_.resize(fd+1,0);
			}
			return true;
		}

		std::vector<int> events_;
	};

	#endif

	#ifdef AIO_HAVE_DEVPOLL

	class devpoll_reactor : public base_poll_reactor, protected base_fast_reactor {
	public:
		std::string name() const { return "devpoll"; }

		devpoll_reactor()
		{
			pollfd_=::open("/dev/poll",O_RDWR);
			if(!pollfd_)
				throw system::system_error(errno,syscat,"Failed to open /dev/poll");
		}

		virtual ~devpoll_reactor()
		{
			::close(pollfd_);
		}
		virtual void select(native_type fd,int flags,int &error)
		{
			if(!check(fd,error))
				return;
			struct pollfd evs[2] = {0};
			int evs_count = 0;
			if(flags == events_[fd])
				return;

			if(events_[fd]) {
				evs[evs_count].fd=fd;
				evs[evs_count].events=POLLREMOVE;
				evs_count++;
			}
			if(flags!=0) {
				evs[evs_count].fd=fd;
				evs[evs_count].events=to_poll_events(flags);
				evs_count++;
			}
			if(evs_count > 0) {
				int size = sizeof(evs[0])*evs_count;
				if(::write(pollfd_,evs,size)!=size) {
					error=errno;
					return;
				}
			}
			events_[fd]=flags;
		}

		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			struct pollfd fds[128] = {{0}};
			struct dvpoll dvp={0};
			dvp.dp_timeout = timeout;
			dvp.dp_nfds = n > 128 ? 128 : n;
			dvp.dp_fds=fds;

			int size = ::ioctl(pollfd_,DP_POLL,&dvp);

			if(size < 0) {
				error = errno;
				return -1;
			}
			int read = 0;
			for(int i=0;i<size;i++) {
				events[read].events = to_user_events(fds[i].revents);
				events[read].fd = fds[i].fd;
				read ++;
			}
			return read;
		}
	private:

		int pollfd_;
	};

	#endif // /dev/poll

	#ifdef AIO_HAVE_EPOLL
	class epoll_reactor : public base_poll_reactor, public base_fast_reactor {
	public:
		std::string name() const { return "epoll"; }

		epoll_reactor()
		{
			pollfd_=::epoll_create(16);
			if(!pollfd_)
				throw system::system_error(errno,syscat,"Failed to create epoll descriptor");
		}
		virtual ~epoll_reactor()
		{
			::close(pollfd_);
		}
		virtual void select(native_type fd,int flags,int &error)
		{
			if(!check(fd,error))
				return;
			if(events_[fd]!=0 && flags==0)
				write_flag(fd,EPOLL_CTL_DEL,0,error);
			else if(events_[fd]==0 && flags!=0)
				write_flag(fd,EPOLL_CTL_ADD,to_poll_events(flags),error);
			else if(events_[fd]!=flags)
				write_flag(fd,EPOLL_CTL_MOD,to_poll_events(flags),error);
			events_[fd]=flags;

		}

		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			struct epoll_event fds[128] = {};
			if (n >128) n=128;

			int size = 0;
			size = ::epoll_wait(pollfd_,fds,n,timeout);

			if(size < 0) {
				error = errno;
				return -1;
			}
			int read = 0;
			for(int i=0;i<size;i++) {
				events[read].events = to_user_events(fds[i].events);
				events[read].fd = fds[i].data.fd;
				read ++;
			}
			return read;
		}
	private:
		int to_poll_events(int event)
		{
			int pe=0;
			if(event & reactor::in)
				pe|=EPOLLIN;
			if(event & reactor::out)
				pe|=EPOLLOUT;
			return pe;
		}

		int to_user_events(int event)
		{
			int ue=0;
			if(event & EPOLLIN)
				ue|=reactor::in;
			if(event & EPOLLOUT)
				ue|=reactor::out;
			if(event & (EPOLLERR | EPOLLPRI | EPOLLHUP))
				ue|=reactor::err;
			return ue;
		}

		void write_flag(int fd,int op,int flags,int &error)
		{
			struct epoll_event efd=epoll_event();
			efd.events=flags;
			efd.data.fd=fd;

			if(::epoll_ctl(pollfd_,op,fd,&efd) < 0) {
				error=errno;
				return;
			}
		}
		int pollfd_;
	};
	#endif // epoll

	#if defined AIO_HAVE_POSIX_SELECT
	class select_reactor : public reactor_impl {
	public:
		std::string name() const { return "select"; }
		select_reactor() :
			map_(FD_SETSIZE,-1)
		{
		}
		virtual void select(native_type fd,int flags,int &error)
		{
			if(!check(fd,error))
				return;
			if(flags == 0) {
				remove(fd);
				return;
			}
			entry(fd).events=flags;
		}

		void remove(native_type fd)
		{
			if(fd >= int(map_.size()) || map_[fd]==-1)
				return;
			int index=map_[fd];
			std::swap(pollfds_[index],pollfds_.back());
			map_[pollfds_[index].fd]=index;
			pollfds_.resize(pollfds_.size()-1);
			map_[fd]=-1;
		}
		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			fd_set rd,wr,er;
			FD_ZERO(&rd);
			FD_ZERO(&wr);
			FD_ZERO(&er);
			int max_fd=0;
			for(unsigned i=0;i<pollfds_.size();i++) {
				int flags=pollfds_[i].events;
				int fd=pollfds_[i].fd;
				if(flags & reactor::in)
					FD_SET(fd,&rd);
				if(flags & reactor::out)
					FD_SET(fd,&wr);
				FD_SET(fd,&er);
				if(fd +1> max_fd)
					max_fd = fd+1;
			}
			struct timeval tv,*ptv=0;
			if(timeout >=0) {
				tv.tv_sec = timeout / 1000;
				tv.tv_usec = (timeout % 1000)*1000;
				ptv=&tv;
			}
			int read=::select(max_fd,&rd,&wr,&er,ptv);
			if(read < 0) {
				error=errno;
				return -1;
			}

			int count = 0;

			for(unsigned i=0;read > 0 && i < pollfds_.size() ;i++) {
				int fd=pollfds_[i].fd;
				bool r = FD_ISSET(fd,&rd);
				read-=int(r);
				bool w = FD_ISSET(fd,&wr);
				read-=int(w);
				bool e = FD_ISSET(fd,&er);
				read-=int(e);
				if(r || w || e) {
					if(count >=n) {
						count ++;
						continue;
					}
					reactor::event &ev=events[count];
					ev.fd = fd;
					ev.events=0;
					if(r)
						ev.events |= reactor::in;
					if(w)
						ev.events |= reactor::out;
					if(e)
						ev.events |= reactor::err;
					count++;
				}
			}
			return count;
		}
	private:
		bool check_exists(native_type fd,int &error)
		{
			if(!check(fd,error))
				return false;
			if(map_[fd]==-1) {
				error = ENOENT;
				return false;
			}
			return true;
		}
		bool check(native_type fd,int &error)
		{
			if(fd < 0 || fd>=native_type(FD_SETSIZE)) {
				error=EBADF;
				return false;
			}
			return true;

		}
		struct ev {
			int fd;
			int events;
		};

		ev &entry(native_type fd)
		{
			if(map_.size() <= unsigned(fd)) {
				map_.resize(fd+1,-1);
			}
			if(map_[fd]==-1) {
				map_[fd]=pollfds_.size();
				ev tmp=ev();
				tmp.fd=fd;
				pollfds_.push_back(tmp);
				return pollfds_.back();
			}
			return pollfds_[map_[fd]];

		}

		std::vector<int> map_;
		std::vector<ev> pollfds_;
	};
	#endif // POSIX_SELECT

	#ifdef AIO_HAVE_KQUEUE
	class kqueue_reactor : public reactor_impl, protected base_fast_reactor  {
	public:
		std::string name() const { return "kqueue"; }
		kqueue_reactor() :
			kev_(::kqueue())
		{
			if(kev_ < 0)
				throw system::system_error(errno,syscat,"Failed to create kqueue");
		}
		void select(int fd,int new_flags,int &error)
		{
			if(!check(fd,error))
				return;

			struct kevent evs

			int evs_count = 0;

			if((events_[fd] & reactor::in) && ! (new_flags & reactor::in)) {
				EV_SET(&evs[evs_count],fd,EVFILT_READ,EV_DELETE,0,0,0);
				evs_count++;
			}
			if((events_[fd] & reactor::out) && ! (new_flags & reactor::out)) {
				EV_SET(&evs[evs_count],fd,EVFILT_WRITE,EV_DELETE,0,0,0);
				evs_count++;
			}
			if(!(events_[fd] & reactor::in) && (new_flags & reactor::in)) {
				EV_SET(&evs[evs_count],fd,EVFILT_READ,EV_ADD,0,0,0);
				evs_count++;
			}
			if(!(events_[fd] & reactor::out) && (new_flags & reactor::out)) {
				EV_SET(&evs[evs_count],fd,EVFILT_WRITE,EV_ADD,0,0,0);
				evs_count++;
			}
			if(evs_count > 0) {
				if(::kevent(kev_,evs,evs_count,0,0,0) < 0) {
					error=errno;
					return;
				}
			}
			events_[fd]=new_flags;
		}

		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			struct kevent evs[128];
			struct timespec tv,*ptv=0;
			if(timeout >=0) {
				tv.tv_sec = timeout / 1000;
				tv.tv_nsec = (timeout % 1000)*1000000L;
				ptv=&tv;
			}
			int read=::kevent(kev_,0,0,evs,128,ptv);
			if(read < 0) {
				error=errno;
				return -1;
			}
			int count = 0;
			for(int i=0;i<read;i++) {
				if(evs[i].flags & EV_EOF)
					add(evs[i].ident,events,n,count,reactor::in);
				if(evs[i].flags & EV_ERROR)
					add(evs[i].ident,events,n,count,reactor::err);
				if(evs[i].filter == EVFILT_READ)
					add(evs[i].ident,events,n,count,reactor::in);
				if(evs[i].filter == EVFILT_WRITE)
					add(evs[i].ident,events,n,count,reactor::out);
			}

			return count;
		}
		virtual ~kqueue_reactor() { ::close(kev_); };
	private:
		void add(int fd,reactor::event *events,int n,int &count,int flags)
		{
			for(int i=0;i<count;i++) {
				if(events[i].fd==fd) {
					events[i].events|=flags;
					return;
				}
			}
			if(count < n) {
				events[count].fd=fd;
				events[count].events=flags;
				count++;
			}
		}

		int kev_;
	};
	#endif

	#if defined AIO_HAVE_WIN32_SELECT
	class w32_select_reactor : public reactor_impl {
	public:
		std::string name() const { return "select"; }
		w32_select_reactor()
		{
		}
		virtual void select(native_type fd,int flags,int &error)
		{
			if(fd==invalid_socket) {
				error=WSAEBADF;
				return;
			}
			if(flags==0)
				pollfds_.erase(fd);
			else
				pollfds_[fd]=flags;
		}

		void set(native_type fd,fd_set *s)
		{
			s->fd_array[s->fd_count++]=fd;
		}

		bool isset(native_type fd,fd_set *s)
		{
			return std::binary_search(s->fd_array,s->fd_array+s->fd_count,fd);
		}

		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			fd_set rd,wr,er;
			FD_ZERO(&rd);
			FD_ZERO(&wr);
			FD_ZERO(&er);
			int count=0;
			for(pollfds_type::iterator p=pollfds_.begin(),e=pollfds_.end();p!=e;++p) {
				int flags=p->second;
				native_type fd=p->first;
				if(flags==0)
					continue;
				count ++;
				if(count >= FD_SETSIZE) {
					error = WSAEINVAL;
					return -1;
				}
				if(flags & reactor::in)
					set(fd,&rd);
				if(flags & reactor::out)
					set(fd,&wr);
				set(fd,&er);
			}
			struct timeval tv,*ptv=0;
			if(timeout >=0) {
				tv.tv_sec = timeout / 1000;
				tv.tv_usec = (timeout % 1000)*1000;
				ptv=&tv;
			}

			int read=::select(0,&rd,&wr,&er,ptv);
			if(read < 0) {
				error=WSAGetLastError();
				return -1;
			}
			std::sort(rd.fd_array,rd.fd_array+rd.fd_count);
			std::sort(wr.fd_array,wr.fd_array+wr.fd_count);
			std::sort(er.fd_array,er.fd_array+er.fd_count);

			count = 0;

			for(pollfds_type::iterator p=pollfds_.begin(),end=pollfds_.end();read > 0 && p!=end;++p) {
				int fd=p->first;
				bool r = isset(fd,&rd);
				read-=int(r);
				bool w = isset(fd,&wr);
				read-=int(w);
				bool e = isset(fd,&er);
				read-=int(e);
				if(r || w || e) {
					if(count >=n) {
						count ++;
						continue;
					}
					reactor::event &ev=events[count];
					ev.fd = fd;
					ev.events=0;
					if(r)
						ev.events |= reactor::in;
					if(w)
						ev.events |= reactor::out;
					if(e)
						ev.events |= reactor::err;
					count++;
				}
			}
			return count;
		}
	private:
		typedef std::map<native_type,int> pollfds_type;
		pollfds_type pollfds_;
	};
	#endif // W32_SELECT

	#ifdef BOOSTER_WIN32
	namespace  {
		struct loader {
			loader() {
				WORD ver=MAKEWORD(2, 2);
				WSADATA data;
				if(WSAStartup(ver,&data) < 0) {
					throw booster::runtime_error("Failed to init winsock");
				}
			}
		} instance;
	}
	#endif

	#if defined _MSC_VER  && _MSC_VER  == 1600
	reactor::reactor(int /*hint*/)
	{
		impl_.reset(new w32_select_reactor());
	}
	#else // Normal compiler
	reactor::reactor(int hint)
	{
		static const int default_poll =
		#if defined AIO_HAVE_EPOLL
			use_epoll;
		#elif defined AIO_HAVE_DEVPOLL
			use_dev_poll;
		#elif defined AIO_HAVE_KQUEUE
			use_kqueue;
		#elif defined AIO_HAVE_POLL
			use_poll;
		#else
			use_select;
		#endif

		if(hint==use_default)
			hint=default_poll;

		for(;;) {
			switch(hint) {
			// select
			#if defined AIO_HAVE_POSIX_SELECT
			case use_select:
				impl_.reset(new select_reactor());
				return;
			#elif defined AIO_HAVE_WIN32_SELECT
			case use_select:
				impl_.reset(new w32_select_reactor());
				return;
			#endif
			// poll
			#if defined AIO_HAVE_POLL
			case use_poll:
				impl_.reset(new poll_reactor());
				return;
			#endif
			// epoll
			#if defined AIO_HAVE_EPOLL
			case use_epoll:
				impl_.reset(new epoll_reactor());
				return;
			#endif
			// devpoll
			#if defined AIO_HAVE_DEVPOLL
			case use_dev_poll:
				impl_.reset(new devpoll_reactor());
				return;
			#endif
			// kqueue
			#if defined AIO_HAVE_KQUEUE
			case use_kqueue:
				impl_.reset(new kqueue_reactor());
				return;
			#endif
			default:
				if(hint!=default_poll)
					hint=default_poll;
				else
					throw booster::runtime_error("Internal error - no poller found");
			}
		}
	}

	#endif

	reactor::~reactor() {}

	std::string reactor::name() const
	{
		return impl_->name();
	}

	void reactor::select(native_type fd,int flags)
	{
		system::error_code e;
		select(fd,flags,e);
		if(e) throw system::system_error(e);
	}

	void reactor::select(native_type fd,int flags,system::error_code &e)
	{
		int error = 0;
		impl_->select(fd,flags,error);
		if(error)
			e=system::error_code(error,syscat);
	}

	int reactor::poll(reactor::event *events,int n,int timeout)
	{
		system::error_code e;
		int r=poll(events,n,timeout,e);
		if(e)
			throw system::system_error(e);
		return r;
	}

	int reactor::poll(reactor::event *events,int n,int timeout,system::error_code &e)
	{
		int error = 0;
		int r=impl_->poll(events,n,timeout,error);
		if(error)
			e=system::error_code(error,syscat);
		return r;
	}

} // aio
} // booster


for(int i=0;i<read;i++) {
				if(evs[i].flags & EV_EOF)
					add(evs[i].ident,events,n,count,reactor::in);
				if(evs[i].flags & EV_ERROR)
					add(evs[i].ident,events,n,count,reactor::err);
				if(evs[i].filter == EVFILT_READ)
					add(evs[i].ident,events,n,count,reactor::in);
				if(evs[i].filter == EVFILT_WRITE)
					add(evs[i].ident,events,n,count,reactor::out);
			}

#define BOOSTER_SOURCE

#include "reactor_config.h"

#include <string.h>

#ifdef AIO_HAVE_POSIX_SELECT
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>
#include <unistd.h>
#endif

#if defined AIO_HAVE_WIN32_SELECT || defined AIO_HAVE_WSAPOLL
#undef FD_SETSIZE
#define FD_SETSIZE 1024
#include <winsock2.h>
#include <map>
#include <algorithm>
#endif

#ifdef AIO_HAVE_POLL
#include <poll.h>
#include <unistd.h>
#endif
#ifdef AIO_HAVE_DEVPOLL
#include <sys/devpoll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif

#ifdef AIO_HAVE_EPOLL
#include <sys/epoll.h>
#include <unistd.h>
#endif

#ifdef AIO_HAVE_KQUEUE
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#endif

#include <booster/aio/reactor.h>
#include <booster/system_error.h>

#include <vector>
#include <iostream>

#include "category.h"

namespace booster {
namespace aio {
	class reactor_impl {
	public:
		virtual void select(native_type fd,int flags,int &error) = 0;
		virtual int poll(reactor::event *events,int n,int timeout,int &error) = 0;
		virtual std::string name() const = 0;
		virtual ~reactor_impl() {};
	};

	#if defined AIO_HAVE_POLL  || defined AIO_HAVE_DEVPOLL
	class base_poll_reactor : public reactor_impl {
	protected:
		int to_poll_events(int event)
		{
			int pe=0;
			if(event & reactor::in)
				pe|=POLLIN;
			if(event & reactor::out)
				pe|=POLLOUT;
			return pe;
		}
		int to_user_events(int event)
		{
			int ue=0;
			if(event & POLLIN)
				ue|=reactor::in;
			if(event & POLLOUT)
				ue|=reactor::out;
			if(event & (POLLERR | POLLHUP | POLLPRI))
				ue|=reactor::err;
			return ue;
		}
	};
	#endif

	#ifdef AIO_HAVE_POLL

	class poll_reactor : public base_poll_reactor {
	public:
		std::string name() const { return "poll"; }
		virtual void select(native_type fd,int flags,int &error)
		{
			if(!check(fd,error))
				return;
			if(flags == 0) {
				remove(fd);
				return;
			}
			entry(fd).events=to_poll_events(flags);
		}

		struct pollfd &entry(native_type fd)
		{
			if(map_.size() <= unsigned(fd)) {
				map_.resize(fd+1,-1);
			}
			if(map_[fd]==-1) {
				map_[fd]=pollfds_.size();
				pollfd tmp=pollfd();
				tmp.fd=fd;
				pollfds_.push_back(tmp);
			}
			return pollfds_[map_[fd]];

		}

		void remove(native_type fd)
		{
			if(fd >= int(map_.size()) || map_[fd]==-1)
				return;

			int index=map_[fd];
			std::swap(pollfds_[index],pollfds_.back());
			map_[pollfds_[index].fd]=index;
			pollfds_.resize(pollfds_.size()-1);
			map_[fd]=-1;
		}

		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			struct pollfd *pfd = pollfds_.size() > 0 ? &pollfds_.front() : 0;
			int size = pollfds_.size();

			int count = ::poll(pfd,size,timeout);
			if(count < 0)
				error = errno;
			int read=0;
			for(unsigned i=0;i<pollfds_.size() && read < count && read < n;i++) {
				if(pollfds_[i].revents == POLLNVAL) {
					remove(pollfds_[i].fd);
					count --;
					continue;
				}
				if(pollfds_[i].revents != 0) {
					events[read].events = to_user_events(pollfds_[i].revents);
					events[read].fd = pollfds_[i].fd;
					read ++;
				}
			}
			return read;
		}
	private:
		bool check(native_type fd,int &error)
		{
			if(fd < 0) {
				error=EBADF;
				return false;
			}
			return true;
		}
		std::vector<int> map_;
		std::vector< ::pollfd> pollfds_;
	};

	#endif // poll

	#if defined(AIO_HAVE_DEVPOLL) || defined(AIO_HAVE_EPOLL) || defined(AIO_HAVE_KQUEUE)
	class base_fast_reactor {
	protected:
		bool check(int fd,int &error)
		{
			if(fd < 0) {
				error=EINVAL;
				return false;
			}
			if(fd >= int(events_.size())) {
				events_.resize(fd+1,0);
			}
			return true;
		}

		std::vector<int> events_;
	};

	#endif

	#ifdef AIO_HAVE_DEVPOLL

	class devpoll_reactor : public base_poll_reactor, protected base_fast_reactor {
	public:
		std::string name() const { return "devpoll"; }

		devpoll_reactor()
		{
			pollfd_=::open("/dev/poll",O_RDWR);
			if(!pollfd_)
				throw system::system_error(errno,syscat,"Failed to open /dev/poll");
		}

		virtual ~devpoll_reactor()
		{
			::close(pollfd_);
		}
		virtual void select(native_type fd,int flags,int &error)
		{
			if(!check(fd,error))
				return;
			struct pollfd evs[2] = {0};
			int evs_count = 0;
			if(flags == events_[fd])
				return;

			if(events_[fd]) {
				evs[evs_count].fd=fd;
				evs[evs_count].events=POLLREMOVE;
				evs_count++;
			}
			if(flags!=0) {
				evs[evs_count].fd=fd;
				evs[evs_count].events=to_poll_events(flags);
				evs_count++;
			}
			if(evs_count > 0) {
				int size = sizeof(evs[0])*evs_count;
				if(::write(pollfd_,evs,size)!=size) {
					error=errno;
					return;
				}
			}
			events_[fd]=flags;
		}

		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			struct pollfd fds[128] = {{0}};
			struct dvpoll dvp={0};
			dvp.dp_timeout = timeout;
			dvp.dp_nfds = n > 128 ? 128 : n;
			dvp.dp_fds=fds;

			int size = ::ioctl(pollfd_,DP_POLL,&dvp);

			if(size < 0) {
				error = errno;
				return -1;
			}
			int read = 0;
			for(int i=0;i<size;i++) {
				events[read].events = to_user_events(fds[i].revents);
				events[read].fd = fds[i].fd;
				read ++;
			}
			return read;
		}
	private:

		int pollfd_;
	};

	#endif // /dev/poll

	#ifdef AIO_HAVE_EPOLL
	class epoll_reactor : public base_poll_reactor, public base_fast_reactor {
	public:
		std::string name() const { return "epoll"; }

		epoll_reactor()
		{
			pollfd_=::epoll_create(16);
			if(!pollfd_)
				throw system::system_error(errno,syscat,"Failed to create epoll descriptor");
		}
		virtual ~epoll_reactor()
		{
			::close(pollfd_);
		}
		virtual void select(native_type fd,int flags,int &error)
		{
			if(!check(fd,error))
				return;
			if(events_[fd]!=0 && flags==0)
				write_flag(fd,EPOLL_CTL_DEL,0,error);
			else if(events_[fd]==0 && flags!=0)
				write_flag(fd,EPOLL_CTL_ADD,to_poll_events(flags),error);
			else if(events_[fd]!=flags)
				write_flag(fd,EPOLL_CTL_MOD,to_poll_events(flags),error);
			events_[fd]=flags;

		}

		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			struct epoll_event fds[128] = {};
			if (n >128) n=128;

			int size = 0;
			size = ::epoll_wait(pollfd_,fds,n,timeout);

			if(size < 0) {
				error = errno;
				return -1;
			}
			int read = 0;
			for(int i=0;i<size;i++) {
				events[read].events = to_user_events(fds[i].events);
				events[read].fd = fds[i].data.fd;
				read ++;
			}
			return read;
		}
	private:
		int to_poll_events(int event)
		{
			int pe=0;
			if(event & reactor::in)
				pe|=EPOLLIN;
			if(event & reactor::out)
				pe|=EPOLLOUT;
			return pe;
		}

		int to_user_events(int event)
		{
			int ue=0;
			if(event & EPOLLIN)
				ue|=reactor::in;
			if(event & EPOLLOUT)
				ue|=reactor::out;
			if(event & (EPOLLERR | EPOLLPRI | EPOLLHUP))
				ue|=reactor::err;
			return ue;
		}

		void write_flag(int fd,int op,int flags,int &error)
		{
			struct epoll_event efd=epoll_event();
			efd.events=flags;
			efd.data.fd=fd;

			if(::epoll_ctl(pollfd_,op,fd,&efd) < 0) {
				error=errno;
				return;
			}
		}
		int pollfd_;
	};
	#endif // epoll

	#if defined AIO_HAVE_POSIX_SELECT
	class select_reactor : public reactor_impl {
	public:
		std::string name() const { return "select"; }
		select_reactor() :
			map_(FD_SETSIZE,-1)
		{
		}
		virtual void select(native_type fd,int flags,int &error)
		{
			if(!check(fd,error))
				return;
			if(flags == 0) {
				remove(fd);
				return;
			}
			entry(fd).events=flags;
		}

		void remove(native_type fd)
		{
			if(fd >= int(map_.size()) || map_[fd]==-1)
				return;
			int index=map_[fd];
			std::swap(pollfds_[index],pollfds_.back());
			map_[pollfds_[index].fd]=index;
			pollfds_.resize(pollfds_.size()-1);
			map_[fd]=-1;
		}
		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			fd_set rd,wr,er;
			FD_ZERO(&rd);
			FD_ZERO(&wr);
			FD_ZERO(&er);
			int max_fd=0;
			for(unsigned i=0;i<pollfds_.size();i++) {
				int flags=pollfds_[i].events;
				int fd=pollfds_[i].fd;
				if(flags & reactor::in)
					FD_SET(fd,&rd);
				if(flags & reactor::out)
					FD_SET(fd,&wr);
				FD_SET(fd,&er);
				if(fd +1> max_fd)
					max_fd = fd+1;
			}
			struct timeval tv,*ptv=0;
			if(timeout >=0) {
				tv.tv_sec = timeout / 1000;
				tv.tv_usec = (timeout % 1000)*1000;
				ptv=&tv;
			}
			int read=::select(max_fd,&rd,&wr,&er,ptv);
			if(read < 0) {
				error=errno;
				return -1;
			}

			int count = 0;

			for(unsigned i=0;read > 0 && i < pollfds_.size() ;i++) {
				int fd=pollfds_[i].fd;
				bool r = FD_ISSET(fd,&rd);
				read-=int(r);
				bool w = FD_ISSET(fd,&wr);
				read-=int(w);
				bool e = FD_ISSET(fd,&er);
				read-=int(e);
				if(r || w || e) {
					if(count >=n) {
						count ++;
						continue;
					}
					reactor::event &ev=events[count];
					ev.fd = fd;
					ev.events=0;
					if(r)
						ev.events |= reactor::in;
					if(w)
						ev.events |= reactor::out;
					if(e)
						ev.events |= reactor::err;
					count++;
				}
			}
			return count;
		}
	private:
		bool check_exists(native_type fd,int &error)
		{
			if(!check(fd,error))
				return false;
			if(map_[fd]==-1) {
				error = ENOENT;
				return false;
			}
			return true;
		}
		bool check(native_type fd,int &error)
		{
			if(fd < 0 || fd>=native_type(FD_SETSIZE)) {
				error=EBADF;
				return false;
			}
			return true;

		}
		struct ev {
			int fd;
			int events;
		};

		ev &entry(native_type fd)
		{
			if(map_.size() <= unsigned(fd)) {
				map_.resize(fd+1,-1);
			}
			if(map_[fd]==-1) {
				map_[fd]=pollfds_.size();
				ev tmp=ev();
				tmp.fd=fd;
				pollfds_.push_back(tmp);
				return pollfds_.back();
			}
			return pollfds_[map_[fd]];

		}

		std::vector<int> map_;
		std::vector<ev> pollfds_;
	};
	#endif // POSIX_SELECT

	#ifdef AIO_HAVE_KQUEUE
	class kqueue_reactor : public reactor_impl, protected base_fast_reactor  {
	public:
		std::string name() const { return "kqueue"; }
		kqueue_reactor() :
			kev_(::kqueue())
		{
			if(kev_ < 0)
				throw system::system_error(errno,syscat,"Failed to create kqueue");
		}
		void select(int fd,int new_flags,int &error)
		{
			if(!check(fd,error))
				return;

			struct kevent evs[2];
			int evs_count = 0;

			if((events_[fd] & reactor::in) && ! (new_flags & reactor::in)) {
				EV_SET(&evs[evs_count],fd,EVFILT_READ,EV_DELETE,0,0,0);
				evs_count++;
			}
			if((events_[fd] & reactor::out) && ! (new_flags & reactor::out)) {
				EV_SET(&evs[evs_count],fd,EVFILT_WRITE,EV_DELETE,0,0,0);
				evs_count++;
			}
			if(!(events_[fd] & reactor::in) && (new_flags & reactor::in)) {
				EV_SET(&evs[evs_count],fd,EVFILT_READ,EV_ADD,0,0,0);
				evs_count++;
			}
			if(!(events_[fd] & reactor::out) && (new_flags & reactor::out)) {
				EV_SET(&evs[evs_count],fd,EVFILT_WRITE,EV_ADD,0,0,0);
				evs_count++;
			}
			if(evs_count > 0) {
				if(::kevent(kev_,evs,evs_count,0,0,0) < 0) {
					error=errno;
					return;
				}
			}
			events_[fd]=new_flags;
		}

		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			struct kevent evs[128];
			struct timespec tv,*ptv=0;
			if(timeout >=0) {
				tv.tv_sec = timeout / 1000;
				tv.tv_nsec = (timeout % 1000)*1000000L;
				ptv=&tv;
			}
			int read=::kevent(kev_,0,0,evs,128,ptv);
			if(read < 0) {
				error=errno;
				return -1;
			}
			int count = 0;

			return count;
		}
		virtual ~kqueue_reactor() { ::close(kev_); };
	private:
		void add(int fd,reactor::event *events,int n,int &count,int flags)
		{
			for(int i=0;i<count;i++) {
				if(events[i].fd==fd) {
					events[i].events|=flags;
					return;
				}
			}
			if(count < n) {
				events[count].fd=fd;
				events[count].events=flags;
				count++;
			}
		}

		int kev_;
	};
	#endif

	#if defined AIO_HAVE_WIN32_SELECT
	class w32_select_reactor : public reactor_impl {
	public:
		std::string name() const { return "select"; }
		w32_select_reactor()
		{
		}
		virtual void select(native_type fd,int flags,int &error)
		{
			if(fd==invalid_socket) {
				error=WSAEBADF;
				return;
			}
			if(flags==0)
				pollfds_.erase(fd);
			else
				pollfds_[fd]=flags;
		}

		void set(native_type fd,fd_set *s)
		{
			s->fd_array[s->fd_count++]=fd;
		}

		bool isset(native_type fd,fd_set *s)
		{
			return std::binary_search(s->fd_array,s->fd_array+s->fd_count,fd);
		}

		virtual int poll(reactor::event *events,int n,int timeout,int &error)
		{
			fd_set rd,wr,er;
			FD_ZERO(&rd);
			FD_ZERO(&wr);
			FD_ZERO(&er);
			int count=0;
			for(pollfds_type::iterator p=pollfds_.begin(),e=pollfds_.end();p!=e;++p) {
				int flags=p->second;
				native_type fd=p->first;
				if(flags==0)
					continue;
				count ++;
				if(count >= FD_SETSIZE) {
					error = WSAEINVAL;
					return -1;
				}
				if(flags & reactor::in)
					set(fd,&rd);
				if(flags & reactor::out)
					set(fd,&wr);
				set(fd,&er);
			}
			struct timeval tv,*ptv=0;
			if(timeout >=0) {
				tv.tv_sec = timeout / 1000;
				tv.tv_usec = (timeout % 1000)*1000;
				ptv=&tv;
			}

			int read=::select(0,&rd,&wr,&er,ptv);
			if(read < 0) {
				error=WSAGetLastError();
				return -1;
			}
			std::sort(rd.fd_array,rd.fd_array+rd.fd_count);
			std::sort(wr.fd_array,wr.fd_array+wr.fd_count);
			std::sort(er.fd_array,er.fd_array+er.fd_count);

			count = 0;

			for(pollfds_type::iterator p=pollfds_.begin(),end=pollfds_.end();read > 0 && p!=end;++p) {
				int fd=p->first;
				bool r = isset(fd,&rd);
				read-=int(r);
				bool w = isset(fd,&wr);
				read-=int(w);
				bool e = isset(fd,&er);
				read-=int(e);
				if(r || w || e) {
					if(count >=n) {
						count ++;
						continue;
					}
					reactor::event &ev=events[count];
					ev.fd = fd;
					ev.events=0;
					if(r)
						ev.events |= reactor::in;
					if(w)
						ev.events |= reactor::out;
					if(e)
						ev.events |= reactor::err;
					count++;
				}
			}
			return count;
		}
	private:
		typedef std::map<native_type,int> pollfds_type;
		pollfds_type pollfds_;
	};
	#endif // W32_SELECT

	#ifdef BOOSTER_WIN32
	namespace  {
		struct loader {
			loader() {
				WORD ver=MAKEWORD(2, 2);
				WSADATA data;
				if(WSAStartup(ver,&data) < 0) {
					throw booster::runtime_error("Failed to init winsock");
				}
			}
		} instance;
	}
	#endif

	#if defined _MSC_VER  && _MSC_VER  == 1600
	reactor::reactor(int /*hint*/)
	{
		impl_.reset(new w32_select_reactor());
	}
	#else // Normal compiler
	reactor::reactor(int hint)
	{
		static const int default_poll =
		#if defined AIO_HAVE_EPOLL
			use_epoll;
		#elif defined AIO_HAVE_DEVPOLL
			use_dev_poll;
		#elif defined AIO_HAVE_KQUEUE
			use_kqueue;
		#elif defined AIO_HAVE_POLL
			use_poll;
		#else
			use_select;
		#endif

		if(hint==use_default)
			hint=default_poll;

		for(;;) {
			switch(hint) {
			// select
			#if defined AIO_HAVE_POSIX_SELECT
			case use_select:
				impl_.reset(new select_reactor());
				return;
			#elif defined AIO_HAVE_WIN32_SELECT
			case use_select:
				impl_.reset(new w32_select_reactor());
				return;
			#endif
			// poll
			#if defined AIO_HAVE_POLL
			case use_poll:
				impl_.reset(new poll_reactor());
				return;
			#endif
			// epoll
			#if defined AIO_HAVE_EPOLL
			case use_epoll:
				impl_.reset(new epoll_reactor());
				return;
			#endif
			// devpoll
			#if defined AIO_HAVE_DEVPOLL
			case use_dev_poll:
				impl_.reset(new devpoll_reactor());
				return;
			#endif
			// kqueue
			#if defined AIO_HAVE_KQUEUE
			case use_kqueue:
				impl_.reset(new kqueue_reactor());
				return;
			#endif
			default:
				if(hint!=default_poll)
					hint=default_poll;
				else
					throw booster::runtime_error("Internal error - no poller found");
			}
		}
	}

	#endif

	reactor::~reactor() {}

	std::string reactor::name() const
	{
		return impl_->name();
	}

	void reactor::select(native_type fd,int flags)
	{
		system::error_code e;
		select(fd,flags,e);
		if(e) throw system::system_error(e);
	}

	void reactor::select(native_type fd,int flags,system::error_code &e)
	{
		int error = 0;
		impl_->select(fd,flags,error);
		if(error)
			e=system::error_code(error,syscat);
	}

	int reactor::poll(reactor::event *events,int n,int timeout)
	{
		system::error_code e;
		int r=poll(events,n,timeout,e);
		if(e)
			throw system::system_error(e);
		return r;
	}

	int reactor::poll(reactor::event *events,int n,int timeout,system::error_code &e)
	{
		int error = 0;
		int r=impl_->poll(events,n,timeout,error);
		if(error)
			e=system::error_code(error,syscat);
		return r;
	}

} // aio
} // booster


/*

*/
#include "oneflow/xrt/xla/ops/op_context.h"
#include "oneflow/xrt/xla/ops/op_kernel.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"

#include "oneflow/xrt/xla/xla_helpers.h"

namespace oneflow {
namespace xrt {
namespace mola {

class ReshapeOp : public XlaOpKernel {
 public:
  void Compile(XlaOpContext* ctx) override {
    Shape in_shape = ctx->SoleInputShape();
    Shape shape = ctx->SoleOutputShape();
    CHECK_EQ(shape.Count(0), in_shape.Count(0));

    ctx->SetSoleOutput(Reshape(ctx->SoleInput(), shape));
  }
};

REGISTER_XLA_OP_KERNEL(Reshape, ReshapeOp).Finalize();

class ReshapeLikeOp : public XlaOpKernel {
 public:

{
    Shape x_shape = ctx->InputShape("in_0");
    Shape like_shape = ctx->InputShape("like_0");
    CHECK_EQ(x_shape.Count(0), like_shape.Count(0));

    ctx->SetOutput("out_0", Reshape(ctx->Input("in_0"), like_shape));
  }
};

REGISTER_XLA_OP_KERNEL(ReshapeLike, ReshapeLikeOp).Finalize();

}  // namespace mola
}  // namespace xrt
}  // namespace oneflow


{
    Shape x_shape = ctx->InputShape("in_0");
    Shape like_shape = ctx->InputShape("like_0");
    CHECK_EQ(x_shape.Count(0), like_shape.Count(0));

    ctx->SetOutput("out_0", Reshape(ctx->Input("in_0"), like_shape));
  }

/*

*/
#include "oneflow/xrt/xla/ops/op_context.h"
#include "oneflow/xrt/xla/ops/op_kernel.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"

#include "oneflow/xrt/xla/xla_helpers.h"

namespace oneflow {
namespace xrt {
namespace mola {

class ReshapeOp : public XlaOpKernel {
 public:
  void Compile(XlaOpContext* ctx) override {
    Shape in_shape = ctx->SoleInputShape();
    Shape shape = ctx->SoleOutputShape();
    CHECK_EQ(shape.Count(0), in_shape.Count(0));

    ctx->SetSoleOutput(Reshape(ctx->SoleInput(), shape));
  }
};

REGISTER_XLA_OP_KERNEL(Reshape, ReshapeOp).Finalize();

class ReshapeLikeOp : public XlaOpKernel {
 public:
  void Compile(XlaOpContext* ctx) override

};

REGISTER_XLA_OP_KERNEL(ReshapeLike, ReshapeLikeOp).Finalize();

}  // namespace mola
}  // namespace xrt
}  // namespace oneflow


/*

*/
#include "oneflow/xrt/xla/ops/op_context.h"
#include "oneflow/xrt/xla/ops/op_kernel.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"

#include "oneflow/xrt/xla/xla_helpers.h"

namespace oneflow {
namespace xrt {
namespace mola {

class ReshapeOp : public XlaOpKernel {
 public:
  void Compile(XlaOpContext* ctx) override {
    Shape in_shape = ctx->SoleInputShape();
    Shape shape = ctx->SoleOutputShape();
    CHECK_EQ(shape.Count(0), in_sh

    ctx->SetSoleOutput(Reshape(ctx->SoleInput(), shape));
  }
};

REGISTER_XLA_OP_KERNEL(Reshape, ReshapeOp).Finalize();

class ReshapeLikeOp : public XlaOpKernel {
 public:
  void Compile(XlaOpContext* ctx) override {
    Shape x_shape = ctx->InputShape("in_0");
    Shape like_shape = ctx->InputShape("like_0");
    CHECK_EQ(x_shape.Count(0), like_shape.Count(0));

    ctx->SetOutput("out_0", Reshape(ctx->Input("in_0"), like_shape));
  }
};

REGISTER_XLA_OP_KERNEL(ReshapeLike, ReshapeLikeOp).Finalize();

}  // namespace mola
}  // namespace xrt
}  // namespace oneflow


/*
 *
 * Author:     gongheng<example@nnthink.com>
 *
 * Maintainer: gongheng<gongheng@uniontech.com>
 *
 */

#include "models/dfmrootfileinfo.h"
#include "stub.h"
#include "app/define.h"
#include "dfileservices.h"
#include "testhelper.h"

#include <gtest/gtest.h>
#include <QLineEdit>
#include <QComboBox>
#include <QCheckBox>

#define private public
#include "dialogs/shareinfoframe.h"

namespace  {
    class TestShareInfoFrame : public testing::Test
    {
    public:
        void SetUp() override
        {
            QString strPath = QDir::currentPath() + QDir::separator() + "TestPropertyDialog.txt";
            QFile file(strPath);
            if(!file.exists()){
                if(file.open(QIODevice::ReadWrite | QIODevice::Text))
                    file.close();
            }
            DAbstractFileInfoPointer fi(new DFMRootFileInfo(DUrl("file:///test1")));;
            m_pTester = new ShareInfoFrame(fi);
            std::cout << "start TestShareInfoFrame";
        }
        void TearDown() override
        {
            QString strPath = QDir::currentPath() + QDir::separator() + "TestPropertyDialog.txt";
            QFile file(strPath);
            if(file.exists()){
                file.remove();
            }
            QString strPath2 = QDir::currentPath() + QDir::separator() + "TestPropertyDialog.txt.txt";
            QFile file2(strPath2);
            if(file2.exists()){
                file2.remove();
            }
            delete m_pTester;
            m_pTester = nullptr;
            std::cout << "end TestShareInfoFrame";
        }
    public:
        ShareInfoFrame  *m_pTester;
    };
}

TEST_F(TestShareInfoFrame, testInit)
{
    EXPECT_NE(m_pTester, nullptr);
}

TEST_F(TestShareInfoFrame, testSetFileinfo)
{
    DAbstractFileInfoPointer fileinfo(new DFMRootFileInfo(DUrl("file:///test1")));
    m_pTester->setFileinfo(fileinfo);
    QString str = m_pTester->m_fileinfo->path();
    EXPECT_TRUE(str == "");
}

TEST_F(TestShareInfoFrame, testCheckShareName)
{
    QString(*stub_fileName)() = []()->QString{
        return QString("sharenameedit");
    };
    Stub stu;
    stu.set(ADDR(QFileInfo, fileName), stub_fileName);

    EXPECT_TRUE(m_pTester->checkShareName());
}

TEST_F(TestShareInfoFrame, testHandleCheckBoxChanged)
{
    m_pTester->handleCheckBoxChanged(false);
    bool b = m_pTester->m_shareCheckBox->isEnabled();
    EXPECT_EQ(b, false);
}

TEST_F(TestShareInfoFrame, testHandleCheckBoxChanged2)
{
    m_pTester->handleCheckBoxChanged(true);
    bool b = m_pTester->m_shareCheckBox->isEnabled();
    EXPECT_EQ(b, false);
}

TEST_F(TestShareInfoFrame, testHandleCheckBoxChanged3)
{
    bool(*stub_doShareInfoSetting)() = []()->bool{
        return false;
    };
    Stub stu;
    stu.set(ADDR(ShareInfoFrame, doShareInfoSetting), stub_doShareInfoSetting);
    m_pTester->handleCheckBoxChanged(true);
    bool b = m_pTester->m_shareCheckBox->isEnabled();
    EXPECT_EQ(b, false);
}

TEST_F(TestShareInfoFrame, testHandleShareNameFinished)
{
    EXPECT_NO_FATAL_FAILURE(m_pTester->handleShareNameFinished());
}

TEST_F(TestShareInfoFrame, testHandleShareNameFinished2)
{
    QLineEdit *pShareNamelineEdit = new QLineEdit();
    m_pTester->m_shareNamelineEdit = pShareNamelineEdit;
    pShareNamelineEdit->setFocus();
    QComboBox *pPermissoComBox = new QComboBox();
    m_pTester->m_permissoComBox = pPermissoComBox;

    bool(*stub_hasFocus)() = []()->bool{
            return  true;
    };
    Stub stu;
    stu.set(ADDR(QWidget, hasFocus), stub_hasFocus);

    EXPECT_NO_FATAL_FAILURE(m_pTester->handleShareNameFinished());

    if (pShareNamelineEdit)
        pShareNamelineEdit->deleteLater();
    if (pPermissoComBox)
        pPermissoComBox->deleteLater();

}

TEST_F(TestShareInfoFrame, testHandleShareNameChinged)
{
    QLineEdit shareNamelineEdit;
    m_pTester->m_shareNamelineEdit = &shareNamelineEdit;
    EXPECT_NO_FATAL_FAILURE(m_pTester->handleShareNameChanged(" 123"));
}

TEST_F(TestShareInfoFrame, testHandlePermissionComboxChanged)
{
    EXPECT_NO_FATAL_FAILURE(m_pTester->handlePermissionComboxChanged(1));
}

TEST_F(TestShareInfoFrame, testHandleAnonymityComboxChanged)
{
    EXPECT_NO_FATAL_FAILURE(m_pTester->handleAnonymityComboxChanged(1));
}

{

}

TEST_F(TestShareInfoFrame, testDisactivateWidgets)
{
    m_pTester->disactivateWidgets();
    bool b = m_pTester->m_permissoComBox->isEditable();
    EXPECT_EQ(b, false);
}
#ifndef __arm__
TEST_F(TestShareInfoFrame, testDoShareInfoSetting)
{
    m_pTester->m_shareCheckBox->setChecked(true);
    m_pTester->m_permissoComBox->setCurrentIndex(0);
    m_pTester->m_anonymityCombox->setCurrentIndex(1);
    bool b = m_pTester->doShareInfoSetting();
    EXPECT_EQ(b, false);
}
#endif
TEST_F(TestShareInfoFrame, testUpdateShareInfo)
{
    TestHelper::runInLoop([](){});

    DAbstractFileInfoPointer fileinfo = fileService->createFileInfo(nullptr, DUrl("file:///home"));
    m_pTester->m_fileinfo = fileinfo;

    bool(*stub_isEmpty)() = []()->bool{
        return false;
    };
    Stub stu;
    stu.set(ADDR(QString, isEmpty), stub_isEmpty);

    m_pTester->updateShareInfo("/home");
    bool b = m_pTester->m_shareCheckBox->isEnabled();
    EXPECT_EQ(b, false);
}

TEST_F(TestShareInfoFrame, testActivateWidgets)
{
    QComboBox box;
    m_pTester->m_permissoComBox = &box;
    QComboBox box2;
    m_pTester->m_anonymityCombox = &box2;
    m_pTester->activateWidgets();
    bool b = m_pTester->m_permissoComBox->isEnabled();
    EXPECT_EQ(b, true);
}


{
    DAbstractFileInfoPointer fileinfo(new DFMRootFileInfo(DUrl("file:///test1")));
    m_pTester->setFileinfo(fileinfo);
    QString str = m_pTester->m_fileinfo->path();
    EXPECT_TRUE(str == "");
}

/*
 *
 * Author:     gongheng<example@nnthink.com>
 *
 * Maintainer: gongheng<gongheng@uniontech.com>
 *
 */

#include "models/dfmrootfileinfo.h"
#include "stub.h"
#include "app/define.h"
#include "dfileservices.h"
#include "testhelper.h"

#include <gtest/gtest.h>
#include <QLineEdit>
#include <QComboBox>
#include <QCheckBox>

#define private public
#include "dialogs/shareinfoframe.h"

namespace  {
    class TestShareInfoFrame : public testing::Test
    {
    public:
        void SetUp() override
        {
            QString strPath = QDir::currentPath() + QDir::separator() + "TestPropertyDialog.txt";
            QFile file(strPath);
            if(!file.exists()){
                if(file.open(QIODevice::ReadWrite | QIODevice::Text))
                    file.close();
            }
            DAbstractFileInfoPointer fi(new DFMRootFileInfo(DUrl("file:///test1")));;
            m_pTester = new ShareInfoFrame(fi);
            std::cout << "start TestShareInfoFrame";
        }
        void TearDown() override
        {
            QString strPath = QDir::currentPath() + QDir::separator() + "TestPropertyDialog.txt";
            QFile file(strPath);
            if(file.exists()){
                file.remove();
            }
            QString strPath2 = QDir::currentPath() + QDir::separator() + "TestPropertyDialog.txt.txt";
            QFile file2(strPath2);
            if(file2.exists()){
                file2.remove();
            }
            delete m_pTester;
            m_pTester = nullptr;
            std::cout << "end TestShareInfoFrame";
        }
    public:
        ShareInfoFrame  *m_pTester;
    };
}

TEST_F(TestShareInfoFrame, testInit)
{
    EXPECT_NE(m_pTester, nullptr);
}

TEST_F(TestShareInfoFrame, testSetFileinfo)

TEST_F(TestShareInfoFrame, testCheckShareName)
{
    QString(*stub_fileName)() = []()->QString{
        return QString("sharenameedit");
    };
    Stub stu;
    stu.set(ADDR(QFileInfo, fileName), stub_fileName);

    EXPECT_TRUE(m_pTester->checkShareName());
}

TEST_F(TestShareInfoFrame, testHandleCheckBoxChanged)
{
    m_pTester->handleCheckBoxChanged(false);
    bool b = m_pTester->m_shareCheckBox->isEnabled();
    EXPECT_EQ(b, false);
}

TEST_F(TestShareInfoFrame, testHandleCheckBoxChanged2)
{
    m_pTester->handleCheckBoxChanged(true);
    bool b = m_pTester->m_shareCheckBox->isEnabled();
    EXPECT_EQ(b, false);
}

TEST_F(TestShareInfoFrame, testHandleCheckBoxChanged3)
{
    bool(*stub_doShareInfoSetting)() = []()->bool{
        return false;
    };
    Stub stu;
    stu.set(ADDR(ShareInfoFrame, doShareInfoSetting), stub_doShareInfoSetting);
    m_pTester->handleCheckBoxChanged(true);
    bool b = m_pTester->m_shareCheckBox->isEnabled();
    EXPECT_EQ(b, false);
}

TEST_F(TestShareInfoFrame, testHandleShareNameFinished)
{
    EXPECT_NO_FATAL_FAILURE(m_pTester->handleShareNameFinished());
}

TEST_F(TestShareInfoFrame, testHandleShareNameFinished2)
{
    QLineEdit *pShareNamelineEdit = new QLineEdit();
    m_pTester->m_shareNamelineEdit = pShareNamelineEdit;
    pShareNamelineEdit->setFocus();
    QComboBox *pPermissoComBox = new QComboBox();
    m_pTester->m_permissoComBox = pPermissoComBox;

    bool(*stub_hasFocus)() = []()->bool{
            return  true;
    };
    Stub stu;
    stu.set(ADDR(QWidget, hasFocus), stub_hasFocus);

    EXPECT_NO_FATAL_FAILURE(m_pTester->handleShareNameFinished());

    if (pShareNamelineEdit)
        pShareNamelineEdit->deleteLater();
    if (pPermissoComBox)
        pPermissoComBox->deleteLater();

}

TEST_F(TestShareInfoFrame, testHandleShareNameChinged)
{
    QLineEdit shareNamelineEdit;
    m_pTester->m_shareNamelineEdit = &shareNamelineEdit;
    EXPECT_NO_FATAL_FAILURE(m_pTester->handleShareNameChanged(" 123"));
}

TEST_F(TestShareInfoFrame, testHandlePermissionComboxChanged)
{
    EXPECT_NO_FATAL_FAILURE(m_pTester->handlePermissionComboxChanged(1));
}

TEST_F(TestShareInfoFrame, testHandleAnonymityComboxChanged)
{
    EXPECT_NO_FATAL_FAILURE(m_pTester->handleAnonymityComboxChanged(1));
}

TEST_F(TestShareInfoFrame, testHandShareInfoChanged)
{

}

TEST_F(TestShareInfoFrame, testDisactivateWidgets)
{
    m_pTester->disactivateWidgets();
    bool b = m_pTester->m_permissoComBox->isEditable();
    EXPECT_EQ(b, false);
}
#ifndef __arm__
TEST_F(TestShareInfoFrame, testDoShareInfoSetting)
{
    m_pTester->m_shareCheckBox->setChecked(true);
    m_pTester->m_permissoComBox->setCurrentIndex(0);
    m_pTester->m_anonymityCombox->setCurrentIndex(1);
    bool b = m_pTester->doShareInfoSetting();
    EXPECT_EQ(b, false);
}
#endif
TEST_F(TestShareInfoFrame, testUpdateShareInfo)
{
    TestHelper::runInLoop([](){});

    DAbstractFileInfoPointer fileinfo = fileService->createFileInfo(nullptr, DUrl("file:///home"));
    m_pTester->m_fileinfo = fileinfo;

    bool(*stub_isEmpty)() = []()->bool{
        return false;
    };
    Stub stu;
    stu.set(ADDR(QString, isEmpty), stub_isEmpty);

    m_pTester->updateShareInfo("/home");
    bool b = m_pTester->m_shareCheckBox->isEnabled();
    EXPECT_EQ(b, false);
}

TEST_F(TestShareInfoFrame, testActivateWidgets)
{
    QComboBox box;
    m_pTester->m_permissoComBox = &box;
    QComboBox box2;
    m_pTester->m_anonymityCombox = &box2;
    m_pTester->activateWidgets();
    bool b = m_pTester->m_permissoComBox->isEnabled();
    EXPECT_EQ(b, true);
}


/*
 *
 * Author:     gongheng<example@nnthink.com>
 *
 * Maintainer: gongheng<gongheng@uniontech.com>
 *
 */

#include "models/dfmrootfileinfo.h"
#include "stub.h"
#include "app/define.h"
#include "dfileservices.h"
#include "testhelper.h"

#include <gtest/gtest.h>
#include <QLineEdit>
#include <QComboBox>
#include <QCheckBox>

#define private public
#include "dialogs/shareinfoframe.h"

namespace  {
    class TestShareInfoFrame : public testing::Test
    {
    public:
        void SetUp() override
        {
            QString strPath = QDir::currentPath() + QDir::separator() + "TestPropertyDialog.txt";
            QFile file(strPath);
            if(!file.exists()){
                if(file.open(QIODevice::ReadWrite | QIODevice::Text))
                    file.close();
            }
            DAbstractFileInfoPointer fi(new DFMRootFileInfo(DUrl("file:///test1")));;
            m_pTester = new ShareInfoFrame(fi);
            std::cout << "start TestShareInfoFrame";
        }
        void TearDown() override
        {
            QString strPath = QDir::currentPath() + QDir::separator() + "TestPropertyDialog.txt";
            QFile file(strPath);
            if(file.exists()){
                file.remove();
            }
            QString strPath2 = QDir::currentPath() + QDir::separator() + "TestPropertyDialog.txt.txt";
            QFile file2(strPath2);
            if(file2.exists()){
                file2.remove();
            }
            delete m_pTester;
            m_pTester = nullptr;
            std::cout << "end TestShareInfoFrame";
        }
    public:
        ShareInfoFrame  *m_pTester;
    };
}

TEST_F(TestShareInfoFrame, testInit)
{
    EXPECT_NE(m_pTester, nullptr);
}

TEST_F(TestShareInfoFrame, testSetFileinfo)
{
    DAbstractFileInfoPointer fileinfo(new DFMRootFileInfo(DUrl("file:///test1")));
    m_pTester->setFileinfo(fileinfo);
    QString str = m_pTester->m_fileinfo->path();
    EXPECT_TRUE(str == "");
}

TEST_F(TestShareInfoFrame, testCheckShareName)
{
    QString(*stub_fileName)() = []()->QString{
        return QString("sharenameedit");
    };
    Stub stu;
    stu.set(ADDR(QFileInfo, fileName), stub_fileName);

    EXPECT_TRUE(m_pTester->checkShareName());
}

TEST_F(TestShareInfoFrame, testHandleCheckBoxChanged)
{
    m_pTester->handleCheckBoxChanged(false);
    bool b = m_pTester->m_shareCheckBox->isEnabled();
    EXPECT_EQ(b, false);
}

TEST_F(TestShareInfoFrame, testHandleCheckBoxChanged2)
{
    m_pTester->handleCheckBoxChanged(true);
    bool b = m_pTester->m_shareCheckBox->isEnabled();
    EXPECT_EQ(b, false);
}

TEST_F(TestShareInfoFrame, testHandleCheckBoxChanged3)
{
    bool(*stub_doShareInfoSetting)() = []()->bool{
        return false;
    };
    Stub stu;
    stu.set(ADDR(ShareInfoFrame, doShareInfoSetting), stub_doShareInfoSetting);
    m_pTester->handleCheckBoxChanged(true);
    bool b = m_pTester->m_shareCheckBox->isEnabled();
    EXPECT_EQ(b, false);
}

TEST_F(TestShareInfoFrame, testHandleShareNameFinished)
{
    EXPECT_NO_FATAL_FAILURE(m_pTester->handleShareNameFinished());
}

TEST_F(TestShareInfoFrame, testHandleShareNameFinished2)
{
    QLineEdit *pShareNamelineEdit = new QLineEdit();
    m_pTester->m_shareNamelineEdit = pShareNamelineEdit;
    pShareNamelineEdit->setFocus();
    QComboBox *pPermissoComBox = new QComboBox();
    m_pTester->m_permissoComBox = pPermissoComBox;

    bool(*stub_hasFocus)() = []()->bool{
            return  true;
    };
    Stub stu;
    stu.set(ADDR(QWidget, hasFocus), stub_hasFocus);

    EXPECT_NO_FATAL_FAILURE(m_pTester->handleShareNameFinished());

    if (pShareNamelineEdit)
        pShareNamelineEdit->deleteLater();
    if (pPermissoComBox)
        pPermissoComBox->deleteLater();

}

TEST_F(TestShareInfoFrame, testHandleShareNameChinged)
{
    QLineEdit shareNamelineEdit;
    m_pTester->m_shareNamelineEdit = &shareNamelineEdit;
    EXPECT_NO_FATAL_FAILURE(m_pTester->handleShareNameChanged(" 123"));
}

TEST_F(TestShareInfoFrame, testHandlePermissionComboxChanged)
{
    EXPECT_NO_FATAL_FAILURE(m_pTester->handlePermissionC

}

TEST_F(TestShareInfoFrame, testHandleAnonymityComboxChanged)
{
    EXPECT_NO_FATAL_FAILURE(m_pTester->handleAnonymityComboxChanged(1));
}

TEST_F(TestShareInfoFrame, testHandShareInfoChanged)
{

}

TEST_F(TestShareInfoFrame, testDisactivateWidgets)
{
    m_pTester->disactivateWidgets();
    bool b = m_pTester->m_permissoComBox->isEditable();
    EXPECT_EQ(b, false);
}
#ifndef __arm__
TEST_F(TestShareInfoFrame, testDoShareInfoSetting)
{
    m_pTester->m_shareCheckBox->setChecked(true);
    m_pTester->m_permissoComBox->setCurrentIndex(0);
    m_pTester->m_anonymityCombox->setCurrentIndex(1);
    bool b = m_pTester->doShareInfoSetting();
    EXPECT_EQ(b, false);
}
#endif
TEST_F(TestShareInfoFrame, testUpdateShareInfo)
{
    TestHelper::runInLoop([](){});

    DAbstractFileInfoPointer fileinfo = fileService->createFileInfo(nullptr, DUrl("file:///home"));
    m_pTester->m_fileinfo = fileinfo;

    bool(*stub_isEmpty)() = []()->bool{
        return false;
    };
    Stub stu;
    stu.set(ADDR(QString, isEmpty), stub_isEmpty);

    m_pTester->updateShareInfo("/home");
    bool b = m_pTester->m_shareCheckBox->isEnabled();
    EXPECT_EQ(b, false);
}

TEST_F(TestShareInfoFrame, testActivateWidgets)
{
    QComboBox box;
    m_pTester->m_permissoComBox = &box;
    QComboBox box2;
    m_pTester->m_anonymityCombox = &box2;
    m_pTester->activateWidgets();
    bool b = m_pTester->m_permissoComBox->isEnabled();
    EXPECT_EQ(b, true);
}


void ResourcePendingMaintenanceActions::OutputToStream(Aws::OStream& oStream, const char* location) const

/**
 */

#include <aws/neptune/model/ResourcePendingMaintenanceActions.h>
#include <aws/core/utils/xml/XmlSerializer.h>
#include <aws/core/utils/StringUtils.h>
#include <aws/core/utils/memory/stl/AWSStringStream.h>

#include <utility>

using namespace Aws::Utils::Xml;
using namespace Aws::Utils;

namespace Aws
{
namespace Neptune
{
namespace Model
{

ResourcePendingMaintenanceActions::ResourcePendingMaintenanceActions() :
    m_resourceIdentifierHasBeenSet(false),
    m_pendingMaintenanceActionDetailsHasBeenSet(false)
{
}

ResourcePendingMaintenanceActions::ResourcePendingMaintenanceActions(const XmlNode& xmlNode) :
    m_resourceIdentifierHasBeenSet(false),
    m_pendingMaintenanceActionDetailsHasBeenSet(false)
{
  *this = xmlNode;
}

ResourcePendingMaintenanceActions& ResourcePendingMaintenanceActions::operator =(const XmlNode& xmlNode)
{
  XmlNode resultNode = xmlNode;

  if(!resultNode.IsNull())
  {
    XmlNode resourceIdentifierNode = resultNode.FirstChild("ResourceIdentifier");
    if(!resourceIdentifierNode.IsNull())
    {
      m_resourceIdentifier = Aws::Utils::Xml::DecodeEscapedXmlText(resourceIdentifierNode.GetText());
      m_resourceIdentifierHasBeenSet = true;
    }
    XmlNode pendingMaintenanceActionDetailsNode = resultNode.FirstChild("PendingMaintenanceActionDetails");
    if(!pendingMaintenanceActionDetailsNode.IsNull())
    {
      XmlNode pendingMaintenanceActionDetailsMember = pendingMaintenanceActionDetailsNode.FirstChild("PendingMaintenanceAction");
      while(!pendingMaintenanceActionDetailsMember.IsNull())
      {
        m_pendingMaintenanceActionDetails.push_back(pendingMaintenanceActionDetailsMember);
        pendingMaintenanceActionDetailsMember = pendingMaintenanceActionDetailsMember.NextNode("PendingMaintenanceAction");
      }

      m_pendingMaintenanceActionDetailsHasBeenSet = true;
    }
  }

  return *this;
}

void ResourcePendingMaintenanceActions::OutputToStream(Aws::OStream& oStream, const char* location, unsigned index, const char* locationValue) const
{
  if(m_resourceIdentifierHasBeenSet)
  {
      oStream << location << index << locationValue << ".ResourceIdentifier=" << StringUtils::URLEncode(m_resourceIdentifier.c_str()) << "&";
  }

  if(m_pendingMaintenanceActionDetailsHasBeenSet)
  {
      unsigned pendingMaintenanceActionDetailsIdx = 1;
      for(auto& item : m_pendingMaintenanceActionDetails)
      {
        Aws::StringStream pendingMaintenanceActionDetailsSs;
        pendingMaintenanceActionDetailsSs << location << index << locationValue << ".PendingMaintenanceAction." << pendingMaintenanceActionDetailsIdx++;
        item.OutputToStream(oStream, pendingMaintenanceActionDetailsSs.str().c_str());
      }
  }

}

{
  if(m_resourceIdentifierHasBeenSet)
  {
      oStream << location << ".ResourceIdentifier=" << StringUtils::URLEncode(m_resourceIdentifier.c_str()) << "&";
  }
  if(m_pendingMaintenanceActionDetailsHasBeenSet)
  {
      unsigned pendingMaintenanceActionDetailsIdx = 1;
      for(auto& item : m_pendingMaintenanceActionDetails)
      {
        Aws::StringStream pendingMaintenanceActionDetailsSs;
        pendingMaintenanceActionDetailsSs << location <<  ".PendingMaintenanceAction." << pendingMaintenanceActionDetailsIdx++;
        item.OutputToStream(oStream, pendingMaintenanceActionDetailsSs.str().c_str());
      }
  }
}

} // namespace Model
} // namespace Neptune
} // namespace Aws


/**
 */

#include <aws/neptune/model/ResourcePendingMaintenanceActions.h>
#include <aws/core/utils/xml/XmlSerializer.h>
#include <aws/core/utils/StringUtils.h>
#include <aws/core/utils/memory/stl/AWSStringStream.h>

#include <utility>

using namespace Aws::Utils::Xml;
using namespace Aws::Utils;

namespace Aws
{
namespace Neptune
{
namespace Model
{

ResourcePendingMaintenanceActions::ResourcePendingMaintenanceActions() :
    m_resourceIdentifierHasBeenSet(false),
    m_pendingMaintenanceActionDetailsHasBeenSet(false)
{
}

ResourcePendingMaintenanceActions::ResourcePendingMaintenanceActions(const XmlNode& xmlNode) :
    m_resourceIdentifierHasBeenSet(false),
    m_pendingMaintenanceActionDetailsHasBeenSet(false)

ResourcePendingMaintenanceActions& ResourcePendingMaintenanceActions::operator =(const XmlNode& xmlNode)
{
  XmlNode resultNode = xmlNode;

  if(!resultNode.IsNull())
  {
    XmlNode resourceIdentifierNode = resultNode.FirstChild("ResourceIdentifier");
    if(!resourceIdentifierNode.IsNull())
    {
      m_resourceIdentifier = Aws::Utils::Xml::DecodeEscapedXmlText(resourceIdentifierNode.GetText());
      m_resourceIdentifierHasBeenSet = true;
    }
    XmlNode pendingMaintenanceActionDetailsNode = resultNode.FirstChild("PendingMaintenanceActionDetails");
    if(!pendingMaintenanceActionDetailsNode.IsNull())
    {
      XmlNode pendingMaintenanceActionDetailsMember = pendingMaintenanceActionDetailsNode.FirstChild("PendingMaintenanceAction");
      while(!pendingMaintenanceActionDetailsMember.IsNull())
      {
        m_pendingMaintenanceActionDetails.push_back(pendingMaintenanceActionDetailsMember);
        pendingMaintenanceActionDetailsMember = pendingMaintenanceActionDetailsMember.NextNode("PendingMaintenanceAction");
      }

      m_pendingMaintenanceActionDetailsHasBeenSet = true;
    }
  }

  return *this;
}

void ResourcePendingMaintenanceActions::OutputToStream(Aws::OStream& oStream, const char* location, unsigned index, const char* locationValue) const
{
  if(m_resourceIdentifierHasBeenSet)
  {
      oStream << location << index << locationValue << ".ResourceIdentifier=" << StringUtils::URLEncode(m_resourceIdentifier.c_str()) << "&";
  }

  if(m_pendingMaintenanceActionDetailsHasBeenSet)
  {
      unsigned pendingMaintenanceActionDetailsIdx = 1;
      for(auto& item : m_pendingMaintenanceActionDetails)
      {
        Aws::StringStream pendingMaintenanceActionDetailsSs;
        pendingMaintenanceActionDetailsSs << location << index << locationValue << ".PendingMaintenanceAction." << pendingMaintenanceActionDetailsIdx++;
        item.OutputToStream(oStream, pendingMaintenanceActionDetailsSs.str().c_str());
      }
  }

}

void ResourcePendingMaintenanceActions::OutputToStream(Aws::OStream& oStream, const char* location) const
{
  if(m_resourceIdentifierHasBeenSet)
  {
      oStream << location << ".ResourceIdentifier=" << StringUtils::URLEncode(m_resourceIdentifier.c_str()) << "&";
  }
  if(m_pendingMaintenanceActionDetailsHasBeenSet)
  {
      unsigned pendingMaintenanceActionDetailsIdx = 1;
      for(auto& item : m_pendingMaintenanceActionDetails)
      {
        Aws::StringStream pendingMaintenanceActionDetailsSs;
        pendingMaintenanceActionDetailsSs << location <<  ".PendingMaintenanceAction." << pendingMaintenanceActionDetailsIdx++;
        item.OutputToStream(oStream, pendingMaintenanceActionDetailsSs.str().c_str());
      }
  }
}

} // namespace Model
} // namespace Neptune
} // namespace Aws


/**
 */

#include <aws/neptune/model/ResourcePendingMaintenanceActions.h>
#include <aws/core/utils/xml/XmlSerializer.h>
#include <aws/core/utils/StringUtils.h>
#include <aws/core/utils/memory/stl/AWSStringStream.h>

#include <utility>

using namespace Aws::Utils::Xml;
using namespace Aws::Utils;

namespace Aws
{
namespace Neptune
{
namespace Model
{

ResourcePendingMaintenanceActions::ResourcePendingMaintenanceActions() :
    m_resourceIdentifierHasBeenSet(false),
    m_pendingMaintenanceActionDetailsHasBeenSet(false)
{
}

ResourcePendingMaintenanceActions::ResourcePendingMaintenanceActions(const XmlNode& xmlNode) :
    m_resourceIdentifierHasBeenSet(false),
    m_pendingMaintenanceActionDetailsHasBeenSet(false)
{
  *this = xmlNode;
}

ResourcePendingMaintenanceActions& ResourcePendingMaintenanceActions::operator =(const XmlNode& xmlNode)
{
  XmlNode resultNode = xmlNode;

  if(!resultNode.IsNull())
  {
    XmlNode resourceIdentifierNode = resultNode.FirstChild("ResourceIdentifier");
    if(!resourceIdentifierNode.IsNull())
    {
      m_resourceIdentifier = Aws::Utils::Xml::DecodeEscapedXmlText(resourceIdentifierNode.GetText());
      m_resourceIdentifierHasBeenSet = true;
    }
    XmlNode pendingMaintenanceActionDetailsNode = resultNode.FirstChild("PendingMaintenanceActionDetails");
    if(!pendingMaintenanceActionDetailsNode.IsNull())
    {
      XmlNode pendingMaintenanceActionDetailsMember = pendingMaintenanceActionDetailsNode.FirstChild("PendingMaintenanceAction");
      while(!pendingMaintenanceActionDetailsMember.IsNull())
      {
        m_pendingMaintenanceActionDetails.push_back(pendingMaintenanceActionDetailsMember);
        pendingMaintenanceActionDetailsMember = pendingMaintenanceActionDetailsMember.NextNode("PendingMaintenanceAction");
      }

      m_pendingMaintenanceActionDetailsHasBeenSet = true;
    }
  }

  r

}

void ResourcePendingMaintenanceActions::OutputToStream(Aws::OStream& oStream, const char* location, unsigned index, const char* locationValue) const
{
  if(m_resourceIdentifierHasBeenSet)
  {
      oStream << location << index << locationValue << ".ResourceIdentifier=" << StringUtils::URLEncode(m_resourceIdentifier.c_str()) << "&";
  }

  if(m_pendingMaintenanceActionDetailsHasBeenSet)
  {
      unsigned pendingMaintenanceActionDetailsIdx = 1;
      for(auto& item : m_pendingMaintenanceActionDetails)
      {
        Aws::StringStream pendingMaintenanceActionDetailsSs;
        pendingMaintenanceActionDetailsSs << location << index << locationValue << ".PendingMaintenanceAction." << pendingMaintenanceActionDetailsIdx++;
        item.OutputToStream(oStream, pendingMaintenanceActionDetailsSs.str().c_str());
      }
  }

}

void ResourcePendingMaintenanceActions::OutputToStream(Aws::OStream& oStream, const char* location) const
{
  if(m_resourceIdentifierHasBeenSet)
  {
      oStream << location << ".ResourceIdentifier=" << StringUtils::URLEncode(m_resourceIdentifier.c_str()) << "&";
  }
  if(m_pendingMaintenanceActionDetailsHasBeenSet)
  {
      unsigned pendingMaintenanceActionDetailsIdx = 1;
      for(auto& item : m_pendingMaintenanceActionDetails)
      {
        Aws::StringStream pendingMaintenanceActionDetailsSs;
        pendingMaintenanceActionDetailsSs << location <<  ".PendingMaintenanceAction." << pendingMaintenanceActionDetailsIdx++;
        item.OutputToStream(oStream, pendingMaintenanceActionDetailsSs.str().c_str());
      }
  }
}

} // namespace Model
} // namespace Neptune
} // namespace Aws


while(!pendingMaintenanceActionDetailsMember.IsNull())
      {
        m_pendingMaintenanceActionDetails.push_back(pendingMaintenanceActionDetailsMember);
        pendingMaintenanceActionDetailsMember = pendingMaintenanceActionDetailsMember.NextNode("PendingMaintenanceAction");
      }

/**
 */

#include <aws/neptune/model/ResourcePendingMaintenanceActions.h>
#include <aws/core/utils/xml/XmlSerializer.h>
#include <aws/core/utils/StringUtils.h>
#include <aws/core/utils/memory/stl/AWSStringStream.h>

#include <utility>

using namespace Aws::Utils::Xml;
using namespace Aws::Utils;

namespace Aws
{
namespace Neptune
{
namespace Model
{

ResourcePendingMaintenanceActions::ResourcePendingMaintenanceActions() :
    m_resourceIdentifierHasBeenSet(false),
    m_pendingMaintenanceActionDetailsHasBeenSet(false)
{
}

ResourcePendingMaintenanceActions::ResourcePendingMaintenanceActions(const XmlNode& xmlNode) :
    m_resourceIdentifierHasBeenSet(false),
    m_pendingMaintenanceActionDetailsHasBeenSet(false)
{
  *this = xmlNode;
}

ResourcePendingMaintenanceActions& ResourcePendingMaintenanceActions::operator =(const XmlNode& xmlNode)
{
  XmlNode resultNode = xmlNode;

  if(!resultNode.IsNull())
  {
    XmlNode resourceIdentifierNode = resultNode.FirstChild("ResourceIdentifier");
    if(!resourceIdentifierNode.IsNull())
    {
      m_resourceIdentifier = Aws::Utils::Xml::DecodeEscapedXmlText(resourceIdentifierNode.GetText());
      m_resourceIdentifierHasBeenSet = true;
    }
    XmlNode pendingMaintenanceActionDetailsNode = resultNode.FirstChild("PendingMaintenanceActionDetails");
    if(!pendingMaintenanceActionDetailsNode.IsNull())
    {
      XmlNode pendingMaintenanceActionDetailsMember = pendingMaintenanceActionDetailsNode.FirstChild("PendingMaintenanceAction");

      m_pendingMaintenanceActionDetailsHasBeenSet = true;
    }
  }

  return *this;
}

void ResourcePendingMaintenanceActions::OutputToStream(Aws::OStream& oStream, const char* location, unsigned index, const char* locationValue) const
{
  if(m_resourceIdentifierHasBeenSet)
  {
      oStream << location << index << locationValue << ".ResourceIdentifier=" << StringUtils::URLEncode(m_resourceIdentifier.c_str()) << "&";
  }

  if(m_pendingMaintenanceActionDetailsHasBeenSet)
  {
      unsigned pendingMaintenanceActionDetailsIdx = 1;
      for(auto& item : m_pendingMaintenanceActionDetails)
      {
        Aws::StringStream pendingMaintenanceActionDetailsSs;
        pendingMaintenanceActionDetailsSs << location << index << locationValue << ".PendingMaintenanceAction." << pendingMaintenanceActionDetailsIdx++;
        item.OutputToStream(oStream, pendingMaintenanceActionDetailsSs.str().c_str());
      }
  }

}

void ResourcePendingMaintenanceActions::OutputToStream(Aws::OStream& oStream, const char* location) const
{
  if(m_resourceIdentifierHasBeenSet)
  {
      oStream << location << ".ResourceIdentifier=" << StringUtils::URLEncode(m_resourceIdentifier.c_str()) << "&";
  }
  if(m_pendingMaintenanceActionDetailsHasBeenSet)
  {
      unsigned pendingMaintenanceActionDetailsIdx = 1;
      for(auto& item : m_pendingMaintenanceActionDetails)
      {
        Aws::StringStream pendingMaintenanceActionDetailsSs;
        pendingMaintenanceActionDetailsSs << location <<  ".PendingMaintenanceAction." << pendingMaintenanceActionDetailsIdx++;
        item.OutputToStream(oStream, pendingMaintenanceActionDetailsSs.str().c_str());
      }
  }
}

} // namespace Model
} // namespace Neptune
} // namespace Aws


#include <cstdio>
#include <algorithm>

using namespace std;

{
    int n;

    scanf("%d",&n);

    int t[n],c[n];

    for(int i = 0;i < n;++i)
        scanf("%d %d",&t[i],&c[i]);

    for(int i = 0;i < n;++i)
        for(int j = i + 1;j < n;++j)
            if(t[j] < t[i]){
                swap(t[i],t[j]);
                swap(c[i],c[j]);
            }

    int last = 0,maxq = 0,sz = 0,prev = 0;

    for(int i = 0,j = 0;i < n;){
        int e = i;
        int cur = t[i];

        sz = max(0,sz - (cur - prev));

        while(e < n && t[e] == cur){
            sz += c[e];
            ++e;
        }

        maxq = max(maxq,sz);
        if(sz) last = cur + sz;

        i = e;
        prev = cur;
    }

    printf("%d %d\n",last,maxq);

    return 0;
}


#include <cstdio>
#include <algorithm>

using namespace std;

int main(){
    int n;

    scanf("%d",&n);

    int t[n],c[n];

    for(int i = 0;i < n;++i)
        scanf("%d %d",&t[i],&c[i]);

    for(int i = 0;i < n;++i)
        for(int j = i + 1;j < n;++j)
            if(t[j] < t[i]){
                swap(t[i],t[j]);
                swap(c[i],c[j]);
            }

    int last = 0,maxq = 0,sz = 0,prev = 0

    for(int i = 0,j = 0;i < n;){
        int e = i;
        int cur = t[i];

        sz = max(0,sz - (cur - prev));

        while(e < n && t[e] == cur){
            sz += c[e];
            ++e;
        }

        maxq = max(maxq,sz);
        if(sz) last = cur + sz;

        i = e;
        prev = cur;
    }

    printf("%d %d\n",last,maxq);

    return 0;
}


#include <cstdio>
#include <algorithm>

using namespace std;

int main(){
    int n;

    scanf("%d",&n);

    int t[n],c[n];

    for(int i = 0;i < n;++i)
        for(int j = i + 1;j < n;++j)
            if(t[j] < t[i]){
                swap(t[i],t[j]);
                swap(c[i],c[j]);
            }

    int last = 0,maxq = 0,sz = 0,prev = 0;

    for(int i = 0,j = 0;i < n;){
        int e = i;
        int cur = t[i];

        sz = max(0,sz - (cur - prev));

        while(e < n && t[e] == cur){
            sz += c[e];
            ++e;
        }

        maxq = max(maxq,sz);
        if(sz) last = cur + sz;

        i = e;
        prev = cur;
    }

    printf("%d %d\n",last,maxq);

    return 0;
}


#include <cstdio>
#include <algorithm>

using namespace std;

int main(){
    int n;

    scanf("%d",&n);

    int t[n],c[n];

    for(int i = 0;i < n;++i)
        scanf("%d %d",&t[i],&c[i]);

    for(int i = 0;i < n;++i)
        for(int j = i + 1;j < n;++j)
            if(t[j] < t[i]){
                swap(t[i],t[j]);
                swap(c[i],c[j]);
            }

    int last = 0,maxq = 0,sz = 0,prev = 0;

    for(int i = 0,j = 0;i < n;){
        int e = i;
        int cur = t[i];

        sz = max(0,sz - (cur - prev));

        maxq = max(maxq,sz);
        if(sz) last = cur + sz;

        i = e;
        prev = cur;
    }

    printf("%d %d\n",last,maxq);

    return 0;
}