//
//  app_classes.cpp - application variable class implementation file
//
//  $Id: app_classes.cpp 38 2014-02-06 18:52:23Z brian $ 
//
//  Copyright (c) 1999-2014 by Precision Micro Control Corp. All rights reserved.
//
#include "stdafx.h"

//*****************************************************************************
// CAppInt implementation

CAppInt::CAppInt(const int value, char* section, char* entry)
	: m_value(value), m_section(section), m_entry(entry)
{
}

void CAppInt::Init(const int value, char* section, char* entry)
{
	m_value = value;
	m_section = section;
	m_entry = entry;
}

void CAppInt::Erase(const char* ini_file)
{
	// Delete contents of entire section from file in preparation for new data
	WritePrivateProfileString(m_section, NULL, NULL, ini_file);
}

void CAppInt::Save(const char* ini_file)
{
	char buffer[INTSTRINGLENGTH];
	
	_snprintf(buffer, sizeof(buffer), "%d", m_value);
	WritePrivateProfileString(m_section, m_entry, buffer, ini_file);
}

void CAppInt::Restore(const char* ini_file)
{
	char buffer[INTSTRINGLENGTH];
	
	GetPrivateProfileString(m_section, m_entry, "0", buffer, sizeof(buffer), ini_file);
	m_value = atoi(buffer);
}

//*****************************************************************************
// CAppDouble implementation

CAppDouble::CAppDouble(const double value, char* section, char* entry)
	: m_value(value), m_section(section), m_entry(entry)
{
}

void CAppDouble::Init(const double value, char* section, char* entry)
{
	m_value = value;
	m_section = section;
	m_entry = entry;
}

void CAppDouble::Erase(const char* ini_file)
{
	WritePrivateProfileString(m_section, NULL, NULL, ini_file);
}

void CAppDouble::Save(const char* ini_file, int precision)
{
	char buffer[DOUBLESTRINGLENGTH];
	
	_snprintf(buffer, sizeof(buffer), "%.*g", precision, m_value);
	WritePrivateProfileString(m_section, m_entry, buffer, ini_file);
}

void CAppDouble::Restore(const char* ini_file)
{
	char buffer[DOUBLESTRINGLENGTH];
	
	GetPrivateProfileString(m_section, m_entry, "0.0", buffer, sizeof(buffer), ini_file);
	m_value = atof(buffer);
}

//*****************************************************************************
// CAppString implementation

CAppString::CAppString(const char* value, char* section, char* entry)
	: m_value(value), m_section(section), m_entry(entry)
{
}

void CAppString::Init(const char* value, char* section, char* entry)
{
	m_value = value;
	m_section = section;
	m_entry = entry;
}

void CAppString::Erase(const char* ini_file)
{
	WritePrivateProfileString(m_section, NULL, NULL, ini_file);
}

void CAppString::Save(const char* ini_file)
{
	WritePrivateProfileString(m_section, m_entry, (const char* )m_value, ini_file);
}

void CAppString::Restore(const char* ini_file)
{
	char buffer[120];
	
	GetPrivateProfileString(m_section, m_entry, "0", buffer, sizeof(buffer), ini_file);
	m_value = buffer;
}

//*****************************************************************************
// Units management

// These are arrays holding Title, Label, and Multipliers for available
//  dimension and period (time) units. They are initialized in succeeding
//  functions to match enumerated data types DIM_UNIT and PER_UNIT.
char* DimUnitTitle[MAX_DIM_UNITS];
char* DimUnitLabel[MAX_DIM_UNITS];
double DimUnitMultiplier[MAX_DIM_UNITS];

double PerUnitMultiplier[MAX_PER_UNITS];
char* PerUnitTitle[MAX_PER_UNITS];
char* PerUnitLabel[MAX_PER_UNITS];

