/*
 * Returns a string representation of the given Unit. THis function is
 * only for debugging purposes.
 * @param const Unit& unit
 * @return std::string unitRepresentation
 */
LIBSBML_EXTERN
std::string UnitConversionFactory::toString(const Unit& unit)
{
    double multiplier = unit.getMultiplier();
    double offset = unit.getOffset();
    int scale = unit.getScale();
    int exponent = unit.getExponent();
    UnitKind_t kind = unit.getKind();
    std::stringstream ss;
    ss << multiplier << " * (" << UnitKind_toString(kind) << " * 10^" << scale << " + " << offset << ")^" << exponent;
    return ss.str();
}
std::string Expression2PresentationMMLUnits::getMathML(const Unit * u, bool absExp) const
{
  if (!u)
    return "<mi>EEE</mi>";

  int exponent = absExp ? abs(u->getExponent()) : u->getExponent();
  bool flagExp = (exponent != 1);
  bool flag = (u->getMultiplier() != 1.0) || (u->getScale() != 0); //are brackets needed?

  std::ostringstream tmp;

  if (flagExp) tmp << "<msup>";

  //if (flag) tmp << "<mfenced>";
  tmp << "<mrow>";

  if (flag) tmp << "<mo>(</mo>";

  if (u->getMultiplier() != 1.0)
    tmp << "<mn>" <<  u->getMultiplier() << "</mn><mo>&CenterDot;</mo>";

  if (u->getScale() != 0)
    tmp << "<msup><mn>10</mn><mn>" << u->getScale() << "</mn></msup><mo>&CenterDot;</mo>";

  tmp << "<mi>";
  tmp << UnitKind_toString(u->getKind());
  tmp << "</mi>";

  if (flag) tmp << "<mo>)</mo>";

  tmp << "</mrow>";
  //if (flag) tmp << "</mfenced>";

  if (flagExp) tmp << "<mn>" << exponent << "</mn>";

  if (flagExp) tmp << "</msup>";

  //tmp << "</mrow>";

  return tmp.str();
}
END_TEST


