#include <gatb/gatb_core.hpp>
#include <iostream>
#define STR_OUT_COVERAGE_FILE_NAME              "-coverage_file"



/*** Takes a set of h5 input files, coma separated, and finishing with a comma ***/
/*** those input files contain only a cutoff group ***/
/*** Return 0 except in case of failure ***/
int glue_simple_h5_files(std::string input_h5_file_names, std::string output_h5_file_name){
    try{
        std::string delimiter = ",";
        
        // PREPARE FOR WRITING
        Storage* storage_out = StorageFactory(STORAGE_HDF5).create (output_h5_file_name, true, false);
        LOCAL (storage_out);
        Group& root_out = storage_out->root();
        Collection<NativeInt64>& myIntegers_out = root_out.getCollection<NativeInt64> ("cutoffs");
        
        
        
        
        // PARSE ALL INPUT H5 files, Dump their content in the output h5.
        size_t pos = 0;
        std::string token;
        while ((pos = input_h5_file_names.find(delimiter)) != std::string::npos) {
            token = input_h5_file_names.substr(0, pos);
            cout<<"reading "<<token<<endl;
            // READING
            Storage* storage = StorageFactory(STORAGE_HDF5).load (token);
            LOCAL (storage);
            Group& root = storage->root();
            Collection<NativeInt64>&  myIntegers = root.getCollection<NativeInt64> ("cutoff");

            
            // We create an iterator for our collection.
            Iterator<NativeInt64>* iterInt = myIntegers.iterator();
            LOCAL (iterInt);
            // WRITING the content of the input h5. should have only on value
            for (iterInt->first(); !iterInt->isDone(); iterInt->next())  {
                
                int n=iterInt->item().toInt();
                myIntegers_out.insert (n);
                break;                          // only one value
            }
            myIntegers.flush();
            
            // Get the next asked coverage valoue
            input_h5_file_names.erase(0, pos + delimiter.length());
        }
        // no need to get the last value as entry finishes with a ',' from run_discoSnp++_ML.sh
        myIntegers_out.flush();
    }
    catch (OptionFailure& e)
    {
        return e.displayErrors (std::cerr);
    }
    catch (Exception& e)
    {
        std::cerr << "EXCEPTION: " << e.getMessage() << std::endl;
    }
    return 0;
}

/*** Takes one h5 input file, all generated by dks ***/
/*** Dump its cuttoff value (either the one asked by the user or the one computed by dsk if the user asked for automatic value) in an output h5 file.  ***/
/*** Return 0 except in case of failure ***/
int from_large_h5_file_to_only_cutoff_h5_file(std::string input_h5_file_name, std::string output_h5_file_name){
    
    try
    {
        
        // PREPARE FOR WRITING
        Storage* storage_out = StorageFactory(STORAGE_HDF5).create (output_h5_file_name, true, false);
        LOCAL (storage_out);
        Group& root_out = storage_out->root();
        Collection<NativeInt64>& myIntegers_out = root_out.getCollection<NativeInt64> ("cutoff");
        
        
        
        
        // PARSE THE INPUT H5 file. Dump its content in the output h5.
        
        
        // READING
        Storage* storage = StorageFactory(STORAGE_HDF5).load (input_h5_file_name);
        LOCAL (storage);
        Group& root = storage->root();
        
        Group& configGroup = storage->getGroup("configuration");
        stringstream ss; ss << configGroup.getProperty ("xml");
        Properties props; props.readXML (ss);
        int asked_ab_min = props.getInt("abundance_min");
        
        
        if (asked_ab_min != -1) // if asked_ab_min != auto
        {
            myIntegers_out.insert (asked_ab_min);
        }
        else // recover the automatic value computed by dsk in the /histogram/cutoff field.
        {
            Group& histo = root.getGroup("histogram");
            Collection<NativeInt64>& myIntegers = histo.getCollection<NativeInt64> ("cutoff");
            // We create an iterator for our collection.
            Iterator<NativeInt64>* iterInt = myIntegers.iterator();
            LOCAL (iterInt);
            // WRITING the content of the input h5.
            for (iterInt->first(); !iterInt->isDone(); iterInt->next())  {
                int n=iterInt->item().toInt();
                myIntegers_out.insert (n);
                break;                          // only one value
            }
            myIntegers.flush();
        }
        myIntegers_out.flush();
        
        
    }
    catch (OptionFailure& e)
    {
        return e.displayErrors (std::cerr);
    }
    catch (Exception& e)
    {
        std::cerr << "EXCEPTION: " << e.getMessage() << std::endl;
    }
    return 0;
}


