// @(#)root/star:$Name:  $:$Id: TFileSet.cxx,v 1.3 2003/12/30 13:16:51 brun Exp $
// Author: Valery Fine(fine@mail.cern.ch)   03/07/98
// $Id: TFileSet.cxx,v 1.3 2003/12/30 13:16:51 brun Exp $

#include "TFileSet.h"
#include "TBrowser.h"
#include "TSystem.h"

#ifndef WIN32
#include <errno.h>
#endif

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TFileSet                                                             //
//                                                                      //
// TFileSet class is a class to convert the                             //
//      "native file system structure"                                  //
// into an instance of the TDataSet class                               //
//                                                                      //
//  Example:                                                            //
//    How to convert your home directory into the OO dataset            //
//                                                                      //
//  root [0] TString home = "$HOME";                                    //
//  root [1] TFileSet set(home);                                        //
//  root [2] TBrowser b("MyHome",&set);                                 //
//  root [3] set.ls("*");                                               //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

ClassImp(TFileSet)

//______________________________________________________________________________
  TFileSet::TFileSet()
           : TDataSet()
{
}

//______________________________________________________________________________
TFileSet::TFileSet(const TString &dirname,const Char_t *setname,Bool_t expand, Int_t maxDepth)
           : TDataSet()
{
  //
  // Creates TFileSet
  // Convert the "opearting system" file system tree into the memory resided TFileSet
  //
  //  Parameters:
  //  -----------
  //  dirname  - the name of the "native file system" directory
  //             to convert into TFileSet
  //  setname  - the name of this TFileSet (it is the "base name"
  //                                 of the "dirname" by default)
  //  expand   - flag whether the "dirname" must be "expanded
  //             (kTRUE by default)
  //  maxDeep  - the max number of the levels of the directory to read in
  //             (=10 by default)
  //  Note: If the "dirname" points to non-existent object, for examoe it is dead-link
  //  ----  the object is marked as "Zombie" and this flag is propagated upwards

  if (!maxDepth) return;

  Long64_t size;
  Long_t id, flags, modtime;
  TString dirbuf = dirname;

  if (expand) gSystem->ExpandPathName(dirbuf);
  const char *name= dirbuf;
  if (gSystem->GetPathInfo(name, &id, &size, &flags, &modtime)==0) {

    if (!setname) {
      setname = strrchr(name,'/');
      if (setname) setname++;      
    }
    if (setname) SetName(setname);
    else SetName(name);

    // Check if "dirname" is a directory.
    void *dir = 0;
    if (flags & 2 ) {
       dir = gSystem->OpenDirectory(name);
       if (!dir) {
#ifndef WIN32
         perror("can not be open due error\n");
         fprintf(stderr, " directory: %s",name);
#endif
       }
    }
    if (dir) {   // this is a directory
      SetTitle("directory");
      while ( (name = gSystem->GetDirEntry(dir)) ) {
         // skip some "special" names
         if (!name[0] || strcmp(name,"..")==0 || strcmp(name,".")==0) continue;
         Char_t *file = gSystem->ConcatFileName(dirbuf,name);
         TString nextdir = file;
         delete [] file;
         TFileSet *fs = new TFileSet(nextdir,name,kFALSE,maxDepth-1);
         if (fs->IsZombie())  {
           // propagate "Zombie flag upwards
           MakeZombie(); 
         }
         Add(fs);
      }
      gSystem->FreeDirectory(dir);
    }
    else
       SetTitle("file");
  } else { 
    // Set Zombie flag
    MakeZombie(); 
    SetTitle("Zombie");
  }
}

//______________________________________________________________________________
TFileSet::~TFileSet()
{
}

//______________________________________________________________________________
Bool_t TFileSet::IsEmpty() const
{
 return  strcmp(GetTitle(),"file")!=0 ? kTRUE : kFALSE ;
}

//______________________________________________________________________________
Long_t TFileSet::HasData() const
{
  // This implementation is done in the TDataSet::Purge() method in mind
  // Since this method returns non-zero for files the last are NOT "purged"
  // by TDataSet::Purge()
  //
   return strcmp(GetTitle(),"file")==0 ? 1 : 0;

   //  this must be like this:
   //  return !IsFolder() ;
   //  Alas TObject::IsFolder() isn't defined as "const" (IT IS in 2.25/03)
}

//______________________________________________________________________________
Bool_t TFileSet::IsFolder() const
{
 // If the title of this TFileSet is "file" it is NOT folder
 // see: TFileSet(TString &dirname,const Char_t *setname,Bool_t expand)
 //
 return strcmp(GetTitle(),"file")!=0;
}