// Initialize all dimension units data
void InitDimUnits()
{
	InitDimUnit(UNDEFINED_DIM_UNIT, UNDEFINED_DIM_UNIT_TITLE, UNDEFINED_DIM_UNIT_LABEL, UNDEFINED_DIM_UNIT_MULTIPLIER);
	
	InitDimUnit(REVOLUTION_UNIT, REVOLUTION_UNIT_TITLE, REVOLUTION_UNIT_LABEL, REVOLUTION_UNIT_MULTIPLIER);
	InitDimUnit(DEGREE_UNIT, DEGREE_UNIT_TITLE, DEGREE_UNIT_LABEL, DEGREE_UNIT_MULTIPLIER);
	InitDimUnit(RADIAN_UNIT, RADIAN_UNIT_TITLE, RADIAN_UNIT_LABEL, RADIAN_UNIT_MULTIPLIER);
	
	InitDimUnit(HUNDRETHMIL_UNIT, HUNDRETHMIL_UNIT_TITLE, HUNDRETHMIL_UNIT_LABEL, HUNDRETHMIL_UNIT_MULTIPLIER);
	InitDimUnit(TENTHMIL_UNIT, TENTHMIL_UNIT_TITLE, TENTHMIL_UNIT_LABEL, TENTHMIL_UNIT_MULTIPLIER);
	InitDimUnit(MIL_UNIT, MIL_UNIT_TITLE, MIL_UNIT_LABEL, MIL_UNIT_MULTIPLIER);
	InitDimUnit(INCH_UNIT, INCH_UNIT_TITLE, INCH_UNIT_LABEL, INCH_UNIT_MULTIPLIER);
	InitDimUnit(FEET_UNIT, FEET_UNIT_TITLE, FEET_UNIT_LABEL, FEET_UNIT_MULTIPLIER);
	InitDimUnit(YARD_UNIT, YARD_UNIT_TITLE, YARD_UNIT_LABEL, YARD_UNIT_MULTIPLIER);

	InitDimUnit(MICROMETER_UNIT, MICROMETER_UNIT_TITLE, MICROMETER_UNIT_LABEL, MICROMETER_UNIT_MULTIPLIER);
	InitDimUnit(HUNDRETHMM_UNIT, HUNDRETHMM_UNIT_TITLE, HUNDRETHMM_UNIT_LABEL, HUNDRETHMM_UNIT_MULTIPLIER);
	InitDimUnit(TENTHMM_UNIT, TENTHMM_UNIT_TITLE, TENTHMM_UNIT_LABEL, TENTHMM_UNIT_MULTIPLIER);
	InitDimUnit(MILLIMETER_UNIT, MILLIMETER_UNIT_TITLE, MILLIMETER_UNIT_LABEL, MILLIMETER_UNIT_MULTIPLIER);
	InitDimUnit(CENTIMETER_UNIT, CENTIMETER_UNIT_TITLE, CENTIMETER_UNIT_LABEL, CENTIMETER_UNIT_MULTIPLIER);
	InitDimUnit(DECIMETER_UNIT, DECIMETER_UNIT_TITLE, DECIMETER_UNIT_LABEL, DECIMETER_UNIT_MULTIPLIER);
	InitDimUnit(METER_UNIT, METER_UNIT_TITLE, METER_UNIT_LABEL, METER_UNIT_MULTIPLIER);
}

// Initialize a dimension unit's data
void InitDimUnit(DIM_UNIT unit, char* title, char* label, double multiplier)
{
	DimUnitTitle[unit] = title;
	DimUnitLabel[unit] = label;
	DimUnitMultiplier[unit] = multiplier;
}	


// Initialize all period units data
void InitPerUnits()
{
	InitPerUnit(UNDEFINED_PER_UNIT, UNDEFINED_PER_UNIT_TITLE, UNDEFINED_PER_UNIT_LABEL, UNDEFINED_PER_UNIT_MULTIPLIER);
	
	InitPerUnit(MILLISECOND_UNIT, MILLISECOND_UNIT_TITLE, MILLISECOND_UNIT_LABEL, MILLISECOND_UNIT_MULTIPLIER);
	InitPerUnit(SECOND_UNIT, SECOND_UNIT_TITLE, SECOND_UNIT_LABEL, SECOND_UNIT_MULTIPLIER);
	InitPerUnit(MINUTE_UNIT, MINUTE_UNIT_TITLE, MINUTE_UNIT_LABEL, MINUTE_UNIT_MULTIPLIER);
	InitPerUnit(HOUR_UNIT, HOUR_UNIT_TITLE, HOUR_UNIT_LABEL, HOUR_UNIT_MULTIPLIER);
	InitPerUnit(DAY_UNIT, DAY_UNIT_TITLE, DAY_UNIT_LABEL, DAY_UNIT_MULTIPLIER);
}

