//
//  app_classes.h - application variable class header file
//
//  $Id: app_classes.h 37 2014-02-06 17:38:11Z brian $ 
//
//  Copyright (c) 1999-2014 by Precision Micro Control Corp. All rights reserved.
//
#ifndef APP_CLASSES_H
#define APP_CLASSES_H

//*********************************************************************************
// Dimension (length) units declarations

#define UNIT_SEPARATOR	'/'		// Separator between units

// Dimension units enumerated data type
//  Types must be ordered so that there are no ambiguities when searching
//	for Titles and Labels. For example: since meter units have 'm' for the
//	label, its' placement in the enumeration list must follow all others that
//	have and 'm' in the label.
typedef enum {
	UNDEFINED_DIM_UNIT,
	REVOLUTION_UNIT,
	DEGREE_UNIT,
	RADIAN_UNIT,
	HUNDRETHMIL_UNIT,
	TENTHMIL_UNIT,
	MIL_UNIT,
	INCH_UNIT,
	FEET_UNIT,
	YARD_UNIT,
	MICROMETER_UNIT,
	HUNDRETHMM_UNIT,
	TENTHMM_UNIT,
	MILLIMETER_UNIT,
	CENTIMETER_UNIT,
	DECIMETER_UNIT,
	METER_UNIT,			// See comment above regarding placement of meter unit
	LAST_DIM_UNIT
} DIM_UNIT;

#define MAX_DIM_UNITS 20	// Number of items in DIM_UNIT enumerated data type
#define DEFAULT_DIM_UNIT	INCH_UNIT
#define DEFAULT_DIM_UNIT_LABEL	INCH_UNIT_LABEL

#define UNDEFINED_DIM_UNIT_TITLE	"UNDEFINED"
#define REVOLUTION_UNIT_TITLE	"REVOLUTION"
#define DEGREE_UNIT_TITLE		"DEGREE"
#define RADIAN_UNIT_TITLE		"RADIAN"
#define HUNDRETHMIL_UNIT_TITLE	"1/100000 INCH"
#define TENTHMIL_UNIT_TITLE		"1/10000 INCH"
#define MIL_UNIT_TITLE			"1/1000 INCH"
#define INCH_UNIT_TITLE			"INCH"
#define FEET_UNIT_TITLE			"FEET"
#define YARD_UNIT_TITLE			"YARD"
#define MICROMETER_UNIT_TITLE	"MICROMETER"
#define HUNDRETHMM_UNIT_TITLE	"1/100 MILLIMETER"
#define TENTHMM_UNIT_TITLE		"1/10 MILLIMETER"
#define MILLIMETER_UNIT_TITLE	"MILLIMETER"
#define CENTIMETER_UNIT_TITLE	"CENTIMETER"
#define DECIMETER_UNIT_TITLE	"DECIMETER"
#define METER_UNIT_TITLE		"METER"

#define UNDEFINED_DIM_UNIT_LABEL	"???"
#define REVOLUTION_UNIT_LABEL	"rev"
#define DEGREE_UNIT_LABEL		"deg"
#define RADIAN_UNIT_LABEL		"rad"
#define TENTHMIL_UNIT_LABEL		"hmil"
#define HUNDRETHMIL_UNIT_LABEL	"tmil"
#define MIL_UNIT_LABEL			"mil"
#define INCH_UNIT_LABEL			"in"
#define FEET_UNIT_LABEL			"ft"
#define YARD_UNIT_LABEL			"yd"
#define MICROMETER_UNIT_LABEL	"um"
#define HUNDRETHMM_UNIT_LABEL	"cmm"
#define TENTHMM_UNIT_LABEL		"dmm"
#define MILLIMETER_UNIT_LABEL	"mm"
#define CENTIMETER_UNIT_LABEL	"cm"
#define DECIMETER_UNIT_LABEL	"dm"
#define METER_UNIT_LABEL		"m"

// Unit conversion factors. These are relative to internal units which can be
// anything. Internal unit times multiplier converts to respective unit
#define UNDEFINED_DIM_UNIT_MULTIPLIER		1.0
// For linear units, internal units are arbitrarily chosen as meters
#define HUNDRETHMIL_UNIT_MULTIPLIER	3937007.8
#define TENTHMIL_UNIT_MULTIPLIER	393700.78
#define MIL_UNIT_MULTIPLIER			39370.078
#define INCH_UNIT_MULTIPLIER		39.370078
#define FEET_UNIT_MULTIPLIER		0.3048
#define YARD_UNIT_MULTIPLIER		0.9144

