#include <string>
#include <iostream>
#include <iomanip>
#include <set>
#include <memory>
#include <string.h>

#include "TError.h"
#include "TROOT.h"
#include "TFile.h"
#include "TKey.h"
#include "TTree.h"
#include "TChain.h"

#include "JSystem/JGlob.hh"

#include "Jeep/JParser.hh"
#include "Jeep/JMessage.hh"


namespace {

  /**
   * Auxiliary data structure for TChain.
   */
  struct JChain :
    public std::unique_ptr<TChain>
  {
    /**
     * Default constructor.
     */
    JChain()
    {}

    /**
     * Constructor.
     *
     * \param  name        name of TTree
     */
    JChain(const char* const name) :
      std::unique_ptr<TChain>(new TChain(name))
    {}

    /**
     * Less-than operator for TChain.
     *
     * \param  first       first  TChain
     * \param  second      second TChain
     * \return             true if name of first TChain is less than that of second; else false
     */
    friend inline bool operator<(const JChain& first, const JChain& second)
    {
      return strcmp(first->GetName(), second->GetName()) < 0;
    }
  };
}


/**
 * \file
 *
 * Auxiliary program to print ROOT TChain information.
 * \author mdejong
 */
int main(int argc, char **argv)
{
  using namespace std;
  using namespace JPP;

  vector<string>     inputFile;
  int                debug;

  try { 

    JParser<> zap("Auxiliary program to print ROOT TChain information.");
    
    zap['f'] = make_field(inputFile);
    zap['d'] = make_field(debug)           = 1;

    zap(argc, argv);
  }
  catch(const exception &error) {
    FATAL(error.what() << endl);
  }

  gErrorIgnoreLevel = kFatal;

  inputFile = getFilenames(inputFile);

  set<JChain> buffer;

  for (vector<string>::const_iterator file_name = inputFile.begin(); file_name != inputFile.end(); ++file_name) {

    TFile* file = TFile::Open(file_name->c_str());

    if (file != NULL) {

      TIter iter(file->GetListOfKeys(), kIterBackward);

      for (TKey* key; (key = (TKey*) iter.Next()) != NULL; ) {

        TKey* p = dynamic_cast<TKey*>(file->GetListOfKeys()->Before(key));

        if (p == NULL || strcmp(key->GetName(), p->GetName()) != 0) {                      // select last key

          TTree* tree = dynamic_cast<TTree*>(key->ReadObj());

          if (tree != NULL) {
	    buffer.insert(JChain(tree->GetName()));
	  }
	}
      }

      file->Close();

      delete file;
    }
  }

  for (auto& chain : buffer) {

    for (vector<string>::const_iterator file_name = inputFile.begin(); file_name != inputFile.end(); ++file_name) {
      chain->Add(file_name->c_str());
    }

    cout << setw(24) << left  <<  chain->GetName()    << ' '
	 << setw(10) << right <<  chain->GetEntries() << endl;
  }
}