//---------------------------------------------------------------------------------------------
// <copyright file="SBGPCTDSensor_HardwareData.cpp" 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>
// 	Implementation of methods of SBGPCTDSensor's HardwareData inner class, which carries parsed
//  output from the gethd command
// </summary>
//
// <owner>Mike Cookson</owner>
//---------------------------------------------------------------------------------------------

#include "SBGPCTDSensor.h"
#include "LqrSMACEscapeStr.h"
#include <cmath>
#include <string>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>
#include "pugixml.hpp"

using namespace std;
using namespace LiquidRobotics::SMACFramework;

namespace LiquidRobotics {
namespace SeabirdGPCTD {

SBGPCTDSensor::HardwareData::HardwareData()
{
}

SBGPCTDSensor::HardwareData::HardwareData(const string& _line)
: line(_line)
{
	pugi::xml_document doc;
	doc.load_buffer(line.c_str(), line.length());

	for (pugi::xml_node n = doc.first_child(); n; n = n.next_sibling())
		if (boost::iequals(n.name(), "HardwareData"))
		{
			for (pugi::xml_attribute a = n.first_attribute(); a; a = a.next_attribute())
			{
				if (boost::iequals(a.name(), "DeviceType"))
					mainSensor.deviceType = a.value();
				else if (boost::iequals(a.name(), "SerialNumber"))
					mainSensor.serialNumber = a.value();
			}

			for (pugi::xml_node c = n.first_child(); c; c = c.next_sibling())
			{
				if (boost::iequals(c.name(), "Manufacturer"))
					manufacturer = c.child_value();
				else if (boost::iequals(c.name(), "FirmwareVersion"))
					firmwareVersion = c.child_value();
				else if (boost::iequals(c.name(), "FirmwareDate"))
					firmwareDate = c.child_value();
				else if (boost::iequals(c.name(), "CommandSetVersion"))
					commandSetVersion = c.child_value();
				else if (boost::iequals(c.name(), "MfgDate"))
				    mfgDate = c.child_value();
				else if (boost::iequals(c.name(), "PCBAssembly"))
				{
				    pcbs.resize(pcbs.size()+1);
					pcbs[pcbs.size()-1].id = c.child_value();
				}
				else if (boost::iequals(c.name(), "PCBSerialNum"))
					pcbs[pcbs.size()-1].serialNumber = c.child_value();
				else if (boost::iequals(c.name(), "InternalSensors"))
				{
				    for (pugi::xml_node i = c.first_child(); i; i = i.next_sibling())
					{
					    if (boost::iequals(i.name(), "Sensor"))
						{
						    internalSensors.resize(internalSensors.size()+1);
						    HardwareID& hid = internalSensors[internalSensors.size()-1];
						    for (pugi::xml_attribute ia = i.first_attribute(); ia; ia = ia.next_attribute())
							    if (boost::iequals(ia.name(), "id"))
								    hid.id = ia.value();
						    for (pugi::xml_node ic = i.first_child(); ic; ic = ic.next_sibling())
							    if (boost::iequals(ic.name(), "type"))
								    hid.deviceType = ic.child_value();
							    else if (boost::iequals(ic.name(), "SerialNumber"))
								    hid.serialNumber = ic.child_value();
						}
					}
				}
				else if (boost::iequals(c.name(), "ExternalSensors"))
				{
				    for (pugi::xml_node i = c.first_child(); i; i = i.next_sibling())
					{
					    if (boost::iequals(i.name(), "Sensor"))
						{
						    externalSensors.resize(externalSensors.size()+1);
						    HardwareID& hid = externalSensors[externalSensors.size()-1];
						    for (pugi::xml_attribute ia = i.first_attribute(); ia; ia = ia.next_attribute())
							    if (boost::iequals(ia.name(), "id"))
								    hid.id = ia.value();
						    for (pugi::xml_node ic = i.first_child(); ic; ic = ic.next_sibling())
							    if (boost::iequals(ic.name(), "type"))
								    hid.deviceType = ic.child_value();
							    else if (boost::iequals(ic.name(), "SerialNumber"))
								    hid.serialNumber = ic.child_value();
						}
					}
				}
			}

			break;
		}
}

inline void add(stringstream& stm, const string& name, const string& value)
{
	if (stm.tellp()) stm.put(' ');
	stm << name << "='" << EscapeStr(value) << "'";
}

#define ADD(var) add(msg,#var,var)

string SBGPCTDSensor::HardwareData::ToString() const
{
	stringstream msg;

	ADD(line);
	ADD(manufacturer);
	ADD(firmwareVersion);
	ADD(firmwareDate);
	ADD(commandSetVersion);
	ADD(mfgDate);
	msg << " mainSensor={ " << mainSensor.ToString() << " }";
	msg << " internalSensors={";
	for (HardwareID::Vector::const_iterator ci = internalSensors.begin(); ci != internalSensors.end(); ++ci)
	    msg << "{ " << ci->ToString() << " }";
	msg << " }";
	msg << " externalSensors={";
	for (HardwareID::Vector::const_iterator ci = externalSensors.begin(); ci != externalSensors.end(); ++ci)
	    msg << "{ " << ci->ToString() << " }";
	msg << " }";

	return msg.str();
}

string SBGPCTDSensor::HardwareID::ToString() const
{
    stringstream msg;

	ADD(id);
	ADD(deviceType);
	ADD(serialNumber);

	return msg.str();
}

}
}