#define MICROMETER_UNIT_MULTIPLIER	1000000.0
#define HUNDRETHMM_UNIT_MULTIPLIER	100000.0
#define TENTHMM_UNIT_MULTIPLIER		10000.0
#define MILLIMETER_UNIT_MULTIPLIER	1000.0
#define CENTIMETER_UNIT_MULTIPLIER	100.0
#define DECIMETER_UNIT_MULTIPLIER	10.0
#define METER_UNIT_MULTIPLIER		1.0

// For angle units, internal units are arbitrarily chosen as one revolution
#define REVOLUTION_UNIT_MULTIPLIER	1.0
#define DEGREE_UNIT_MULTIPLIER	360.0
#define RADIAN_UNIT_MULTIPLIER	6.28		// 2 * pi

//*********************************************************************************
// Period (time) units declarations

// Period units enumerated data type
//  Types must be ordered so that there are no ambiguities when searching
//	for Titles and Labels. For example: since second units have 'sec' for the
//	label, its' placement in the enumeration list must follow all others that
//	have and 'sec' in the label.
typedef enum {
	UNDEFINED_PER_UNIT,
	MILLISECOND_UNIT,
	SECOND_UNIT,
	MINUTE_UNIT,
	HOUR_UNIT,
	DAY_UNIT,
	LAST_PER_UNIT
} PER_UNIT;

#define MAX_PER_UNITS 10	// Number of items in DIM_UNIT enumerated data type
#define DEFAULT_PER_UNIT		SECOND_UNIT
#define DEFAULT_PER_UNIT_LABEL	SECOND_UNIT_LABEL

#define UNDEFINED_PER_UNIT_TITLE	"UNDEFINED"
#define MILLISECOND_UNIT_TITLE		"MILLISECOND"
#define SECOND_UNIT_TITLE			"SECOND"
#define MINUTE_UNIT_TITLE			"MINUTE"
#define HOUR_UNIT_TITLE				"HOUR"
#define DAY_UNIT_TITLE				"DAY"

#define UNDEFINED_PER_UNIT_LABEL	"???"
#define MILLISECOND_UNIT_LABEL		"msec"
#define SECOND_UNIT_LABEL			"sec"
#define MINUTE_UNIT_LABEL			"min"
#define HOUR_UNIT_LABEL				"hr"
#define DAY_UNIT_LABEL				"day"

// Unit conversion factors. These are relative to internal units which can be
// anything. Internal unit times multiplier converts to respective unit
#define UNDEFINED_PER_UNIT_MULTIPLIER		1.0
// For period units, internal units are arbitrarily chosen as seconds
#define MILLISECOND_UNIT_MULTIPLIER		1000.0
#define SECOND_UNIT_MULTIPLIER			1.0
#define MINUTE_UNIT_MULTIPLIER			(1/60.0)
#define HOUR_UNIT_MULTIPLIER			(1/3600.0)
#define DAY_UNIT_MULTIPLIER				(1/86400.0)

/// <summary>
/// A registerable item has three member functions erase, save and restore. This is an abstract base class.
/// </summary>
class CRegisterableItem
{
public:
	/// <summary>Erase this item from an INI file. Note that the entire INI section is deleted.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	virtual void				Erase(const char* ini_file) = 0;
	/// <summary>Save this item to an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	virtual void				Save(const char* ini_file) = 0;
	/// <summary>Restore this item from an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	virtual void				Restore(const char* ini_file) = 0;
};

/// <summary>
/// Similar to CRegisterableItem, has three member functions erase, save and restore. Items of this type
/// must specify the required sprintf() precision when saving their value. This is an abstract base class.
/// </summary>
class CRegisterableItemWithPrecision
{
public:
	/// <summary>Erase this item from an INI file. Note that the entire INI section is deleted.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	virtual void				Erase(const char* ini_file) = 0;
	/// <summary>Save this item to an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	virtual void				Save(const char* ini_file, int precision) = 0;
	/// <summary>Restore this item from an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	virtual void				Restore(const char* ini_file) = 0;
};

