#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <stdexcept>

#include "test_utils.hh"

#include "geners/GeneralCatalog.hh"
#include "geners/CatalogIO.hh"

using namespace gs;
using namespace std;

int main(int argc, char* argv[])
{
    const char *progname = strrchr(argv[0], '/');
    if (progname)
	++progname;
    else
	progname = argv[0];

    bool useRegexForName = true;
    bool useRegexForCategory = true;

    int c;
    bool errflg = false;
    extern int optind;
    while((c = getopt(argc, argv, "cn")) != EOF)
    {
        switch (c)
        {
        case 'c':
            useRegexForCategory = false;
            break;
        case 'n':
            useRegexForName = false;
            break;
	default:
	    errflg = true;
	    break;
        }
    }

    if (argc - optind != 3 || errflg)
    {
        cerr << "\nUsage: " << progname 
             << " [-n] [-c] namePattern categoryPattern filename\n\n"
             << "Flags -n and -c can be used to turn off regular expression matching\n"
             << "for names and categories, respectively, and to search for the exact\n"
             << "match instead.\n"
             << endl;
        return 1;
    }

    char* namePattern = argv[optind];
    char* categoryPattern = argv[optind+1];
    char* filename = argv[optind+2];

    ifstream in(filename, ios_base::binary);
    if (!in.is_open())
    {
        cerr << "Error: failed to open file \"" << filename << "\""
             << std::endl;
        return 1;
    }

    unsigned compressionCode = 0, mergeLevel = 0;
    std::vector<std::string> annotations;
    CPP11_auto_ptr<GeneralCatalog> cat(readBinaryCatalog<GeneralCatalog>(
                 in, &compressionCode, &mergeLevel, &annotations, true));
    if (cat.get() == 0)
    {
        cerr << "Error: failed to read catalog from file \"" << filename << "\""
             << endl;
        return 1;
    }

    const SearchSpecifier& nameSearch = useRegexForName ? 
        SearchSpecifier(Regex(namePattern)) :
        SearchSpecifier(namePattern);
    const SearchSpecifier& categorySearch = useRegexForCategory ?
        SearchSpecifier(Regex(categoryPattern)) : 
        SearchSpecifier(categoryPattern);

    std::vector<unsigned long long> idlist;
    try {
        cat->search(nameSearch, categorySearch, &idlist);
    }
    catch (std::exception& e) {
        cerr << "Error in search: " << e.what() << endl;
        return 1;
    }

    const unsigned long sz = idlist.size();
    if (sz)
    {
        for (unsigned long item=0; item<sz; ++item)
        {
            CPP11_shared_ptr<const CatalogEntry> e = 
                cat->retrieveEntry(idlist[item]);
            if (item)
                cout << '\n';
            e->humanReadable(cout);
        }
    }
    else
        cout << "No matching items" << endl;

    return 0;
}
