/*! @file

    $Id$
*/
//       1         2         3         4         5         6         7         8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890

// kompilieren mit g++ spirit.cxx -o spirit

#include <boost/spirit.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <map>
#include <algorithm>

using namespace boost::spirit;
using namespace boost;
using namespace std;

class SortFootnotes { //========================================================
  public: //--------------------------------------------------------------------
    SortFootnotes(char const*const filename): //................................
        num(1), fndef(false), tag(0), begin_of_line(true), result(false) {
      file_iterator<> first(filename);
      if (!first) return;
      file_iterator<> last = first.make_end();
      result =
        parse
        (first, last, /* Follows Grammar in EBNF like Syntax: */
         *(('[' >> ulong_p[bind(&SortFootnotes::fn, this, _1)] >> ']')
           |
           ((eol_p>>"@footnote:">>eol_p)
            [bind(&SortFootnotes::delim, this, _1, _2)])
           |
           (eol_p[bind(&SortFootnotes::newline, this, _1, _2)])
           |
           (anychar_p[bind(&SortFootnotes::txt, this, _1)]))
         >> end_p[bind(&SortFootnotes::end, this, _1, _2)],
         nothing_p).full;
    }
    bool success() { //.........................................................
      return result;
    }
  private: // types ------------------------------------------------------------
    typedef map<unsigned long, unsigned long> NumMap;
    typedef map<unsigned long, std::string> DefMap;
  private: // variables --------------------------------------------------------
    int num;
    NumMap nummap;
    DefMap defmap;
    bool fndef;
    std::string line;
    unsigned long tag;
    bool begin_of_line;
    uint_parser<unsigned long, 10, 1, -1> ulong_p;
    bool result;
  private: // methods, parser callbacks ----------------------------------------
    void delim(file_iterator<> begin, file_iterator<> end) { // delimiter ......
      fndef = true;
      copy(begin, end, ostream_iterator<char>(cout));
    }
    void txt(char v) { // any character ........................................
      if (fndef)
        line+=v;
      else
        cout<<v;
    }
    void newline(file_iterator<> begin, file_iterator<> end) { // new line .....
      if (fndef && tag) {
        defmap[tag] = line+string(begin, end);
        begin_of_line = true;
      } else
        copy(begin, end, ostream_iterator<char>(cout<<line));
      line.clear();
    }
    void fn(unsigned long v) { // footnote .....................................
      if (nummap.insert(make_pair(v, num)).second) ++num;
      if (fndef)
        if (begin_of_line) {
          tag=nummap[v];
          begin_of_line=false;
        } else
          line+='['+lexical_cast<std::string>(nummap[v])+']';
      else
        cout<<'['<<nummap[v]<<']';
    }
    void end(file_iterator<>, file_iterator<>) { // end of input ...............
      for (DefMap::const_iterator it(defmap.begin()); it!=defmap.end(); ++it)
        cout<<'['<<it->first<<']'<<it->second;
    }
};
int main(const int argv, char const*const*const argc) { //======================
  bool result(true);
  for (int i(1); i<argv; ++i) result=result&&(SortFootnotes(argc[i]).success());
  return result ? 0 : 1;
}
