/* -*- indent-tabs-mode: nil; -*-
 *
 * This file is part of the Mango recipe management distribution.
 * Copyright (c) 2000-2003, Roland Jesse
 * All rights reserved.
 *
 * For license and copyright information see the file COPYRIGHT or 
 * <http://www.opensource.org/licenses/bsd-license.html>.
 *
 * $Id: Measurement.cpp,v 1.3 2003/01/12 16:19:56 rjesse Exp $
 */

#include "Measurement.h"
#include <qstringlist.h>

//! \internal
struct MeasurementData {
      long refCount;
      QString mmAbbrev;         //!< Meal-Master name for this measurement
      /*!
        Maps from the MM abbrev onto the RK abbrev. Does not use tr()!
      */
      QMap<QString, QString> rkAbbrevs;
      /*!
        Maps from the MM abbrev onto its according full text description.
      */
      QMap<QString, QString> descriptions;
};

/*!
  Constructor.
*/
Measurement::Measurement()
{
   d = new MeasurementData();
   d->refCount = 1;
   initRezkonvAbbrevs();
   initDescriptions();
}

/*!
  Constructs a Measurement object with \a mm as Meal-Master abbreviation.
*/
Measurement::Measurement( const QString& mm)
{
   d = new MeasurementData();
   d->refCount = 1;
   d->mmAbbrev = mm;
   initRezkonvAbbrevs();
   initDescriptions();
}

/*!
  Copy constructor.
*/
Measurement::Measurement( const Measurement& other)
{
   d = other.d;
   d->refCount++;
}

Measurement::~Measurement()
{
   if (--d->refCount == 0)
      delete d;
}

Measurement&
Measurement::operator=( const Measurement& right)
{
   right.d->refCount++;
   if (--d->refCount == 0)
      delete d;
   d = right.d;
   return *this;
}

void
Measurement::detach()
{
   if (d->refCount > 1) {
      d->refCount--;
      d = new MeasurementData();
      d->refCount = 1;
      d->mmAbbrev = mmAbbrev();
   }
} // detach()

void
Measurement::setName( const QString& s)
{
   detach();
   d->mmAbbrev = s;
}

QString
Measurement::mmAbbrev() const
{
   return d->mmAbbrev;
}

QString
Measurement::rkAbbrev() const
{
   return d->rkAbbrevs[mmAbbrev()];
}

QString
Measurement::description() const
{
   return d->descriptions[mmAbbrev()];
}

/*!
  Returns the number of times \a s appears in the measurement's description.
*/
int
Measurement::contains( const QString& s, bool cs) const
{
   return( d->descriptions[mmAbbrev()].contains( s, cs));
} // contains()

bool
Measurement::isScaleable() const
{
   bool rc = (mmAbbrev() == "x") ? false : true;
   return rc;
}

/*!
  Maps each Meal-Master measurement name onto its Rezkonv counterpart.

  Not handled (i.e. mapped onto empty strings):
  - "cl" and "dl". These are converted to "ml" by MMImporter.
  - "cg" and "dg". These are converted to "mg" by MMImporter.
  - "fl, "ga", "qt", and "pt".
  - "oz", "lb".
  
  This function does *not* use tr() as the names are determined by the
  file formats and not subject to i18n.
*/
void
Measurement::initRezkonvAbbrevs()
{
   detach();
   d->rkAbbrevs.insert( "x", " x");
   d->rkAbbrevs.insert( "c", "Tasse/n ");
   d->rkAbbrevs.insert( "sm", "klein."); // "Etwas " (?!)
   d->rkAbbrevs.insert( "md", "mittl.");
   d->rkAbbrevs.insert( "lg", "groß.");
   d->rkAbbrevs.insert( "pt", "");
   d->rkAbbrevs.insert( "qt", "");
   d->rkAbbrevs.insert( "ga", "");
   d->rkAbbrevs.insert( "cn", "Dose/n ");
   d->rkAbbrevs.insert( "oz", "");
   d->rkAbbrevs.insert( "pk", "Pack.");
   d->rkAbbrevs.insert( "lb", "");
   d->rkAbbrevs.insert( "pn", "Prise/n ");
   d->rkAbbrevs.insert( "ml", "ml ");
   d->rkAbbrevs.insert( "cl", "");
   d->rkAbbrevs.insert( "dl", "");
   d->rkAbbrevs.insert( "l", "Liter ");

   d->rkAbbrevs.insert( "mg", "mg ");
   d->rkAbbrevs.insert( "cg", "");
   d->rkAbbrevs.insert( "dg", "");
   d->rkAbbrevs.insert( "g", "Gramm ");
   d->rkAbbrevs.insert( "kg", "Kilo ");

   d->rkAbbrevs.insert( "dr", "Tropfen ");
   d->rkAbbrevs.insert( "cb", "ml ");
   d->rkAbbrevs.insert( "ds", "Schuss ");
   d->rkAbbrevs.insert( "ct", "Karton ");
   d->rkAbbrevs.insert( "bn", "Bund ");
   d->rkAbbrevs.insert( "sl", "Scheib.");
   d->rkAbbrevs.insert( "ea", "");

   d->rkAbbrevs.insert( "t", "Teel.");
   d->rkAbbrevs.insert( "ts", "Teel.");
   d->rkAbbrevs.insert( "T", "Essl.");
   d->rkAbbrevs.insert( "tb", "Essl.");
   d->rkAbbrevs.insert( "fl", "");
} // initRezkonvAbbrevs()

