/** \file
 *
 *  Contains the Unit class declaration.
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef UNIT_H_
#define UNIT_H_

#include "data/BinaryDataType.h"
#include "data/BlobType.h"

class DataValue;

class BaseUnit;

/**
 *  Code that represents an engineering unit. Allows engineering units to be
 *  converted to/from the SI units used internally
 *
 *  \ingroup units
 */
class Unit
{

public:

    /// General unit constructor
    Unit( const char* name, const char* abbreviation, const BaseUnit& baseUnit,
          const double toSiMultiplier = 1.0, const double toSiAddend = 0.0 );

    /// Base unit constructor
    Unit( const char* name, const char* abbreviation,
          const BinaryDataType defaultDataType = NO_TYPE );

    virtual ~Unit();

    const double getScaled( const double& siValue ) const;
    const float getScaled( const float& siValue ) const;
    const int getScaled( const int siValue ) const;
    const double getSI( const double& scaledValue ) const;
    const float getSI( const float& scaledValue ) const;
    const int getSI( const int scaledValue ) const;

    void toScaled( double& siValue ) const;
    void toScaled( float& siValue ) const;
    void toScaled( int& siValue ) const;
    void toSI( double& scaledValue ) const;
    void toSI( float& scaledValue ) const;
    void toSI( int& scaledValue ) const;

    DataValue* dataValue( const BinaryDataType dataType = NO_TYPE,
                          const BlobType blobType = NOT_BLOB ) const;

    DataValue* dataValue( const bool& assignFrom,
                          const BinaryDataType dataType = NO_TYPE ) const;

    DataValue* dataValue( const unsigned char& assignFrom,
                          const BinaryDataType dataType = NO_TYPE ) const;

    DataValue* dataValue( const int& assignFrom,
                          const BinaryDataType dataType = NO_TYPE ) const;

    DataValue* dataValue( const float& assignFrom,
                          const BinaryDataType dataType = NO_TYPE ) const;

    DataValue* dataValue( const double& assignFrom,
                          const BinaryDataType dataType = NO_TYPE ) const;

    bool operator== ( const Unit& unit ) const;
    bool operator!= ( const Unit& unit ) const;

    DataValue* operator()( const BinaryDataType dataType = NO_TYPE,
                           const BlobType blobType = NOT_BLOB ) const
    {
        return dataValue( dataType, blobType );
    }

    DataValue* operator()( const bool& assignFrom,
                           const BinaryDataType dataType = NO_TYPE ) const
    {
        return dataValue( assignFrom, dataType );
    }

    DataValue* operator()( const unsigned char& assignFrom,
                           const BinaryDataType dataType = NO_TYPE ) const
    {
        return dataValue( assignFrom, dataType );
    }

    DataValue* operator()( const int& assignFrom,
                           const BinaryDataType dataType = NO_TYPE ) const
    {
        return dataValue( assignFrom, dataType );
    }

    DataValue* operator()( const float& assignFrom,
                           const BinaryDataType dataType = NO_TYPE ) const
    {
        return dataValue( assignFrom, dataType );
    }

    DataValue* operator()( const double& assignFrom,
                           const BinaryDataType dataType = NO_TYPE ) const
    {
        return dataValue( assignFrom, dataType );
    }

    const char* getAbbreviation( void ) const
    {
        return abbreviation_;
    }
    const char getAbbrev( void ) const
    {
        return abbrev_;
    }
    const char* getName( void ) const
    {
        return name_;
    }
    const Unit& getBaseUnit( void ) const
    {
        return baseUnit_;
    }
    const BinaryDataType getDefaultDataType() const
    {
        return defaultDataType_;
    }

protected:

    const char* name_;
    const char* abbreviation_;
    const Unit& baseUnit_;
    const BinaryDataType defaultDataType_;
    double toSiAddend_;
    double toSiMultiplier_;
    double fromSiAddend_;
    double fromSiMultiplier_;
    bool needSiAddend_;
    bool needSiMultiplier_;
    char abbrev_;

private:
    // Note that the copy constructor below is private and not given a body.
    // Any attempt to call it will return a compiler error.
    Unit( const Unit& old ); // disallow copy constructor

};

class BaseUnit : public Unit
{
public:
    /// Base unit constructor
    BaseUnit( const char* name, const char* abbreviation,
              const BinaryDataType defaultDataType = NO_TYPE )
        : Unit( name, abbreviation, defaultDataType ) {}

};

#endif /*UNITS_H_*/