/********************************************************************************/
/*** Deal with h5 files for multiple large version of discoSnp ***/
/*** Two main features:
     If the input file(s) contain comas, then merge cutoff value of all input h5 files in an output h5 file
     If the input does not contain coma, this is the raw h5 output from dsk. We need only to dump the cutoff value, either asked by user or computed by dsk in case of automatic computation of the cutoff
 ***/
int main (int argc, char* argv[])
{
    /** We create a command line parser. */
    OptionsParser parser ("CoverageDump");
    parser.push_back (new OptionOneParam (STR_URI_INPUT, " set of .h5 files from which one need to grab the coverage cutoff ",   true));
    parser.push_back (new OptionOneParam (STR_OUT_COVERAGE_FILE_NAME, " name of the created .h5 coverage file ",   true));
    IProperties* options = parser.parse (argc, argv);
    std::string input_h5_file_names = options->getStr(STR_URI_INPUT);
    std::string output_h5_file_name = options->getStr(STR_OUT_COVERAGE_FILE_NAME);
    
    if (input_h5_file_names.find(",") != std::string::npos) {
        // first case, need to merge h5 files:
        return glue_simple_h5_files(input_h5_file_names, output_h5_file_name);
    }
    else{
        return from_large_h5_file_to_only_cutoff_h5_file(input_h5_file_names, output_h5_file_name);
    }
    
//    try
//    {
//        IProperties* options = parser.parse (argc, argv);
//        
//        std::string input_h5_file_names = options->getStr(STR_URI_INPUT); // h5 files, separated by comma
//        std::string delimiter = ",";
//        
//        // PREPARE FOR WRITING
//        Storage* storage_out = StorageFactory(STORAGE_HDF5).create (options->getStr(STR_OUT_COVERAGE_FILE_NAME), true, false);
//        LOCAL (storage_out);
//        Group& root_out = storage_out->root();
//        Collection<NativeInt64>& myIntegers_out = root_out.getCollection<NativeInt64> ("cutoffs");
//        
//        
//        
//        
//        // PARSE ALL INPUT H5 files, Dump their content in the output h5.
//        size_t pos = 0;
//        std::string token;
//        while ((pos = input_h5_file_names.find(delimiter)) != std::string::npos) {
//            token = input_h5_file_names.substr(0, pos);
//            cout<<"reading "<<token<<endl;
//            // READING
//            Storage* storage = StorageFactory(STORAGE_HDF5).load (token);
//            LOCAL (storage);
//            Group& root = storage->root();
//            
//            Group& configGroup = storage->getGroup("configuration");
//            stringstream ss; ss << configGroup.getProperty ("xml");
//            Properties props; props.readXML (ss);
//            int asked_ab_min = props.getInt("abundance_min");
//            
//            
//            if (asked_ab_min != -1) // if asked_ab_min != auto
//            {
//                myIntegers_out.insert (asked_ab_min);
//            }
//            else // recover the automatic value computed by dsk in the /histogram/cutoff field.
//            {
//                Group& histo = root.getGroup("histogram");
//                Collection<NativeInt64>& myIntegers = histo.getCollection<NativeInt64> ("cutoff");
//                // We create an iterator for our collection.
//                Iterator<NativeInt64>* iterInt = myIntegers.iterator();
//                LOCAL (iterInt);
//                // WRITING the content of the input h5.
//                for (iterInt->first(); !iterInt->isDone(); iterInt->next())  {
//                    int n=iterInt->item().toInt();
//                    myIntegers_out.insert (n);
//                    break;                          // only one value
//                }
//                myIntegers.flush();
//            }
//            // Get the next asked coverage valoue
//            input_h5_file_names.erase(0, pos + delimiter.length());
//        }
//        // no need to get the last value as entry finishes with a ',' from run_discoSnp++_ML.sh
//        myIntegers_out.flush();
//        
//        
//    }
//    catch (OptionFailure& e)
//    {
//        return e.displayErrors (std::cerr);
//    }
//    catch (Exception& e)
//    {
//        std::cerr << "EXCEPTION: " << e.getMessage() << std::endl;
//    }
}