/// <summary>
/// An Application Integer is able to save and restore its' value.
/// </summary>
class CAppInt : public CRegisterableItem
{
public:
	/// <summary>Constructor.</summary>
	/// <param name="value">Integer value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	CAppInt(const int value = 0, char* section = NULL, char* entry = NULL);
	/// <summary>Destructor.</summary>
	~CAppInt() {}
	/// <summary>Cast to int.</summary>
	/// <returns>Current integer value.</returns>
	operator int() const { return m_value; }
	/// <summary>Assignment.</summary>
	/// <param name="value">Integer value to represent.</param>
	void operator= (int value) { m_value = value; }

	/// <summary>Initialize a CAppInt object.</summary>
	/// <param name="value">Integer value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	void						Init(const int value, char* section, char* entry);
	/// <summary>Erase this item from an INI file. Note that the entire INI section is deleted.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Erase(const char* ini_file);
	/// <summary>Save this item to an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Save(const char* ini_file);
	/// <summary>Restore this item from an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Restore(const char* ini_file);

private:
	int							m_value;						///< integer value this object represents
	char*						m_section;						///< INI file section name string
	char*						m_entry;						///< INI file entry name string
};

/// <summary>
/// An Application Double is able to save and restore its' value.
/// </summary>
class CAppDouble : public CRegisterableItemWithPrecision
{
public:
	/// <summary>Constructor.</summary>
	/// <param name="value">Double precision value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	CAppDouble(const double value = 0.0, char* section = NULL, char* entry = NULL);
	/// <summary>Destructor.</summary>
	~CAppDouble() {}
	/// <summary>Cast to double.</summary>
	/// <returns>Current double precision value.</returns>
	operator double() const { return m_value; }
	/// <summary>Assignment.</summary>
	/// <param name="value">Double precision value to represent.</param>
	void operator= (double value) { m_value = value; }

	/// <summary>Initialize a CAppDouble object.</summary>
	/// <param name="value">Double precision value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	void						Init(const double value, char* section, char* entry);
	/// <summary>Erase this item from an INI file. Note that the entire INI section is deleted.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Erase(const char* ini_file);
	/// <summary>Save this item to an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	void						Save(const char* ini_file, int precision);
	/// <summary>Restore this item from an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Restore(const char* ini_file);

private:
	double						m_value;						///< double precision value this object represents
	char*						m_section;						///< INI file section name string
	char*						m_entry;						///< INI file entry name string
};

/// <summary>
/// An Application String is able to save and restore its' value.
/// </summary>
class CAppString : public CRegisterableItem
{
public:
	/// <summary>Constructor.</summary>
	/// <param name="value">String value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	CAppString(const char* string = NULL, char* section = NULL, char* entry = NULL);
	/// <summary>Destructor.</summary>
	~CAppString() {}
	/// <summary>Cast to string.</summary>
	/// <returns>Current string value.</returns>
	operator const char* () const { return (const char*)m_value; }
	/// <summary>Assignment.</summary>
	/// <param name="value">String value to represent.</param>
	void operator= (const char* value) { m_value = value; }

	/// <summary>Initialize a CAppString object.</summary>
	/// <param name="value">String value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	void						Init(const char* string, char* section, char* entry);
	/// <summary>Erase this item from an INI file. Note that the entire INI section is deleted.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Erase(const char* ini_file);
	/// <summary>Save this item to an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Save(const char* ini_file);
	/// <summary>Restore this item from an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Restore(const char* ini_file);

private:
	CString						m_value;						///< string value this object represents
	char*						m_section;						///< INI file section name string
	char*						m_entry;						///< INI file entry name string
};

//*****************************************************************************
// Units management data
//  this data is common to all objects of the respective type
extern char* DimUnitTitle[MAX_DIM_UNITS];
extern char* DimUnitLabel[MAX_DIM_UNITS];
extern double DimUnitMultiplier[MAX_DIM_UNITS];

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

void InitDimUnits();
void InitDimUnit(DIM_UNIT unit, char* title, char* label, double multiplier);
	
void InitPerUnits();
void InitPerUnit(PER_UNIT unit, char* title, char* label, double multiplier);
	
