#ifndef BRICK_INTERFACE_H
#define BRICK_INTERFACE_H

#include "brick_base.h"
#include "piserial.h"
#include "piethernet.h"
#include "pifile.h"

static PIMutex mutex;

class BrickInterfaceBase: public BrickBase {
public:
	BrickInterfaceBase(int inputs_num = 1, int outputs_num = 1, int parameters_num = 1): BrickBase(inputs_num, outputs_num, parameters_num + 1) {
		lib = "Interfaces";
		paramNames[0] = "Struct file";
		parameters[0].setValue("struct_example.conf");
		parameters[0].setType(BrickBase::File);
		header_ = 0;
		note_ = "\"Struct file\" is a path to *.conf file that describe struct to send or receive. See \"struct_example.conf\" for details.";
		rtOnly = true;
	}
	virtual ~BrickInterfaceBase() {;}
protected:
	virtual void parameterChanged(int index) {
		if (index != 0) return;
		mutex.lock();
		///struct_.parseFile(parameters[0].toString());
		///data.resize(struct_.size());
		mutex.unlock();
	}
	///PIStruct struct_;
	PIVector<char> data;
	int header_;
};

class BrickInterfaceBaseIn: public BrickInterfaceBase {
public:
	BrickInterfaceBaseIn(int inputs_num = 1, int outputs_num = 1, int parameters_num = 1): BrickInterfaceBase(inputs_num, outputs_num, parameters_num) {parameterChanged(0);}
	virtual ~BrickInterfaceBaseIn() {;}
protected:
	static bool received(void * t, uchar * d, int s);
	virtual bool tick_body(double time);
	virtual void parameterChanged(int index) {
		if (index != 0) return;
		BrickInterfaceBase::parameterChanged(0);
		/**setOutputsCount(struct_.count() + 1);
		for (uint i = 0; i < struct_.count(); ++i) {
			outNames[i + 1] = struct_[i].name();
			outputs[i + 1] = struct_[i].value();
		}*/
	}
};

class BrickInterfaceBaseOut: public BrickInterfaceBase {
public:
	BrickInterfaceBaseOut(int inputs_num = 1, int outputs_num = 1, int parameters_num = 1): BrickInterfaceBase(inputs_num, outputs_num, parameters_num) {parameterChanged(0);}
	virtual ~BrickInterfaceBaseOut() {;}
protected:
	virtual bool tick_body(double time);
	virtual void parameterChanged(int index) {
		if (index != 0) return;
		BrickInterfaceBase::parameterChanged(0);
		/**setInputsCount(struct_.count());
		for (uint i = 0; i < struct_.count(); ++i) {
			inNames[i] = struct_[i].name();
			inputs[i] = struct_[i].value();
		}*/
	}
};


class BrickInterfaceSerialIn: public BrickInterfaceBaseIn {
	MBRICK(BrickInterfaceSerialIn)
	BrickInterfaceSerialIn(): BrickInterfaceBaseIn(0, 1,5) {
		type = "SerialIn";
		setName(type);
		outNames[0] = "Init";
		paramNames[1] = "Device";
		paramNames[2] = "Parity control";
		paramNames[3] = "Two stop bits";
		paramNames[4] = "Baud rate";
		paramNames[5] = "Header size";
#ifdef WINDOWS
		parameters[1].setValue("COM1");
#else
		parameters[1].setValue("/dev/ttyS0");
#endif
		parameters[2].setValue(false);
		parameters[3].setValue(false);
		parameters[4].setValue(115200);
		parameters[5].setValue(0);
		note_ += "\n\"Header size\" is a bytes count from begin of struct, that contains packet attribute (need for advanced receive algorithm).";
		note_ += "\n\"Device\" is a name of your serial device, e.g. \"/dev/ttyS0\" or \"COM1\".";
	}
	virtual ~BrickInterfaceSerialIn() {;}
	virtual void started();
	virtual void finished() {ser.stop(false);}
	virtual bool tick_body(double time);
private:
	PISerial ser;
};
ADD_NEW_TO_COLLECTION(Interfaces, BrickInterfaceSerialIn)