// Initialize a period unit's data
void InitPerUnit(PER_UNIT unit, char* title, char* label, double multiplier)
{
	PerUnitTitle[unit] = title;
	PerUnitLabel[unit] = label;
	PerUnitMultiplier[unit] = multiplier;
}	

//*****************************************************************************
// CDimUnit implementation

CDimUnit::CDimUnit(const DIM_UNIT value, char* section, char* entry)
	: m_value(value), m_section(section), m_entry(entry)
{
}

void CDimUnit::Init(const DIM_UNIT value, char* section, char* entry)
{
	m_value = value;
	m_section = section;
	m_entry = entry;
}

void CDimUnit::SetTitleS(const char* title)
{
	int unit;

	for (unit = UNDEFINED_DIM_UNIT + 1; unit < LAST_DIM_UNIT; unit++)
	{
		if (strstr(title, DimUnitTitle[unit]) != NULL)
			break;
	}
	if (unit == LAST_DIM_UNIT)
		unit = UNDEFINED_DIM_UNIT;
		
	Set(static_cast<DIM_UNIT>(unit));
}

void CDimUnit::SetLabelS(const char* label)
{
	int unit;

	for (unit = UNDEFINED_DIM_UNIT + 1; unit < LAST_DIM_UNIT; unit++)
	{
		if (strstr(label, DimUnitLabel[unit]) != NULL)
			break;
	}
	if (unit == LAST_DIM_UNIT)
		unit = UNDEFINED_DIM_UNIT;
		
	Set(static_cast<DIM_UNIT>(unit));
}

char* CDimUnit::GetTitleS(char* title)
{
	sprintf(title, "%s", DimUnitTitle[m_value]);
	return title;
}

char* CDimUnit::GetLabelS(char* label)
{
	sprintf(label, "%s", DimUnitLabel[m_value]);
	return label;
}

void CDimUnit::Erase(const char* ini_file)
{
	WritePrivateProfileString(m_section, NULL, NULL, ini_file);
}

void CDimUnit::Save(const char* ini_file)
{
	char buffer[VALUESTRINGLENGTH];

	GetTitleS(buffer);
	WritePrivateProfileString(m_section, m_entry, buffer, ini_file);
}

void CDimUnit::Restore(const char* ini_file)
{
	char buffer[VALUESTRINGLENGTH];

	GetPrivateProfileString(m_section, m_entry, "", buffer, sizeof(buffer), ini_file);
	if (strcmp(buffer, "") != 0)
		SetTitleS(buffer);
}

//*****************************************************************************
// CPerUnit implementation

CPerUnit::CPerUnit(const PER_UNIT value, char* section, char* entry)
	: m_value(value), m_section(section), m_entry(entry)
{
}

void CPerUnit::Init(const PER_UNIT value, char* section, char* entry)
{
	m_value = value;
	m_section = section;
	m_entry = entry;
}

void CPerUnit::SetTitleS(const char* title)
{
	int unit;
	
	for (unit = UNDEFINED_PER_UNIT + 1; unit < LAST_PER_UNIT; unit++)
	{
		if (strstr(title, PerUnitTitle[unit]) != NULL)
			break;
	}
	if (unit == LAST_PER_UNIT)
		unit = UNDEFINED_PER_UNIT;
		
	Set(static_cast<PER_UNIT>(unit));
}