// The CDimUnit class defines objects that store a dimension unit (see DIM_UNIT typedef).
//
/// <summary>
/// CDimUnit stores a dimension unit (see DIM_UNIT typedef).
/// </summary>
class CDimUnit : public CRegisterableItem
{
public:
	/// <summary>Constructor.</summary>
	/// <param name="value">Dimension unit value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	CDimUnit(const DIM_UNIT value = UNDEFINED_DIM_UNIT, char* section = NULL, char* entry = NULL);
	/// <summary>Destructor.</summary>
	~CDimUnit() {}

	/// <summary>Initialize a CDimUnit object.</summary>
	/// <param name="value">Dimension unit value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	void						Init(const DIM_UNIT value, char* section, char* entry);
	/// <summary>Set dimension unit value.</summary>
	/// <param name="value">Dimension unit value to represent.</param>
	void						Set(DIM_UNIT value) { m_value = value; }
	/// <summary>Set dimension unit from string contents. String must contain unit title text example: IN.</summary>
	/// <param name="title">Title string.</param>
	void						SetTitleS(const char* title);
	/// <summary>Set dimension unit from string contents. String must contain unit label text example: in.</summary>
	/// <param name="label">Label string.</param>
	void						SetLabelS(const char* label);
	/// <summary>Get dimension unit value.</summary>
	/// <returns>Dimension unit.</returns>
	DIM_UNIT					Get() { return m_value; }
	/// <summary>Get dimension unit multiplier value.</summary>
	/// <returns>Multiplier.</returns>
	double						GetMultiplier() { return DimUnitMultiplier[m_value]; }
	/// <summary>Get unit title value.</summary>
	/// <returns>Title string.</returns>
	char*						GetTitleS(char* title);
	/// <summary>Get unit label value.</summary>
	/// <returns>Label string.</returns>
	char*						GetLabelS(char* label);
	
	/// <summary>Erase this item from an INI file. Note that the entire INI section is deleted.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Erase(const char* ini_file);
	/// <summary>Save this item to an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Save(const char* ini_file);
	/// <summary>Restore this item from an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Restore(const char* ini_file);

private:
	DIM_UNIT					m_value;						///< dimension unit value this object represents
	char*						m_section;						///< INI file section name string
	char*						m_entry;						///< INI file entry name string
};

/// <summary>
/// CPerUnit stores a time period unit (see PER_UNIT typedef).
/// </summary>
class CPerUnit : public CRegisterableItem
{
public:
	/// <summary>Constructor.</summary>
	/// <param name="value">Time period unit value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	CPerUnit(const PER_UNIT value = UNDEFINED_PER_UNIT, char* section = NULL, char* entry = NULL);
	/// <summary>Destructor.</summary>
	~CPerUnit() {}

	/// <summary>Initialize a CPerUnit object.</summary>
	/// <param name="value">Time period unit value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	void						Init(const PER_UNIT value, char* section, char* entry);
	/// <summary>Set time period unit value.</summary>
	/// <param name="value">Time period unit value to represent.</param>
	void						Set(PER_UNIT value) { m_value = value; }
	/// <summary>Set time period unit from string contents. String must contain unit title text example: SECOND.</summary>
	/// <param name="title">Title string.</param>
	void						SetTitleS(const char* title);
	/// <summary>Set time period unit from string contents. String must contain unit label text example: sec.</summary>
	/// <param name="label">Label string.</param>
	void						SetLabelS(const char* label);
	/// <summary>Get time period unit value.</summary>
	/// <returns>Dimension unit.</returns>
	PER_UNIT					Get() { return m_value; }
	/// <summary>Get time period unit multiplier value.</summary>
	/// <returns>Multiplier.</returns>
	double						GetMultiplier() { return PerUnitMultiplier[m_value]; }
	/// <summary>Get time period unit title value.</summary>
	/// <returns>Title string.</returns>
	char*						GetTitleS(char* title);
	/// <summary>Get time period unit label value.</summary>
	/// <returns>Label string.</returns>
	char*						GetLabelS(char* label);
	