class BrickInterfaceSerialOut: public BrickInterfaceBaseOut {
	MBRICK(BrickInterfaceSerialOut)
	BrickInterfaceSerialOut(): BrickInterfaceBaseOut(0, 1, 4) {
		type = "SerialOut";
		setName(type);
		outNames[0] = "Init";
		paramNames[1] = "Device";
		paramNames[2] = "Parity control";
		paramNames[3] = "Two stop bits";
		paramNames[4] = "Baud rate";
#ifdef WINDOWS
		parameters[1].setValue("COM1");
#else
		parameters[1].setValue("/dev/ttyS0");
#endif
		parameters[2].setValue(false);
		parameters[3].setValue(false);
		parameters[4].setValue(115200);
		note_ += "\n\"Header size\" is a bytes count from begin of struct, that contains packet attribute (need for advanced receive algorithm).";
		note_ += "\n\"Device\" is a name of your serial device, e.g. \"/dev/ttyS0\" or \"COM1\".";
	}
	virtual ~BrickInterfaceSerialOut() {;}
	virtual void started();
	virtual void finished() {ser.stop(false);}
	virtual bool tick_body(double time);
private:
	PISerial ser;
};
ADD_NEW_TO_COLLECTION(Interfaces, BrickInterfaceSerialOut)


class BrickInterfaceUDPIn: public BrickInterfaceBaseIn {
	MBRICK(BrickInterfaceUDPIn)
	BrickInterfaceUDPIn(): BrickInterfaceBaseIn(0, 1, 2) {
		type = "UDPIn";
		setName(type);
		outNames[0] = "Init";
		paramNames[1] = "IP";
		paramNames[2] = "Port";
		parameters[1].setValue("127.0.0.1");
		parameters[2].setValue(1638);
	}
	virtual ~BrickInterfaceUDPIn() {;}
	virtual void started();
	virtual void finished() {eth.stop(false);}
	virtual bool tick_body(double time);
private:
	PIEthernet eth;
};
ADD_NEW_TO_COLLECTION(Interfaces, BrickInterfaceUDPIn)


class BrickInterfaceUDPOut: public BrickInterfaceBaseOut {
	MBRICK(BrickInterfaceUDPOut)
	BrickInterfaceUDPOut(): BrickInterfaceBaseOut(0, 1, 2) {
		type = "UDPOut";
		setName(type);
		outNames[0] = "Init";
		paramNames[1] = "IP";
		paramNames[2] = "Port";
		parameters[1].setValue("127.0.0.1");
		parameters[2].setValue(1638);
	}
	virtual ~BrickInterfaceUDPOut() {;}
	virtual void started() {parameterChanged(0); eth.open();}
	//virtual void finished() {eth.terminate();}
	virtual bool tick_body(double time);
private:
	PIEthernet eth;
};
ADD_NEW_TO_COLLECTION(Interfaces, BrickInterfaceUDPOut)


class BrickInterfaceBinFileOut: public BrickInterfaceBaseOut {
	MBRICK(BrickInterfaceBinFileOut)
	BrickInterfaceBinFileOut(): BrickInterfaceBaseOut(0, 0, 4) {
		type = "BinFileOut";
		setName(type);
		paramNames[1] = "File";
		paramNames[2] = "ID(Dec)";
		paramNames[3] = "Overwrite";
		paramNames[4] = "Flush";
		parameters[1].setValue("binlog.dat");
		parameters[2].setValue(1);
		parameters[3].setValue(false);
		parameters[4].setValue(false);
		parameters[1].setType(BrickBase::File);
		note_ += "\nIf \"Overwrite\" is true file will be cleared before every start.";
		note_ += "\nIf \"Flush\" is true file will be flushed after every tick.";
		note_ += "\nb{NOTE:} this brick create binary file for \"Log Parser\".";
		rtOnly = false;
	}
	virtual ~BrickInterfaceBinFileOut() {;}
	virtual void started();
	virtual void finished() {file.flush(); file.close();}
	virtual bool tick_body(double time);
private:
	ushort id;
	PIFile file;
};
ADD_NEW_TO_COLLECTION(Interfaces, BrickInterfaceBinFileOut)

#endif // BRICK_INTERFACE_H