void CPerUnit::SetLabelS(const char* label)
{
	int unit;
	
	for (unit = UNDEFINED_PER_UNIT + 1; unit < LAST_PER_UNIT; unit++)
	{
		if (strstr(label, PerUnitLabel[unit]) != NULL)
			break;
	}
	if (unit == LAST_PER_UNIT)
		unit = UNDEFINED_PER_UNIT;
		
	Set(static_cast<PER_UNIT>(unit));
}

char* CPerUnit::GetTitleS(char* title)
{
	sprintf(title, "%s", PerUnitTitle[m_value]);
	return title;
}

char* CPerUnit::GetLabelS(char* label)
{
	sprintf(label, "%s", PerUnitLabel[m_value]);
	return label;
}

void CPerUnit::Erase(const char* ini_file)
{
	WritePrivateProfileString(m_section, NULL, NULL, ini_file);
}

void CPerUnit::Save(const char* ini_file)
{
	char buffer[VALUESTRINGLENGTH];

	GetTitleS(buffer);	
	WritePrivateProfileString(m_section, m_entry, buffer, ini_file);
}

void CPerUnit::Restore(const char* ini_file)
{
	char buffer[VALUESTRINGLENGTH];

	GetPrivateProfileString(m_section, m_entry, "", buffer, sizeof(buffer), ini_file);
	if (strcmp(buffer, "") != 0)
		SetTitleS(buffer);
}

//*****************************************************************************
// CDimension implementation

CDimension::CDimension(const DIM_UNIT unit, const double value, char* section, char* entry)
{
	Init(unit, value, section, entry);
}

void CDimension::Init(const DIM_UNIT unit, const double value, char* section, char* entry)
{
	m_set_unit = unit;
	m_set_value = value;
	m_internal_value = m_set_value / DimUnitMultiplier[m_set_unit];
	m_get_unit = UNDEFINED_DIM_UNIT;
	m_get_value = 0.0;
	m_section = section;
	m_entry = entry;
}

void CDimension::Set(DIM_UNIT unit, double value)
{
	m_set_unit = unit;
	m_set_value = value;
	m_internal_value = m_set_value / DimUnitMultiplier[m_set_unit];
	m_get_unit = UNDEFINED_DIM_UNIT;
	m_get_value = 0.0;
}

void CDimension::SetS(const char* str)
{
	int unit;
	double value;
	
	// Read numerial value from string
	if (sscanf(str, "%lf", &value) != 1)
		value = 0.0;

	for (unit = UNDEFINED_DIM_UNIT + 1; unit < LAST_DIM_UNIT; unit++)
	{
		if (strstr(str, DimUnitLabel[unit]) != NULL)
			break;
	}
	if (unit == LAST_DIM_UNIT)
		unit = UNDEFINED_DIM_UNIT;
		
	Set((DIM_UNIT)unit, value);
}

double CDimension::Get(DIM_UNIT unit)
{
	// Check whether this is a request for the value in the same units as last request
	if (m_get_unit != unit)
	{
		// This is a request for the value in new units, do the conversion and save for future requests.
		m_get_unit = unit;
		m_get_value = m_internal_value * DimUnitMultiplier[unit];
	}
	return m_get_value;
}

char* CDimension::GetS(DIM_UNIT unit, char* str, int precision)
{
	char* format = "%.*g %s";
		
	if (unit == UNDEFINED_DIM_UNIT)
		// If no specific units requested, return string with 'set' units
		sprintf(str, format, precision, m_set_value, DimUnitLabel[m_set_unit]);
	else
		sprintf(str, format, precision, Get(unit), DimUnitLabel[unit]);
		
	return str;
}

char* CDimension::GetS(char* str, int precision)
{
	return GetS(UNDEFINED_DIM_UNIT, str, precision);
}

void CDimension::Erase(const char* ini_file)
{
	WritePrivateProfileString(m_section, NULL, NULL, ini_file);
}

void CDimension::Save(const char* ini_file, int precision)
{
	char buffer[VALUESTRINGLENGTH];

	GetS(buffer, precision);
	WritePrivateProfileString(m_section, m_entry, buffer, ini_file);
}

