#ifndef __NAMES_H_
#define __NAMES_H_

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::ostream;

namespace argo {
/**
*   Auxiliary class that is used for generating unique variable, and constant
* names
*   All the name start with a given prefix.
*   All the new names are generated by increasing a subscript
*/

class Names {
private:
  unsigned long _max_num;
  std::string _prefix;

public:
  /**
   *   Constructor
   *   @param prefix used for generating unique names
   */
  Names(const std::string &prefix);

  /**
   *   Adds a name. If it starts with the given prefix,
   *   it can be guaranteed that all new names will have greater subscript than
   * this given name
   *   @param name a name that must not be generated again
   */
  void AddName(const std::string &name);

  bool ContainsName(const std::string &name) {
    return name.compare(0, _prefix.length(), _prefix) == 0;
  }

  /**
   *   Gets a new, unique name
   */
  std::string GetName();

  static std::string LaTeXizeUnderscores(const std::string &str) {
    std::string latexized;
    std::string::const_iterator i;
    for (i = str.begin(); i != str.end(); i++)
      if (*i == '_')
        latexized += "\\_";
      else
        latexized += *i;

    return latexized;
  }

  /**
   *   Prints a given name in the LaTeX format
   *   (inserts underscores infront of subscripts)
   */
  static void PrintLaTeX(ostream &ostr, const std::string &Name) {
    size_t UnderScore_pos = Name.find_last_of('_');

    if (UnderScore_pos != std::string::npos) {
      std::string Prefix = Name.substr(0, UnderScore_pos);
      std::string Suffix = Name.substr(UnderScore_pos + 1);
      const std::string digits = "0123456789";

      if (Suffix.find_first_not_of(digits) == std::string::npos)
        ostr << LaTeXizeUnderscores(Prefix) << "_{" << Suffix << "}";
      else
        ostr << LaTeXizeUnderscores(Name);
    } else
      ostr << Name;
  }

  static std::string itoa(int i);

  //#ifdef TEST
  static void test(ostream &expected, ostream &real) {
    Names names("v_");
    names.AddName("zdravo");
    names.AddName("v_1");

    expected << "v_2" << endl;
    real << names.GetName() << endl;

    expected << "v_3" << endl;
    real << names.GetName() << endl;

    names.AddName("v_5");

    expected << "v_6" << endl;
    real << names.GetName() << endl;

    expected << "a\\_b_{3}" << endl;
    PrintLaTeX(cout, "a_b_3");
    cout << endl;

    expected << "a\\_b\\_c" << endl;
    PrintLaTeX(cout, "a_b_c");
    cout << endl;

    expected << "abc" << endl;
    PrintLaTeX(cout, "abc");
    cout << endl;

  }

  //#endif
};

} //end of namespace

#endif
