#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

#define FOOTNOTE_HEADER                 "@footnote:"
#define FOOTNOTE_START                  '['
#define FOOTNOTE_END                    ']'
#define FOOTNOTE_ALLOWEDCHARS   "0123456789"

// not very clean, but fast...
#define to_string(from, to, stringstream)       \
                               stringstream.clear();           \
                               stringstream.str("");           \
                               stringstream << from;           \
                               to = stringstream.str();
#define from_string(from, to, stringstream) \
                               stringstream.clear();           \
                               stringstream.str(from);         \
                               stringstream >> to;

int main(int argc, char ** argv) {
       int                                     FOOTNOTE_HEADER_LEN                     = strlen(FOOTNOTE_HEADER);
       int                                     FOOTNOTE_ALLOWEDCHARS_LEN       = strlen(FOOTNOTE_ALLOWEDCHARS);

       ifstream                        input(argv[1]);
       string                          line;                           // ... for reading from file
       string                          strold;                         // old footnote as string
       string                          strnew;                         // new footnote as string
       string::size_type       pos1    = 0;
       string::size_type       pos2    = 0;
       bool                            found   = false;        // indicates whether we've found the footnote header
       size_t                          last    = 0;            // last used footnote
       size_t                          old             = 0;            // old footnote as number
       std::vector<size_t>     mapping(1024, 0);       // mapping between old and new footnote numbers
       stringstream            ss;                                     // for conversions (string <-> size_t)

       // process input until footnote header has been found
       while (!found && getline(input, line)) {

               // check for footnote header
               if (line.compare(0, FOOTNOTE_HEADER_LEN, FOOTNOTE_HEADER) == 0) {
                       found = true;
                       cout << line << endl;
                       continue;
               }

               // search footnotes
               pos1 = 0;
               while ( (pos1 = line.find_first_of(FOOTNOTE_START,      pos1)) != string::npos) {
                       pos2 = line.find_first_not_of(FOOTNOTE_ALLOWEDCHARS, pos1 + 1, FOOTNOTE_ALLOWEDCHARS_LEN);

                       // skip invalid footnote references
                       if (pos2 == string::npos || pos2 < pos1 + 2 || line[pos2] != FOOTNOTE_END) {
                               pos1 = pos2;
                               continue;
                       }

                       // we found a valid footnote reference
                       strold = line.substr(pos1 + 1, pos2 - pos1 - 1);
                       from_string(strold, old, ss);

                       // resize vector if it is to small
                       if (old + 1 > mapping.size()) mapping.resize(old + 1, 0);

                       if (mapping[old] != 0) {
                               // known footnote -> use stored number
                               to_string(mapping[old], strnew, ss);
                       }
                       else {
                               // unknown footnote -> new number
                               last++;
                               mapping[old] = last;
                               to_string(last, strnew, ss);
                       }

                       // replace footnote number
                       line.replace(pos1 + 1, pos2 - pos1 - 1, strnew);
                       pos1 = pos2 - strold.size() + strnew.size();
               }
               cout << line << endl;
       }


       // process foot notes

       std::vector<std::string> storage(last, string());

       while (getline(input, line)) {

               // print empty lines directly
               if (line.empty()) { cout << endl; continue; }

               // skip lines without a footnote
               if (line[0] != FOOTNOTE_START) continue;
               pos1 = line.find_first_not_of(FOOTNOTE_ALLOWEDCHARS, 1, FOOTNOTE_ALLOWEDCHARS_LEN);
               if (pos1 == string::npos || line[pos1] != FOOTNOTE_END) continue;

               // store footnote
               strold = line.substr(1, pos1 - 1);
               from_string(strold, old, ss);
               if (old + 1> mapping.size() || mapping[old] == 0) {
                       // skip unknown (i.e. unreferenced) footnotes
                       cerr << "unreferenced footnote " << old << endl;
                       continue;
               }
               storage[mapping[old] - 1] = line.substr(pos1 + 1);
       }

       // print sorted list of footnotes
       for (size_t i = 0; i < storage.size(); i++) {
               if (storage[i].empty()) cerr << "missing footnote " << i + 1 << endl;
               cout << FOOTNOTE_START << i + 1 << FOOTNOTE_END << storage[i] << endl;
       }
}