void CDimension::Restore(const char* ini_file)
{
	char buffer[VALUESTRINGLENGTH];

	GetPrivateProfileString(m_section, m_entry, "", buffer, sizeof(buffer), ini_file);
	if (strcmp(buffer, "") != 0)
		SetS(buffer);
}

//*****************************************************************************
// CPeriod implementation

CPeriod::CPeriod(const PER_UNIT unit, const double value, char* section, char* entry)
{
	Init(unit, value, section, entry);
}

void CPeriod::Init(const PER_UNIT unit, const double value, char* section, char* entry)
{
	m_set_unit = unit;
	m_set_value = value;
	m_internal_value = m_set_value / PerUnitMultiplier[m_set_unit];
	m_get_unit = UNDEFINED_PER_UNIT;
	m_get_value = 0.0;
	m_section = section;
	m_entry = entry;
}

void CPeriod::Set(PER_UNIT unit, double value)
{
	m_set_unit = unit;
	m_set_value = value;
	m_internal_value = m_set_value / PerUnitMultiplier[m_set_unit];
	m_get_unit = UNDEFINED_PER_UNIT;
	m_get_value = 0.0;
}

void CPeriod::SetS(const char* str)
{
	int unit;
	double value;
	
	// Read numerial value from string
	sscanf(str, "%lf", &value);

	for (unit = UNDEFINED_PER_UNIT + 1; unit < LAST_PER_UNIT; unit++)
	{
		if (strstr(str, PerUnitLabel[unit]) != NULL)
			break;
	}
	if (unit == LAST_PER_UNIT)
		unit = UNDEFINED_PER_UNIT;
		
	Set(static_cast<PER_UNIT>(unit), value);
}

double CPeriod::Get(PER_UNIT unit)
{
	// Check whether this is a request for the value in the same units as last request
	if (m_get_unit != unit)
	{
		// If this is a request for the value in new units, do the conversion and save
		//  it for future requests.
		m_get_unit = unit;
		m_get_value = m_internal_value * PerUnitMultiplier[unit];
	}
	return m_get_value;
}

char* CPeriod::GetS(PER_UNIT unit, char* str, int precision)
{
	char* format = "%.*g %s";
		
	if (unit == UNDEFINED_PER_UNIT)
		// If no specific units requested, return string with 'set' units
		sprintf(str, format, precision, m_set_value, PerUnitLabel[m_set_unit]);
	else
		sprintf(str, format, precision, Get(unit), PerUnitLabel[unit]);
		
	return str;
}

char* CPeriod::GetS(char* str, int precision)
{
	return GetS(UNDEFINED_PER_UNIT, str, precision);
}

void CPeriod::Erase(const char* ini_file)
{
	WritePrivateProfileString(m_section, NULL, NULL, ini_file);
}

void CPeriod::Save(const char* ini_file, int precision)
{
	char buffer[VALUESTRINGLENGTH];

	GetS(buffer, precision);	
	WritePrivateProfileString(m_section, m_entry, buffer, ini_file);
}

void CPeriod::Restore(const char* ini_file)
{
	char buffer[VALUESTRINGLENGTH];

	GetPrivateProfileString(m_section, m_entry, "", buffer, sizeof(buffer), ini_file);
	if (strcmp(buffer, "") != 0)
		SetS(buffer);
}


//*****************************************************************************
// CScale implementation

CScale::CScale(const DIM_UNIT unit, const double value, char* section, char* entry)
{
	Init(unit, value, section, entry);
}

void CScale::Init(const DIM_UNIT unit, const double value, char* section, char* entry)
{
	m_set_unit = unit;
	m_set_value = value;
	m_internal_value = m_set_value * DimUnitMultiplier[m_set_unit];
	m_get_unit = UNDEFINED_DIM_UNIT;
	m_get_value = 0.0;
	m_section = section;
	m_entry = entry;
}

void CScale::Set(DIM_UNIT unit, double value)
{
	m_set_unit = unit;
	m_set_value = value;
	m_internal_value = m_set_value * DimUnitMultiplier[m_set_unit];
	m_get_unit = UNDEFINED_DIM_UNIT;
	m_get_value = 0.0;
}

