OZ++ Class: FileTreeWalker
/******************************************************************************
 *
 * Copyright (c) 2014 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 *  
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 *  FileTreeWalker.h
 *
 *****************************************************************************/

#pragma once

#include <oz++/CommonObject.h>
#include <oz++/CharString.h>
#include <oz++/Pair.h>
#include <oz++/Exception.h>
#include <oz++/SmartPtr.h>
#include <ftw.h>


namespace OZ {

class FileTreeWalker :public CommonObject {
private:
  CharString path;
  int        flags;
  int        openfiles;

public:
  static FileTreeWalker* getInstance(
        const char* path=NULL, 
        int flags=FTW_DEPTH|FTW_PHYS, int openfiles=20)
  {
     static FileTreeWalker* walker = NULL;

      if (walker == NULL && path !=NULL) {
        walker = new FileTreeWalker(path, flags, openfiles); 
     }
     return walker;
  }

private:
  //Constructor
  FileTreeWalker(const char* path, 
        int flags, int openfile)
  :path(path),
   flags(flags),
   openfiles(openfiles)
  {
  }
    
public:
  ~FileTreeWalker()
  {
      //printf("~FileTreeWalker\n");
  }
    
public:
  void start()
  {
      //This enables to delete the singletoninstance of this class when this method ends.
      SmartPtr<FileTreeWalker> walker(this);
      
    if (nftw(path, &(FileTreeWalker::callback), openfiles, flags) == -1) {
        throw IException("Failed to nftw:%s", strerror(errno));
    } else {
        printf("Finished \n");        
    }
  }
  

public:
  //If you would like to customize the enumerate method,
  //please define a subclass of FileTreeWalker and define you own enumerate method
  virtual int enumerate(const char* filepath, const struct stat* sb,
                     int tflag, struct FTW* ftwbuf)
  {
    //Do something here on your own requirement.
    printf("%-4s %7jd %s\n", getFileType(tflag), (intmax_t)sb->st_size, filepath);
      
    return 0;
  }

private:
  static int callback(const char* filepath, const struct stat* sb,
                     int tflag, struct FTW* ftwbuf)
  {
      int rc = 0;
    FileTreeWalker* walker = getInstance();
      if (walker) {
      rc = walker->enumerate(filepath, sb, tflag, ftwbuf);
      } else {
          printf("FileTreeWalker is NULL\n");
      }
      return rc;
  }
    
private:
  const char* getFileType(int type)
  {
    static const Pair<int, const char*> fileTypes[] = 
    {
      {FTW_D,    "d"},
      {FTW_DNR,  "dnr"},
      {FTW_DP,   "dp"},
      {FTW_F,    "f"},
      {FTW_NS,   "ns"},
      {FTW_SL,   "sl"},
      {FTW_SLN, "sln"},
      };
    
      const char* string ="???";
      for(int i = 0; i< SizeOf(fileTypes); i++) {
      if (fileTypes[i].first == type) {
           string = fileTypes[i].second;
           break;
      }
    }
    return string;
  }

};

}