	/// <summary>Erase this item from an INI file. Note that the entire INI section is deleted.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Erase(const char* ini_file);
	/// <summary>Save this item to an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Save(const char* ini_file);
	/// <summary>Restore this item from an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Restore(const char* ini_file);

private:
	PER_UNIT					m_value;						///< time period unit value this object represents
	char*						m_section;						///< INI file section name string
	char*						m_entry;						///< INI file entry name string
};

/// <summary>
/// CDimension objects have a real value in internal length units
/// </summary>
/// <remarks>
/// <para>The internal value is set by member functions taking a value and a dimension
/// units specifier (see DIM_UNIT typedef). The value of the object can be retrieved by
/// member functions that allow the caller to specify the desired dimension units.
/// example:
///
///   CDimension Length(INCH, 1.0);
///   double value = Length.Get(MILLIMETER);
///
/// With this code, value would contain 25.4 after execution (the number of millimeters
/// in one inch).</para>
/// </remarks>
class CDimension : public CRegisterableItemWithPrecision
{
public:
	/// <summary>Constructor.</summary>
	/// <param name="unit">Dimensional units to use.</param>
	/// <param name="value">Length unit value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	CDimension(const DIM_UNIT unit = UNDEFINED_DIM_UNIT, const double value = 0.0, char* section = NULL, char* entry = NULL);
	/// <summary>Destructor.</summary>
	~CDimension() {}

	/// <summary>Initialize a CDimension object.</summary>
	/// <param name="unit">Dimensional units to use.</param>
	/// <param name="value">Length unit value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	void						Init(const DIM_UNIT unit, const double value, char* section, char* entry);
	/// <summary>Set dimension unit and value.</summary>
	/// <param name="unit">Dimension unit to use.</param>
	/// <param name="value">Length value to represent.</param>
	void						Set(DIM_UNIT unit, double value);
	/// <summary>Set variable value from string contents.  String must contain value text followed by 
	/// units text example: 123.456 in.</summary>
	/// <param name="str">String to use.</param>
	void						SetS(const char* str);
	/// <summary>Get variable value in specified units.</summary>
	/// <param name="unit">Units to retrieve value in.</param>
	/// <returns>Value, in specified units.</returns>
	double						Get(DIM_UNIT unit);
	/// <summary>Get variable value as string in specified units. String will contain value text 
	/// followed by units text.</summary>
	/// <param name="unit">Units to retrieve value in.</param>
	/// <param name="str">String to hold reply value.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	/// <returns>Pointer to output string.</returns>
	char*						GetS(DIM_UNIT unit, char* str, int precision);
	/// <summary>Get variable value as string in current units. String will contain value text 
	/// followed by units text.</summary>
	/// <param name="str">String to hold reply value.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	/// <returns>Pointer to output string.</returns>
	char*						GetS(char* str, int precision);
	
	/// <summary>Erase this item from an INI file. Note that the entire INI section is deleted.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Erase(const char* ini_file);
	/// <summary>Save this item to an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	void						Save(const char* ini_file, int precision);
	/// <summary>Restore this item from an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Restore(const char* ini_file);

private:
	double						m_set_value;					///< initial set value
	DIM_UNIT					m_set_unit;						///< units for initial set value
	double						m_internal_value;				///< internal representation of value
	double						m_get_value;					///< last retrieved value
	DIM_UNIT					m_get_unit;						///< last retrieved units
	char*						m_section;						///< INI file section name string
	char*						m_entry;						///< INI file entry name string
};

/// <summary>
/// The CPeriod objects have a real value in internal time units.
/// </summary>
/// <remarks>
/// <para>The internal value is set by member functions taking a value and a period
/// units specifier (see PER_UNIT typedef). The value of the object can be retrieved by
/// member functions that allow the caller to specify the desired period units.
/// example:
///
///   CPeriod SomeTime(SECOND, 1.0);
///   double value = SomeTime.Get(MILLSECOND);
///
/// With this code, dValue would contain 1000.0 after execution (the number of milliseconds
/// in one second).</para>
/// </remarks>
class CPeriod : public CRegisterableItemWithPrecision
{
public:
	/// <summary>Constructor.</summary>
	/// <param name="unit">Time period units to use.</param>
	/// <param name="value">Period unit value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	CPeriod(const PER_UNIT unit = UNDEFINED_PER_UNIT, const double value = 0.0, char* section = NULL, char* entry = NULL);
	/// <summary>Destructor.</summary>
	~CPeriod() {}