void CScale::SetS(const char* str)
{
	int unit;
	double value;
	
	// Read numerial value from string
	sscanf(str, "%lf", &value);

	for (unit = UNDEFINED_DIM_UNIT + 1; unit < LAST_DIM_UNIT; unit++)
	{
		if (strstr(str, DimUnitLabel[unit]) != NULL)
			break;
	}
	if (unit == LAST_DIM_UNIT)
		unit = UNDEFINED_DIM_UNIT;
		
	Set(static_cast<DIM_UNIT>(unit), value);
}

double CScale::Get(DIM_UNIT unit)
{
	// Check whether this is a request for the value in the same units as last request
	if (m_get_unit != unit)
	{
		// If request is for new units, do the conversion and save for future requests.
		m_get_unit = unit;
		m_get_value = m_internal_value / DimUnitMultiplier[unit];
	}
	return m_get_value;
}

char* CScale::GetS(DIM_UNIT unit, char* str, int precision)
{
	char* format = "%.*g counts/%s";
		
	// Create string containing value and units label
	if (unit == UNDEFINED_DIM_UNIT)
		// If no specific units requested, return string with 'set' units
		sprintf(str, format, precision, m_set_value, DimUnitLabel[m_set_unit]);
	else
		sprintf(str, format, precision, Get(unit), DimUnitLabel[unit]);
		
	return str;
}

char* CScale::GetS(char* str, int precision)
{
	return GetS(UNDEFINED_DIM_UNIT, str, precision);
}

void CScale::Erase(const char* ini_file)
{
	WritePrivateProfileString(m_section, NULL, NULL, ini_file);
}

void CScale::Save(const char* ini_file, int precision)
{
	char buffer[VALUESTRINGLENGTH];

	GetS(buffer, precision);	
	WritePrivateProfileString(m_section, m_entry, buffer, ini_file);
}

void CScale::Restore(const char* ini_file)
{
	char buffer[VALUESTRINGLENGTH];

	GetPrivateProfileString(m_section, m_entry, "", buffer, sizeof(buffer), ini_file);
	if (strcmp(buffer, "") != 0)
		SetS(buffer);
}

//*****************************************************************************
// CSpeed implementation

CSpeed::CSpeed(const DIM_UNIT dim_unit, const PER_UNIT per_unit, const double value, char* section, char* entry)
{
	Init(dim_unit, per_unit, value, section, entry);
}

void CSpeed::Init(const DIM_UNIT dim_unit, const PER_UNIT per_unit, const double value, char* section, char* entry)
{
	m_set_dim_unit = dim_unit;
	m_set_per_unit = per_unit;
	m_set_value = value;
	m_internal_value = m_set_value * PerUnitMultiplier[m_set_per_unit] / DimUnitMultiplier[m_set_dim_unit];
	m_get_dim_unit = UNDEFINED_DIM_UNIT;
	m_get_per_unit = UNDEFINED_PER_UNIT;
	m_get_value = 0.0;
	m_section = section;
	m_entry = entry;
}

void CSpeed::Set(DIM_UNIT dim_unit, PER_UNIT per_unit, double value)
{
	m_set_dim_unit = dim_unit;
	m_set_per_unit = per_unit;
	m_set_value = value;
	m_internal_value = m_set_value * PerUnitMultiplier[m_set_per_unit] / DimUnitMultiplier[m_set_dim_unit];
	m_get_dim_unit = UNDEFINED_DIM_UNIT;
	m_get_per_unit = UNDEFINED_PER_UNIT;
	m_get_value = 0.0;
}

