#ifndef NFN_H
#define NFN_H

#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

#include <uv.h>
#include <node.h>

namespace nfn {
	using namespace v8;

	const uint8_t NFN_LOG = 1;
	const uint8_t NFN_HEX = 2;
	const uint8_t NFN_RESET = 4;
	const uint8_t NFN_CLOSE = 8;
	const uint8_t NFN_UV = 16;
	const uint8_t NFN_UV_LOCKED = 32;

	struct nfn_buffer_s {
		void *data;
		size_t len{0};
		size_t max{512};
	};

	typedef struct nfn_buffer_s nfn_buffer;

	struct nfn_device_s {
		bool log{false};
		bool hex{true};
		bool manu{false};
		size_t sleep{100};
		size_t rmax{512};
		size_t wmax{512};
		int hwnd;
		char *name;
	};

	typedef struct nfn_device_s nfn_device;

	struct nfn_async_s {
		char *state;
		Persistent<Function> *func;
		nfn_buffer *buf;
		uv_async_t work;
		char *tag;
	};

	typedef struct nfn_async_s nfn_async;

	struct nfn_uv_s {
		uv_work_t work;
		useconds_t sp;
	};

	typedef struct nfn_uv_s nfn_uv;

	struct nfn_info_s {
		char state;
		Persistent<Function> func;
		int hwnd;
		nfn_uv *uv;
		nfn_async *read;
		nfn_async *write;
	};

	typedef struct nfn_info_s nfn_info;

//	==================================================================

	extern size_t min(size_t a, size_t b);

	extern size_t max(size_t a, size_t b);

	extern void *memcpy(char *dest, const char *src, size_t count);

	extern void memset(void *dest, const char val, size_t count);

	extern bool strcmp(char *str1, char *str2);

	extern nfn_buffer *buffer_init(size_t max);

	extern void buffer_free(nfn_buffer *buf);

	extern Local<String> BuftoString(Isolate *isolate, nfn_buffer *buf);

	extern Local<Uint8Array> BuftoHex(Isolate *isolate, nfn_buffer *value, bool init = false);

	extern char *HextoPChar(Local<Uint8Array> value, int index = -1);

	extern char *StringtoPChar(Local<String> value);

	extern nfn_buffer *HextoBuf(Local<Uint8Array> value);

//	do function

	extern void do_read(nfn_info *info, size_t len);

	extern void do_write(nfn_info *info, const void *data, size_t len);

	extern void do_finish(uv_handle_t *handle);

	extern void do_callback(Isolate *isolate, Local<Function> func, const char *tag, Local<Array> data);

//	async function

	extern void async_work(uv_async_t *handle);

	extern void async_finish(nfn_async *async);

//	uv function

	extern void uv_work(uv_work_t *handle);

	extern void uv_finish_cb(nfn_info *info);

	extern void uv_finish(uv_work_t *handle, int status);

//	==================================================================

	class nfn_Core {
		protected:

			nfn_info *_info;

			virtual nfn_info *init(Isolate *isolate, nfn_info *info, nfn_device *dev, Local<Function> func);

			virtual void init_custom(nfn_info *info, nfn_device *dev);

			virtual nfn_async *init_async(nfn_info *info, uv_loop_t *loop, char *tag, size_t max);

			virtual nfn_uv *init_uv(nfn_info *info, uv_loop_t *loop, size_t sleep);

			virtual nfn_info *info_init(Isolate *isolate, Local<Object> opt);

			virtual Local<String> info_get(Isolate *isolate, nfn_device *dev) = 0;

			virtual nfn_device *info_set(Isolate *isolate, Local<Object> opt);

			virtual nfn_device *info_set_custom(Isolate *isolate, Local<Object> opt);

			virtual int device_open(nfn_device *dev) = 0;

			virtual bool device_set(nfn_device *dev) = 0;

			virtual void stop_custom(nfn_info *info);

			virtual bool config_custom(Isolate *isolate, Local<Object> opt, nfn_info *info);

		public:

			~nfn_Core(void);

			bool start(Isolate *isolate, Local<Object> opt, Local<Function> func);

			void stop(void);

			void reset(void);

			bool config(Isolate *isolate, Local<Object> opt);

			void clear(void);

			virtual bool read(size_t len);

			virtual bool write(Local<Value> data);
	};
}

#endif