	/// <summary>Initialize a CPeriod object.</summary>
	/// <param name="unit">Time period units to use.</param>
	/// <param name="value">Period unit value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	void Init(const PER_UNIT InitUnit, const double dInitValue, char* section, char* entry);
	/// <summary>Set time period unit and value.</summary>
	/// <param name="unit">Time period unit to use.</param>
	/// <param name="value">Time period value to represent.</param>
	void						Set(PER_UNIT unit, double value);
	/// <summary>Set variable value from string contents.  String must contain value text followed by 
	/// units text example: 12.1 sec.</summary>
	/// <param name="str">String to use.</param>
	void						SetS(const char* str);
	/// <summary>Get variable value in specified units.</summary>
	/// <param name="unit">Units to retrieve value in.</param>
	/// <returns>Value, in specified units.</returns>
	double						Get(PER_UNIT unit);
	/// <summary>Get variable value as string in specified units. String will contain value text 
	/// followed by units text.</summary>
	/// <param name="unit">Units to retrieve value in.</param>
	/// <param name="str">String to hold reply value.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	/// <returns>Pointer to output string.</returns>
	char*						GetS(PER_UNIT unit, char* str, int precision);
	/// <summary>Get variable value as string in current units. String will contain value text 
	/// followed by units text.</summary>
	/// <param name="str">String to hold reply value.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	/// <returns>Pointer to output string.</returns>
	char*						GetS(char* str, int precision);
	
	/// <summary>Erase this item from an INI file. Note that the entire INI section is deleted.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Erase(const char* ini_file);
	/// <summary>Save this item to an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	void						Save(const char* ini_file, int precision);
	/// <summary>Restore this item from an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Restore(const char* ini_file);

private:
	double						m_set_value;					///< initial set value
	PER_UNIT					m_set_unit;						///< units for initial set value
	double						m_internal_value;				///< internal representation of value
	double						m_get_value;					///< last retrieved value
	PER_UNIT					m_get_unit;						///< last retrieved units
	char*						m_section;						///< INI file section name string
	char*						m_entry;						///< INI file entry name string
};

/// <summary>
/// CScale objects store a value in units of 'encoder counts per dimension unit'.
/// </summary>
/// <remarks>
/// <para>The value is set by member functions taking a value and a dimension units
/// specifier (see DIM_UNIT typedef). The value of the object can be retrieved by
/// member functions that allow the caller to specify the desired dimension units.</para>
/// </remarks>
class CScale : public CRegisterableItemWithPrecision
{
public:
	/// <summary>Constructor.</summary>
	/// <param name="unit">Dimension units to use.</param>
	/// <param name="value">Scale value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	CScale(const DIM_UNIT unit = UNDEFINED_DIM_UNIT, const double value = 0.0, char* section = NULL, char* entry = NULL);
	/// <summary>Destructor.</summary>
	~CScale() {}

	/// <summary>Initialize a CScale object.</summary>
	/// <param name="unit">Dimension units to use.</param>
	/// <param name="value">Scale value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	void						Init(const DIM_UNIT unit, const double value, char* section, char* entry);
	/// <summary>Set dimension unit and value.</summary>
	/// <param name="unit">Dimension unit to use.</param>
	/// <param name="value">Length value to represent.</param>
	void						Set(DIM_UNIT unit, double value);
	/// <summary>Set variable value from string contents.  String must contain value text followed by 
	/// units text example: 123.456 counts/in.</summary>
	/// <param name="str">String to use.</param>
	void						SetS(const char* str);
	/// <summary>Get variable value in specified units.</summary>
	/// <param name="unit">Units to retrieve value in.</param>
	/// <returns>Value, in specified units.</returns>
	double						Get(DIM_UNIT unit);
	/// <summary>Get variable value as string in specified units. String will contain value text 
	/// followed by units text.</summary>
	/// <param name="unit">Units to retrieve value in.</param>
	/// <param name="str">String to hold reply value.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	/// <returns>Pointer to output string.</returns>
	char*						GetS(DIM_UNIT unit, char* str, int precision);
	/// <summary>Get variable value as string in current units. String will contain value text 
	/// followed by units text.</summary>
	/// <param name="str">String to hold reply value.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	/// <returns>Pointer to output string.</returns>
	char*						GetS(char* str, int precision);
	