void CSpeed::SetS(const char* str)
{
	int dim_unit;
	int per_unit;
	double value;
	const char* sep_pos;
	
	// Read numerial value from string
	if (sscanf(str, "%lf", &value) != 1)
		value = 0.0;

	for (dim_unit = UNDEFINED_DIM_UNIT + 1; dim_unit < LAST_DIM_UNIT; dim_unit++)
	{
		const char* dim_pos;
		if (((dim_pos = strstr(str, DimUnitLabel[dim_unit])) != NULL) &&
					((sep_pos = strchr(str, UNIT_SEPARATOR)) != NULL) &&
						(dim_pos < sep_pos))
			break;
	}
	if (dim_unit == LAST_DIM_UNIT)
		dim_unit = UNDEFINED_DIM_UNIT;
		
	for (per_unit = UNDEFINED_PER_UNIT + 1; per_unit < LAST_PER_UNIT; per_unit++)
	{
		const char* per_pos;
		if (((per_pos = strstr(str, PerUnitLabel[per_unit])) != NULL) &&
				(per_pos > sep_pos))
			break;
	}
	if (per_unit == LAST_PER_UNIT)
		per_unit = UNDEFINED_PER_UNIT;
		
	Set(static_cast<DIM_UNIT>(dim_unit), static_cast<PER_UNIT>(per_unit), value);
}

double CSpeed::Get(DIM_UNIT dim_unit, PER_UNIT per_unit)
{
	// Check whether this is a request for the value in the same units as last request
	if ((m_get_dim_unit != dim_unit) || (m_get_per_unit != per_unit))
	{
		// If request is for new units, do the conversion and save for future requests.
		m_get_dim_unit = dim_unit;
		m_get_per_unit = per_unit;
		m_get_value = m_internal_value * DimUnitMultiplier[dim_unit] / PerUnitMultiplier[per_unit];
	}
	return m_get_value;
}

char* CSpeed::GetS(DIM_UNIT dim_unit, PER_UNIT per_unit, char* str, int precision)
{
	char* format = "%.*g %s/%s";
		
	// Create string containing value and units label
	if ((dim_unit == UNDEFINED_DIM_UNIT) || (per_unit == UNDEFINED_PER_UNIT))
		// If no specific units requested, return string with 'set' units
		sprintf(str, format, precision, m_set_value, DimUnitLabel[m_set_dim_unit], PerUnitLabel[m_set_per_unit]);
	else
		sprintf(str, format, precision, Get(dim_unit, per_unit), DimUnitLabel[dim_unit], PerUnitLabel[per_unit]);
		
	return str;
}

char* CSpeed::GetS(char* str, int precision)
{
	return(GetS(UNDEFINED_DIM_UNIT, UNDEFINED_PER_UNIT, str, precision));
}

void CSpeed::Erase(const char* ini_file)
{
	WritePrivateProfileString(m_section, NULL, NULL, ini_file);
}

void CSpeed::Save(const char* ini_file, int precision)
{
	char buffer[VALUESTRINGLENGTH];

	GetS(buffer, precision);	
	WritePrivateProfileString(m_section, m_entry, buffer, ini_file);
}

void CSpeed::Restore(const char* ini_file)
{
	char buffer[VALUESTRINGLENGTH];

	GetPrivateProfileString(m_section, m_entry, "", buffer, sizeof(buffer), ini_file);
	if (strcmp(buffer, "") != 0)
		SetS(buffer);
}

//*****************************************************************************
// CAcceleration implementation

CAcceleration::CAcceleration(const DIM_UNIT dim_unit, const PER_UNIT per_unit, const double value, char* section, char* entry)
{
	Init(dim_unit, per_unit, value, section, entry);
}

void CAcceleration::Init(const DIM_UNIT dim_unit, const PER_UNIT per_unit, const double value, char* section, char* entry)
{
	m_set_dim_unit = dim_unit;
	m_set_per_unit = per_unit;
	m_set_value = value;
	m_internal_value = m_set_value * PerUnitMultiplier[m_set_per_unit] * PerUnitMultiplier[m_set_per_unit] / DimUnitMultiplier[m_set_dim_unit];
	m_get_dim_unit = UNDEFINED_DIM_UNIT;
	m_get_per_unit = UNDEFINED_PER_UNIT;
	m_get_value = 0.0;
	m_section = section;
	m_entry = entry;
}