START_TEST (test_UnitKind_toString)
{
  const char* s;


  s = UnitKind_toString(UNIT_KIND_AMPERE);
  fail_unless(!strcmp(s, "ampere"), NULL);

  s = UnitKind_toString(UNIT_KIND_BECQUEREL);
  fail_unless(!strcmp(s, "becquerel"), NULL);

  s = UnitKind_toString(UNIT_KIND_CANDELA);
  fail_unless(!strcmp(s, "candela"), NULL);

  s = UnitKind_toString(UNIT_KIND_CELSIUS);
  fail_unless(!strcmp(s, "Celsius"), NULL);

  s = UnitKind_toString(UNIT_KIND_COULOMB);
  fail_unless(!strcmp(s, "coulomb"), NULL);

  s = UnitKind_toString(UNIT_KIND_DIMENSIONLESS);
  fail_unless(!strcmp(s, "dimensionless"), NULL);

  s = UnitKind_toString(UNIT_KIND_FARAD);
  fail_unless(!strcmp(s, "farad"), NULL);

  s = UnitKind_toString(UNIT_KIND_GRAM);
  fail_unless(!strcmp(s, "gram"), NULL);

  s = UnitKind_toString(UNIT_KIND_GRAY);
  fail_unless(!strcmp(s, "gray"), NULL);

  s = UnitKind_toString(UNIT_KIND_HENRY);
  fail_unless(!strcmp(s, "henry"), NULL);

  s = UnitKind_toString(UNIT_KIND_HERTZ);
  fail_unless(!strcmp(s, "hertz"), NULL);

  s = UnitKind_toString(UNIT_KIND_ITEM);
  fail_unless(!strcmp(s, "item"), NULL);

  s = UnitKind_toString(UNIT_KIND_JOULE);
  fail_unless(!strcmp(s, "joule"), NULL);

  s = UnitKind_toString(UNIT_KIND_KATAL);
  fail_unless(!strcmp(s, "katal"), NULL);

  s = UnitKind_toString(UNIT_KIND_KELVIN);
  fail_unless(!strcmp(s, "kelvin"), NULL);

  s = UnitKind_toString(UNIT_KIND_KILOGRAM);
  fail_unless(!strcmp(s, "kilogram"), NULL);

  s = UnitKind_toString(UNIT_KIND_LITER);
  fail_unless(!strcmp(s, "liter"), NULL);

  s = UnitKind_toString(UNIT_KIND_LITRE);
  fail_unless(!strcmp(s, "litre"), NULL);

  s = UnitKind_toString(UNIT_KIND_LUMEN);
  fail_unless(!strcmp(s, "lumen"), NULL);

  s = UnitKind_toString(UNIT_KIND_LUX);
  fail_unless(!strcmp(s, "lux"), NULL);

  s = UnitKind_toString(UNIT_KIND_METER);
  fail_unless(!strcmp(s, "meter"), NULL);

  s = UnitKind_toString(UNIT_KIND_METRE);
  fail_unless(!strcmp(s, "metre"), NULL);

  s = UnitKind_toString(UNIT_KIND_MOLE);
  fail_unless(!strcmp(s, "mole"), NULL);

  s = UnitKind_toString(UNIT_KIND_NEWTON);
  fail_unless(!strcmp(s, "newton"), NULL);

  s = UnitKind_toString(UNIT_KIND_OHM);
  fail_unless(!strcmp(s, "ohm"), NULL);

  s = UnitKind_toString(UNIT_KIND_PASCAL);
  fail_unless(!strcmp(s, "pascal"), NULL);

  s = UnitKind_toString(UNIT_KIND_RADIAN);
  fail_unless(!strcmp(s, "radian"), NULL);

  s = UnitKind_toString(UNIT_KIND_SECOND);
  fail_unless(!strcmp(s, "second"), NULL);

  s = UnitKind_toString(UNIT_KIND_SIEMENS);
  fail_unless(!strcmp(s, "siemens"), NULL);

  s = UnitKind_toString(UNIT_KIND_SIEVERT);
  fail_unless(!strcmp(s, "sievert"), NULL);

  s = UnitKind_toString(UNIT_KIND_STERADIAN);
  fail_unless(!strcmp(s, "steradian"), NULL);

  s = UnitKind_toString(UNIT_KIND_TESLA);
  fail_unless(!strcmp(s, "tesla"), NULL);

  s = UnitKind_toString(UNIT_KIND_VOLT);
  fail_unless(!strcmp(s, "volt"), NULL);

  s = UnitKind_toString(UNIT_KIND_WATT);
  fail_unless(!strcmp(s, "watt"), NULL);

  s = UnitKind_toString(UNIT_KIND_WEBER);
  fail_unless(!strcmp(s, "weber"), NULL);


  s = UnitKind_toString(UNIT_KIND_INVALID);
  fail_unless(!strcmp(s, "(Invalid UnitKind)"), NULL );

  s = UnitKind_toString((UnitKind_t)-1);
  fail_unless(!strcmp(s, "(Invalid UnitKind)"), NULL );

  s = UnitKind_toString((UnitKind_t)(UNIT_KIND_INVALID + 1));
  fail_unless(!strcmp(s, "(Invalid UnitKind)"), NULL );
}
/*
 * Converts a Unit into the corresponding UnitDefinition that consists
 * only of SI units.
 * Possible offsets are ignored.
 * Freeing the memory for the returned UnitDefinition is up to the
 * receiver.
 * On failure a NULL pointer is returned.
 * @param const Unit& unit
 * @return UnitDefinition* result
 */