void
Measurement::initDescriptions()
{
   detach();
   d->descriptions.insert( "x", QString( QObject::tr( "per serving")));
   d->descriptions.insert( "c", QString( QObject::tr( "cup")));
   d->descriptions.insert( "sm", QString( QObject::tr( "small")));
   d->descriptions.insert( "md", QString( QObject::tr( "medium")));
   d->descriptions.insert( "lg", QString( QObject::tr( "large")));
   d->descriptions.insert( "pt", QString( QObject::tr( "pint")));
   d->descriptions.insert( "qt", QString( QObject::tr( "quart")));
   d->descriptions.insert( "ga", QString( QObject::tr( "gallon")));
   d->descriptions.insert( "cn", QString( QObject::tr( "can")));
   d->descriptions.insert( "oz", QString( QObject::tr( "ounce")));
   d->descriptions.insert( "pk", QString( QObject::tr( "package")));
   d->descriptions.insert( "lb", QString( QObject::tr( "pound")));
   d->descriptions.insert( "pn", QString( QObject::tr( "pinch")));
   d->descriptions.insert( "ml", QString( QObject::tr( "milliliter")));
   d->descriptions.insert( "cl", QString( QObject::tr( "centiliter")));
   d->descriptions.insert( "dl", QString( QObject::tr( "deciliter")));
   d->descriptions.insert( "l", QString( QObject::tr( "liter")));

   d->descriptions.insert( "mg", QString( QObject::tr( "milligram")));
   d->descriptions.insert( "cg", QString( QObject::tr( "centigram")));
   d->descriptions.insert( "dg", QString( QObject::tr( "decigram")));
   d->descriptions.insert( "g", QString( QObject::tr( "gram")));
   d->descriptions.insert( "kg", QString( QObject::tr( "kilogram")));

   d->descriptions.insert( "dr", QString( QObject::tr( "drop")));
   d->descriptions.insert( "cb", QString( QObject::tr( "cubic")));
   d->descriptions.insert( "ds", QString( QObject::tr( "dash")));
   d->descriptions.insert( "ct", QString( QObject::tr( "carton")));
   d->descriptions.insert( "bn", QString( QObject::tr( "bunch")));
   d->descriptions.insert( "sl", QString( QObject::tr( "slice")));
   d->descriptions.insert( "ea", QString( QObject::tr( "each")));

   d->descriptions.insert( "t", QString( QObject::tr( "teaspoon")));
   d->descriptions.insert( "ts", QString( QObject::tr( "teaspoon")));
   d->descriptions.insert( "T", QString( QObject::tr( "tablespoon")));
   d->descriptions.insert( "tb", QString( QObject::tr( "tablespoon")));
   d->descriptions.insert( "fl", QString( QObject::tr( "fluid ounce")));
} // initDescriptions()

/*!
  Return a list of all Meal-Master measurements in order to
  populate combo boxes or what not.
*/
QStringList
Measurement::mmAbbrevs()
{
   QStringList ret;
   Measurement tmp;
   QMap<QString, QString> descr = tmp.d->descriptions;
   QMap<QString, QString>::const_iterator it = descr.begin();
   for (; it != descr.end(); it++)
      ret.append( it.key());
   return ret;
}

/*****************************************************************************
  Related functions for the Measurement classn
 *****************************************************************************/

bool
operator==( const Measurement& m1, const Measurement& m2)
{
   return( m1.mmAbbrev() == m2.mmAbbrev());
}

bool
operator!=( const Measurement& m1, const Measurement& m2)
{
   return !(m1==m2);
}