	/// <summary>Erase this item from an INI file. Note that the entire INI section is deleted.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Erase(const char* ini_file);
	/// <summary>Save this item to an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	void						Save(const char* ini_file, int precision);
	/// <summary>Restore this item from an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Restore(const char* ini_file);

private:
	double						m_set_value;					///< initial set value
	DIM_UNIT					m_set_unit;						///< units for initial set value	
	double						m_internal_value;				///< internal representation of value	
	double						m_get_value;					///< last retrieved value
	DIM_UNIT					m_get_unit;						///< last retrieved units
	char*						m_section;						///< INI file section name string
	char*						m_entry;						///< INI file entry name string
};

/// <summary>
/// CSpeed objects store a value in units of 'dimension unit / period unit'.
/// </summary>
/// <remarks>
/// <para>The value is set by member functions taking a value, a dimension units specifier
///  and a period unit specifier. The value of the object can be retrieved by member
///  functions that allow the caller to specify the desired dimension and period units.</para>
/// </remarks>
class CSpeed : public CRegisterableItemWithPrecision
{
public:
	/// <summary>Constructor.</summary>
	/// <param name="dim_unit">Dimension units to use.</param>
	/// <param name="per_unit">Time period units to use.</param>
	/// <param name="value">Speed value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	CSpeed(const DIM_UNIT dim_unit = UNDEFINED_DIM_UNIT, const PER_UNIT per_unit = UNDEFINED_PER_UNIT,
		   const double value = 0.0, char* section = NULL, char* entry = NULL);
	/// <summary>Destructor.</summary>
	~CSpeed() {}

	/// <summary>Initialize a CSpeed object.</summary>
	/// <param name="dim_unit">Dimension units to use.</param>
	/// <param name="per_unit">Time period units to use.</param>
	/// <param name="value">Speed value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	void Init(const DIM_UNIT dim_unit, const PER_UNIT per_unit, const double value, char* section, char* entry);
	/// <summary>Set dimension unit, time period unit, and value.</summary>
	/// <param name="dim_unit">Dimension units to use.</param>
	/// <param name="per_unit">Time period units to use.</param>
	/// <param name="value">Speed value to represent.</param>
	void						Set(DIM_UNIT dim_unit, PER_UNIT per_unit, double value);
	/// <summary>Set variable value from string contents. String must contain value text followed by 
	/// units text example: 123.456 in/sec.</summary>
	/// <param name="str">String to use.</param>
	void						SetS(const char* str);
	/// <summary>Get variable value in specified units.</summary>
	/// <param name="dim_unit">Dimension units to use.</param>
	/// <param name="per_unit">Time period units to use.</param>
	/// <returns>Value, in specified units.</returns>
	double						Get(DIM_UNIT dim_unit, PER_UNIT per_unit);
	/// <summary>Get variable value as string in specified units. String will contain value text 
	/// followed by units text.</summary>
	/// <param name="dim_unit">Dimension units to use.</param>
	/// <param name="per_unit">Time period units to use.</param>
	/// <param name="str">String to hold reply value.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	/// <returns>Pointer to output string.</returns>
	char*						GetS(DIM_UNIT dim_unit, PER_UNIT per_unit, char* str, int precision);
	/// <summary>Get variable value as string in current units. String will contain value text 
	/// followed by units text.</summary>
	/// <param name="str">String to hold reply value.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	/// <returns>Pointer to output string.</returns>
	char*						GetS(char* str, int precision);
	
	/// <summary>Erase this item from an INI file. Note that the entire INI section is deleted.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Erase(const char* ini_file);
	/// <summary>Save this item to an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	void						Save(const char* ini_file, int precision);
	/// <summary>Restore this item from an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Restore(const char* ini_file);

private:
	double						m_set_value;					///< initial set value
	DIM_UNIT					m_set_dim_unit;					///< dimension units for initial set value	
	PER_UNIT					m_set_per_unit;					///< time period units for initial set value	
	double						m_internal_value;				///< internal representation of value
	double						m_get_value;					///< last retrieved value
	DIM_UNIT					m_get_dim_unit;					///< last retrieved dimension units
	PER_UNIT					m_get_per_unit;					///< last retrieved time period units
	char*						m_section;						///< INI file section name string
	char*						m_entry;						///< INI file entry name string
};