LIBSBML_EXTERN
UnitDefinition* UnitConversionFactory::convertToSI(const Unit& unit)
{
    UnitDefinition* pUdef = NULL;
    Unit* pU = NULL;

    if (!unit.isSetKind()) return pUdef;

    UnitKind_t uKind = unit.getKind();

    switch (uKind)
    {
    case UNIT_KIND_AMPERE:
        pUdef = convertAmpereToSI(unit);
        break;

    case UNIT_KIND_BECQUEREL:
    case UNIT_KIND_HERTZ:
        pUdef = convertFrequencyToSI(unit);
        break;

    case UNIT_KIND_CANDELA:
        pUdef = convertCandelaToSI(unit);
        break;

    case UNIT_KIND_CELSIUS:
        pUdef = convertCelsiusToSI(unit);
        break;

    case UNIT_KIND_COULOMB:
        pUdef = convertCoulombToSI(unit);
        break;

    case UNIT_KIND_DIMENSIONLESS:
    case UNIT_KIND_ITEM:
    case UNIT_KIND_RADIAN:
    case UNIT_KIND_STERADIAN:
        pUdef = convertDimensionlessToSI(unit);
        break;

    case UNIT_KIND_FARAD:
        pUdef = convertFaradToSI(unit);
        break;

    case UNIT_KIND_GRAM:
        pU = new Unit(unit);
        pU->setScale(pU->getScale() - 3);
        pU->setKind(UNIT_KIND_KILOGRAM);
        pUdef = convertKilogramToSI(*pU);
        delete pU;
        break;

    case UNIT_KIND_GRAY:
    case UNIT_KIND_SIEVERT:
        pUdef = convertDoseToSI(unit);
        break;

    case UNIT_KIND_HENRY:
        pUdef = convertHenryToSI(unit);
        break;

    case UNIT_KIND_JOULE:
        pUdef = convertJouleToSI(unit);
        break;

    case UNIT_KIND_KATAL:
        pUdef = convertKatalToSI(unit);
        break;

    case UNIT_KIND_KELVIN:
        pUdef = convertKelvinToSI(unit);
        break;

    case UNIT_KIND_KILOGRAM:
        pUdef = convertKilogramToSI(unit);
        break;

    case UNIT_KIND_LITER:
    case UNIT_KIND_LITRE:
        pU = new Unit(unit);
        pU->setKind(UNIT_KIND_METER);
        pU->setExponent(pU->getExponent()*3);
        pU->setScale(pU->getScale() - 3);
        pUdef = convertMeterToSI(*pU);
        delete pU;
        break;

    case UNIT_KIND_LUMEN:
        pUdef = convertLumenToSI(unit);
        break;

    case UNIT_KIND_LUX:
        pUdef = convertLuxToSI(unit);
        break;

    case UNIT_KIND_METER:
    case UNIT_KIND_METRE:
        pUdef = convertMeterToSI(unit);
        break;

    case UNIT_KIND_MOLE:
#if LIBSBML_VERSION >= 40100
    // this may be not totally correct, but this is the way we currently intend to
    // handle it in COPASI
    case UNIT_KIND_AVOGADRO:
#endif // LIBSBML_VERSION
        pUdef = convertMoleToSI(unit);
        break;

    case UNIT_KIND_NEWTON:
        pUdef = convertNewtonToSI(unit);
        break;

    case UNIT_KIND_OHM:
        pUdef = convertOhmToSI(unit);
        break;

    case UNIT_KIND_PASCAL:
        pUdef = convertPascalToSI(unit);
        break;

    case UNIT_KIND_SECOND:
        pUdef = convertSecondToSI(unit);
        break;

    case UNIT_KIND_SIEMENS:
        pUdef = convertSiemensToSI(unit);
        break;

    case UNIT_KIND_TESLA:
        pUdef = convertTeslaToSI(unit);
        break;

    case UNIT_KIND_VOLT:
        pUdef = convertVoltToSI(unit);
        break;

    case UNIT_KIND_WATT:
        pUdef = convertWattToSI(unit);
        break;

    case UNIT_KIND_WEBER:
        pUdef = convertWeberToSI(unit);
        break;

    case UNIT_KIND_INVALID:
        delete pUdef;
        pUdef = NULL;
        break;
    }

    if (pUdef != NULL)
    {
        unsigned int num = 1;
        std::stringstream ss;
        ss << "UnitDefinition_" << num;

        while (!UnitConversionFactory::isIdUnused(ss.str()))
        {
            ++num;
            ss.str("");
            ss << "UnitDefinition_" << num;
        }

        std::string id = ss.str();
        usedIds.push_back(id);
        pUdef->setId(id);
        UnitKind_t uKind = unit.getKind();
        pUdef->setName(UnitKind_toString(uKind));
    }

    return pUdef;
}