//------------------------------------------------------------------------------
// <copyright file="LqrSMACSerialPortSettings.h" company="LiquidRobotics">
//
// Copyright (c) 2014 Liquid Robotics, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// This software is associated with a release.  Liquid Robotics makes no
// representation that the design, interfaces or component distribution will
// remain unchanged in future releases.
//
// </copyright>
//
// <summary>
// </summary>
//
// <owner></owner>
//------------------------------------------------------------------------------


#ifndef SERIALPORTSETTINGS_H_
#define SERIALPORTSETTINGS_H_

#include <iostream>
#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/shared_ptr.hpp>
#include "LqrSMACSerialPort.h"
#include "LqrSMACLogger.h"

namespace LiquidRobotics {
namespace SMACFramework {

class SHARED_LIB_PUBLIC SerialPortSettings
{
public:

	typedef std::string string;
	typedef ISerialPort::BaudRate BaudRate;
	typedef ISerialPort::CharacterSize CharacterSize;
	typedef ISerialPort::FlowControl FlowControl;
	typedef ISerialPort::Parity Parity;
	typedef ISerialPort::StopBits StopBits;
	typedef ISerialPort::Ptr SerialPortPtr;

	SerialPortSettings();
	SerialPortSettings(const char* _portName, const ISerialPort& _serialPort);
	SerialPortSettings(const char* _portName, BaudRate _baudRate = ISerialPort::BAUD_9600, Parity _parity = ISerialPort::PARITY_NONE,
			CharacterSize _characterSize = ISerialPort::CHAR_SIZE_8, StopBits _stopBits = ISerialPort::STOP_BITS_1,
			FlowControl _flowControl = ISerialPort::FLOW_CONTROL_NONE, bool _rts = true, bool _dtr = true,
			float _breakTimeoutMultiplier = 1.0f);
	SerialPortSettings(const SerialPortSettings& right);

	virtual ~SerialPortSettings();

	SerialPortSettings& operator=(const SerialPortSettings& right);
	bool operator==(const SerialPortSettings& right) const;

	SerialPortPtr CreatePort() const;
	SerialPortPtr CreatePort(Logger& logger) const;
	string ToString() const;

	string GetPortName() const;
	void SetPortName(const char* newValue);

	BaudRate GetBaudRate() const;
	void SetBaudRate(BaudRate newValue);

	Parity GetParity() const;
	void SetParity(Parity newValue);

	CharacterSize GetCharacterSize() const;
	void SetCharacterSize(CharacterSize newValue);

	StopBits GetStopBits() const;
	void SetStopBits(StopBits newValue);

	FlowControl GetFlowControl() const;
	void SetFlowControl(FlowControl newValue);

	bool GetRts() const;
	void SetRts(bool newValue);

	bool GetDtr() const;
	void SetDtr(bool newValue);

	float GetBreakTimeoutMultiplier() const;
	void SetBreakTimeoutMultiplier(float newValue);

	static string BaudRate_ToString(BaudRate baudRate);
	static BaudRate BaudRate_FromString(const string& str);

	static string CharacterSize_ToString(CharacterSize characterSize);
	static CharacterSize CharacterSize_FromString(const string& str);

	static string FlowControl_ToString(FlowControl flowControl);
	static FlowControl FlowControl_FromString(const string& str);

	static string Parity_ToString(Parity parity);
	static Parity Parity_FromString(const string& str);

	static string StopBits_ToString(StopBits stopBits);
	static StopBits StopBits_FromString(const string& str);

private:

	friend class boost::serialization::access;

	template<class Archive>
	void save(Archive& ar, const unsigned int version) const
	{
		ar & BOOST_SERIALIZATION_NVP(portName);

		string strBaudRate = BaudRate_ToString(baudRate);
		string strParity = Parity_ToString(parity);
		string strCharacterSize = CharacterSize_ToString(characterSize);
		string strStopBits = StopBits_ToString(stopBits);
		string strFlowControl = FlowControl_ToString(flowControl);

		ar & boost::serialization::make_nvp("baudRate", strBaudRate);
		ar & boost::serialization::make_nvp("parity", strParity);
		ar & boost::serialization::make_nvp("characterSize", strCharacterSize);
		ar & boost::serialization::make_nvp("stopBits", strStopBits);
		ar & boost::serialization::make_nvp("flowControl", strFlowControl);

		ar & BOOST_SERIALIZATION_NVP(rts);
		ar & BOOST_SERIALIZATION_NVP(dtr);
		ar & BOOST_SERIALIZATION_NVP(breakTimeoutMultiplier);
	}

	template<class Archive>
	void load(Archive& ar, const int version)
	{
		ar & BOOST_SERIALIZATION_NVP(portName);

		string strBaudRate;
		string strParity;
		string strCharacterSize;
		string strStopBits;
		string strFlowControl;

		ar & boost::serialization::make_nvp("baudRate", strBaudRate);
		ar & boost::serialization::make_nvp("parity", strParity);
		ar & boost::serialization::make_nvp("characterSize", strCharacterSize);
		ar & boost::serialization::make_nvp("stopBits", strStopBits);
		ar & boost::serialization::make_nvp("flowControl", strFlowControl);

		baudRate = BaudRate_FromString(strBaudRate);
		parity = Parity_FromString(strParity);
		characterSize = CharacterSize_FromString(strCharacterSize);
		stopBits = StopBits_FromString(strStopBits);
		flowControl = FlowControl_FromString(strFlowControl);

		ar & BOOST_SERIALIZATION_NVP(rts);
		ar & BOOST_SERIALIZATION_NVP(dtr);
		ar & BOOST_SERIALIZATION_NVP(breakTimeoutMultiplier);

		CheckValuesAfterLoading();
	}

	BOOST_SERIALIZATION_SPLIT_MEMBER()

	void CheckValuesAfterLoading();

	string portName;
	BaudRate baudRate;
	Parity parity;
	CharacterSize characterSize;
	StopBits stopBits;
	FlowControl flowControl;
	bool rts;
	bool dtr;
	float breakTimeoutMultiplier;
};

SHARED_LIB_PUBLIC std::ostream& operator<<(std::ostream& out, const SerialPortSettings& settings);

}
}

#endif /* SERIALPORTSETTINGS_H_ */