/// <summary>
/// CAcceleration objects store a value in units of 'dimension unit / period / period unit'.
/// </summary>
/// <remarks>
/// <para>The value is set by member functions taking a value, a dimension units specifier 
/// and a period unit specifier. The value of the object can be retrieved by member functions 
/// that allow the caller to specify the desired dimension and period units.</para>
/// </remarks>
class CAcceleration : public CRegisterableItemWithPrecision
{
public:
	/// <summary>Constructor.</summary>
	/// <param name="dim_unit">Dimension units to use.</param>
	/// <param name="per_unit">Time period units to use.</param>
	/// <param name="value">Acceleration value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	CAcceleration(const DIM_UNIT dim_unit = UNDEFINED_DIM_UNIT, const PER_UNIT per_unit = UNDEFINED_PER_UNIT,
				  const double value = 0.0, char* section = NULL, char* entry = NULL);
	/// <summary>Destructor.</summary>
	~CAcceleration() {}

	/// <summary>Initialize a CAcceleration object.</summary>
	/// <param name="dim_unit">Dimension units to use.</param>
	/// <param name="per_unit">Time period units to use.</param>
	/// <param name="value">Acceleration value to represent.</param>
	/// <param name="section">INI file section name string.</param>
	/// <param name="entry">INI file entry name string.</param>
	void						Init(const DIM_UNIT dim_unit, const PER_UNIT per_unit, const double value, char* section, char* entry);
	/// <summary>Set dimension unit, time period unit, and value.</summary>
	/// <param name="dim_unit">Dimension units to use.</param>
	/// <param name="per_unit">Time period units to use.</param>
	/// <param name="value">Acceleration value to represent.</param>
	void						Set(DIM_UNIT dim_unit, PER_UNIT per_unit, double value);
	/// <summary>Set variable value from string contents. String must contain value text followed by 
	/// units text example: 123.456 in/sec/sec.</summary>
	/// <param name="str">String to use.</param>
	void						SetS(const char* str);
	/// <summary>Get variable value in specified units.</summary>
	/// <param name="dim_unit">Dimension units to use.</param>
	/// <param name="per_unit">Time period units to use.</param>
	/// <returns>Value, in specified units.</returns>
	double						Get(DIM_UNIT dim_unit, PER_UNIT per_unit);
	/// <summary>Get variable value as string in specified units. String will contain value text 
	/// followed by units text.</summary>
	/// <param name="dim_unit">Dimension units to use.</param>
	/// <param name="per_unit">Time period units to use.</param>
	/// <param name="str">String to hold reply value.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	/// <returns>Pointer to output string.</returns>
	char*						GetS(DIM_UNIT dim_unit, PER_UNIT per_unit, char* str, int precision);
	/// <summary>Get variable value as string in current units. String will contain value text 
	/// followed by units text.</summary>
	/// <param name="str">String to hold reply value.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	/// <returns>Pointer to output string.</returns>
	char*						GetS(char* str, int precision);
	
	/// <summary>Erase this item from an INI file. Note that the entire INI section is deleted.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Erase(const char* ini_file);
	/// <summary>Save this item to an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	/// <param name="precision">Precision value to use with sprintf.</param>
	void						Save(const char* ini_file, int precision);
	/// <summary>Restore this item from an INI file.</summary>
	/// <param name="ini_file">INI file name and path.</param>
	void						Restore(const char* ini_file);

private:
	double						m_set_value;					///< initial set value
	DIM_UNIT					m_set_dim_unit;					///< dimension units for initial set value	
	PER_UNIT					m_set_per_unit;					///< time period units for initial set value
	double						m_internal_value;				///< internal representation of value
	double						m_get_value;					///< last retrieved value
	DIM_UNIT					m_get_dim_unit;					///< last retrieved dimension units
	PER_UNIT					m_get_per_unit;					///< last retrieved time period units
	char*						m_section;						///< INI file section name string
	char*						m_entry;						///< INI file entry name string
};

#endif			// APP_CLASSES_H
