//: C04:Showerr.cpp {RunByHand}
// Z knihy "Myslíme v jazyce C++, část 2" od Bruce Eckela a Chucka Allisona.
// (c) 1995-2004 MindView, Inc. Všechna práva vyhrazena.
// Přečtěte si podmínky používání zdrojových kódů umístěné v souboru 
// 'Licence.txt' dodávaném spolu s balíčkem kódu dostupným na www.MindView.net.
// Odkomentovává generátory chyb.
#include <cstddef>
#include <cstdlib>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include "../require.h"
using namespace std;

const string USAGE =
  "Použití: showerr soubor cislokap\n"
  "kde soubor je zdrojový soubor C++ \n"
  "a cislokap je název kapitoly, do které patří.\n"
  "Najde řádky s komentářem //! a odstraní jej,\n"
  "a připojí //(#) kde # je číslo jedinečné\n"
  "pro všechny soubory, takže je můžete rozpoznat\n"
  "když překladač narazí na chybu.\n"
  "showerr /r\n"
  "Nuluje čítač jedinečných čísel.";

class Showerr {
  const int CHAP;
  const string MARKER, FNAME;
  // Soubor obsahující čítač čísel chyb:
  const string ERRNUM;
  // Soubor obsahující chybové řádky:
  const string ERRFILE;
  stringstream edited; // Upravovaný soubor
  int counter;
public:
  Showerr(const string& f, const string& en,
    const string& ef, int c)
  : CHAP(c), MARKER("//!"), FNAME(f), ERRNUM(en),
    ERRFILE(ef), counter(0) {}
  void replaceErrors() {
    ifstream infile(FNAME.c_str());
    assure(infile, FNAME.c_str());
    ifstream count(ERRNUM.c_str());
    if(count) count >> counter;
    int linecount = 1;
    string buf;
    ofstream errlines(ERRFILE.c_str(), ios::app);
    assure(errlines, ERRFILE.c_str());
    while(getline(infile, buf)) {
      // Najít značku na začátku řádku:
      size_t pos = buf.find(MARKER);
      if(pos != string::npos) {
        // Smazat řádku:
        buf.erase(pos, MARKER.size() + 1);
        // Přidat informaci o čísle chyby:
        ostringstream out;
        out << buf << " // (" << ++counter << ") "
            << "Kapitola " << CHAP
            << " Soubor: " << FNAME
            << " Řádek " << linecount << endl;
        edited << out.str();
        errlines << out.str(); // Připojit soubor s chybami
      }
      else
        edited << buf << "\n"; // Pouze zkopírovat
      ++linecount;
    }
  }
  void saveFiles() {
    ofstream outfile(FNAME.c_str()); // přepisuje
    assure(outfile, FNAME.c_str());
    outfile << edited.rdbuf();
    ofstream count(ERRNUM.c_str()); // přepisuje
    assure(count, ERRNUM.c_str());
    count << counter; // Uložit nový čítač
  }
};

int main(int argc, char* argv[]) {
  const string ERRCOUNT("../errnum.txt"),
    ERRFILE("../errlines.txt");
  requireMinArgs(argc, 1, USAGE.c_str());
  if(argv[1][0] == '/' || argv[1][0] == '-') {
    // Umožnit další přepínače:
    switch(argv[1][1]) {
      case 'r': case 'R':
        cout << "Nuluji čítač" << endl;
        remove(ERRCOUNT.c_str()); // Smazat soubory
        remove(ERRFILE.c_str());
        return EXIT_SUCCESS;
      default:
        cerr << USAGE << endl;
        return EXIT_FAILURE;
    }
  }
  if(argc == 3) {
    Showerr s(argv[1], ERRCOUNT, ERRFILE, atoi(argv[2]));
    s.replaceErrors();
    s.saveFiles();
  }
} ///:~
