/*
 * Regexp example: Bill parsing
 *
 * Note: The regexp library in GCC-4.7 is unfinished. The running of this code
 * will cause regex_error exception. (Altrough the syntax of regular expressions
 * is valid ECMAScript),
 */
#include <vector>
#include <iostream>
#include <string>
#include <regex>

using namespace std;



class Item {
public:
    Item(string id_, string name_, int cnt_, double price_) :
        id(id_), name(name_), cnt(cnt_), price(price_) {};

    const string id;
    const string name;
    const int cnt;
    const double price;
};

class Bill {
public:
    static Bill billFactory(vector<string>& text) {

        regex rmId (R"DELIM(^.+ Invoice (SML-(\w|-)+).*$)DELIM");
        regex rmDate (R"DELIM(^.* (\d\d)\/(\d\d)\/(\d{4})$)DELIM");
        regex rmTotal (R"DELIM(^.*Total: (-?\d{1,3}( \d{3})*(\.\d+)?) EUR$)DELIM");
        regex rmItem (R"DELIM(^\d+ (.+?) (\S+) (\d{1,3}(?: \d{3})*) (-?\d{1,3}(?: \d{3})*(?:\.\d+)?) EUR -?\d{1,3}(?: \d{3})*(?:\.\d+)? EUR$)DELIM");
        regex rmSpace (" ");

        auto it = text.cbegin();
        Bill bill = Bill();

        while(!regex_match(*it, rmId)) {
            ++it;
            if (text.end() == it) {
                return bill;
            }
        }
        bill.id = regex_replace(*it, rmId, string("$1"));

        while(!regex_match(*it, rmDate)) {
            ++it;
            if (text.end() == it) {
                return bill;
            }
        }
        bill.date = regex_replace(*it, rmDate, string("$3-$2-$1"));

        bill.total = 0;
        while(!regex_match(*it, rmTotal)) {
            smatch sm;
            if (regex_match(*it, sm, rmItem)) {
                Item item = { sm[2].str(), sm[1].str(),
                     atoi(regex_replace(sm[3].str(), rmSpace, string("")).c_str()),
                     atof(regex_replace(sm[3].str(), rmSpace, string("")).c_str()) };
                bill.items.push_back(item);
                bill.total += item.cnt * item.price;
            }
        }
        double parsedTotal = atof(regex_replace(
                    regex_replace(*it, rmTotal, string("$1")), rmSpace, string("")).c_str());
        if (bill.items.size() > 0 && fabs(bill.total - parsedTotal) < bill.total * 0.001) {
            bill.isValid = true;
        }
        return bill;
    }

    bool isValid;
    string id;
    string date;        //TODO
    vector<Item> items;
    double total;

private:
    Bill() { isValid = false; }
};




int main ()
{
    vector<string> testInput =
        {  "Invoice somethingsomething"
           , "fédgkdéf"
           , "Invoice SML-2011-edf456 dlfj viojgdofjb dsfd"
           , "dfélfé 234/324 45"
           , "efofijsdo ndifjgodgi 12/3/2012"
           , "id name item_id cnt price subtotal"
           , "1 piros cd lejatszo 34_CHERRY 34 2.5 EUR 85.0 EUR"
           , "2 mp3 rock er 43534-ROCK 2 000 0.04 EUR 80.0 EUR"
           , "felirmerhetetlen sordf oo pvoc"
           , "3 plasma Tv 434_TVrt 10 423.0 EUR 4 230.0 EUR"
           , "    Total: 4 415.0"
           , " lrfkdfl  flkgm"
        };

    Bill b = Bill::billFactory(testInput);

    if (b.isValid) {
        printf("A szamla vegosszege: %.2f\n", b.total);
        printf(  "tetelek szama: %d\n", b.items.size());
    } else {
        printf("A szamla hibas.\n");
    }

    return 0;
}
