#include <string>
#include <stdexcept>
#include <sstream>
#include <ctype.h> // for tolower()
#include <stddef.h> // for size_t

namespace ct {

void CheckElement(int iElement)
{
   if (iElement < 0 || size_t(iElement) >= g_nMaxElement) {
//       IvNotify(NOTIFY_Error, IvFmt("Element '%1' not recognized. Returning mass 0.", iElement));
      std::stringstream str;
      str << "Element '" << iElement << " not recognized.";
      throw std::runtime_error(str.str());
   }
}

double GetAtomicMass(int iElement, FAtomicMassType Type)
{
   if (iElement == 0)
      return 0.; // dummy atom
   CheckElement(iElement);
//    assert(sizeof(g_ElementAverageMasses) == sizeof(g_ElementMostCommonIsotopeMasses));
   if (Type == ATMASS_MostCommonIsotope)
      return g_ElementMostCommonIsotopeMasses[size_t(iElement)];
   else if (Type == ATMASS_StandardAtomicWeight)
      return g_ElementAverageMasses[iElement];
   else if (Type == ATMASS_ChargeInsteadOfMass)
      return double(iElement);
   else
      throw std::runtime_error("element mass type not recognized.");
}

// case insensitive compare for simple ASCII strings. There is no standard C function
// for doing this (there are nonstandard functions in POSIX (strcasecmp) and
// win32 (stricmp), but neither one is portable)
int strcicmp(char const *a, char const *b)
{
    for (;; ++ a, ++ b) {
        int d = tolower(*a) - tolower(*b);
        if (d != 0 || !*a)
            return d;
    }
}

// conversion element name <-> atomic number
char const *ElementNameFromNumber(int iElement)
{
//    assert(( AtomicNumber >= 1 ) && ( AtomicNumber <= s_nElementNames ));
   CheckElement(iElement);
   return g_ElementNames[iElement];
}


int ElementNumberFromName(char const *pName)
{
   if (strcicmp(pName, "X") == 0)
      return 0;
   // deuterium and tritium... we can't deal with those in a
   // more dignified manner. The current way may allow using element
   // labels to encode additional information (e.g., D/T or specific
   // basis sets) to element numbers, of both are stored separately.
   if (strcicmp(pName, "D") == 0 || strcicmp(pName, "T") == 0)
      return 1;
   for (int i = 0; i < g_nMaxElement; ++i)
      if (0 == strcicmp(pName, g_ElementNames[i]))
         return i;
   throw std::runtime_error( "Failed to look up atomic number for element symbol '"+std::string(pName)+"'");
}


double GetCovalentRadius(int iElement)
{
   CheckElement(iElement);
   return g_CovalentRadii[size_t(iElement)];
}


} // namespace ct

// kate: syntax c++;