void CAcceleration::Set(DIM_UNIT dim_unit, PER_UNIT per_unit, double value)
{
	m_set_dim_unit = dim_unit;
	m_set_per_unit = per_unit;
	m_set_value = value;
	m_internal_value = m_set_value * PerUnitMultiplier[m_set_per_unit] * PerUnitMultiplier[m_set_per_unit] / DimUnitMultiplier[m_set_dim_unit];
	m_get_dim_unit = UNDEFINED_DIM_UNIT;
	m_get_per_unit = UNDEFINED_PER_UNIT;
	m_get_value = 0.0;
}

void CAcceleration::SetS(const char* str)
{
	int dim_unit;
	int per_unit;
	double value;
	const char* sep_pos;
	
	// Read numerial value from string
	if (sscanf(str, "%lf", &value)!=1)
		value = 0.0;

	for (dim_unit = UNDEFINED_DIM_UNIT + 1; dim_unit < LAST_DIM_UNIT; dim_unit++)
	{
		const char* dim_pos;
		if (((dim_pos = strstr(str, DimUnitLabel[dim_unit])) != NULL) &&
					((sep_pos = strchr(str, UNIT_SEPARATOR)) != NULL) &&
						(dim_pos < sep_pos))
			break;
	}
	if (dim_unit == LAST_DIM_UNIT)
		dim_unit = UNDEFINED_DIM_UNIT;
		
	for (per_unit = UNDEFINED_PER_UNIT+1; per_unit<LAST_PER_UNIT; per_unit++)
	{
		const char* per_pos;
		if (((per_pos = strstr(str, PerUnitLabel[per_unit])) != NULL) &&
				(per_pos > sep_pos))
			break;
	}
	if (per_unit == LAST_PER_UNIT)
		per_unit = UNDEFINED_PER_UNIT;
		
	Set(static_cast<DIM_UNIT>(dim_unit), static_cast<PER_UNIT>(per_unit), value);
}

double CAcceleration::Get(DIM_UNIT dim_unit, PER_UNIT per_unit)
{
	// Check whether this is a request for the value in the same units as last request
	if ((m_get_dim_unit != dim_unit) || (m_get_per_unit != per_unit))
	{
		// If request is for new units, do the conversion and save for future requests.
		m_get_dim_unit = dim_unit;
		m_get_per_unit = per_unit;
		m_get_value = m_internal_value * DimUnitMultiplier[dim_unit] / PerUnitMultiplier[per_unit] / PerUnitMultiplier[m_set_per_unit];
	}
	return(m_get_value);
}

char* CAcceleration::GetS(DIM_UNIT dim_unit, PER_UNIT per_unit, char* str, int precision)
{
	char* format = "%.*g %s/%s/%s";
		
	// Create string containing value and units label
	if ((dim_unit == UNDEFINED_DIM_UNIT) || (per_unit == UNDEFINED_PER_UNIT))
		// If no specific units requested, return string with 'set' units
		sprintf(str, format, precision, m_set_value, DimUnitLabel[m_set_dim_unit], PerUnitLabel[m_set_per_unit], PerUnitLabel[m_set_per_unit]);
	else
		sprintf(str, format, precision, Get(dim_unit, per_unit), DimUnitLabel[dim_unit], PerUnitLabel[per_unit], PerUnitLabel[per_unit]);
		
	return str;
}

char* CAcceleration::GetS(char* str, int precision)
{
	return(GetS(UNDEFINED_DIM_UNIT, UNDEFINED_PER_UNIT, str, precision));
}

void CAcceleration::Erase(const char* ini_file)
{
	WritePrivateProfileString(m_section, NULL, NULL, ini_file);
}

void CAcceleration::Save(const char* ini_file, int precision)
{
	char buffer[VALUESTRINGLENGTH];

	GetS(buffer, precision);	
	WritePrivateProfileString(m_section, m_entry, buffer, ini_file);
}

void CAcceleration::Restore(const char* ini_file)
{
	char buffer[VALUESTRINGLENGTH];

	GetPrivateProfileString(m_section, m_entry, "", buffer, sizeof(buffer), ini_file);
	if (strcmp(buffer, "") != 0)
		SetS(buffer);
}
