// ============================================================================
//  $Id: TFileProperty.cc,v 1.5 2004/06/24 15:15:26 goiwai Exp $
//  $Name: CLDAQ-1-14-06 $
//  $Log: TFileProperty.cc,v $
//  Revision 1.5  2004/06/24 15:15:26  goiwai
//  たくさんの変更
//  Tcout,Tcerr,Tlogをバッファ経由にした。
//  何個かexternした。Tlog,Tcout,Tcerr,Tinfo...Tcritなど出力関係。
//
//  Revision 1.4  2004/03/07 17:38:46  goiwai
//  *** empty log message ***
//
//  Revision 1.3  2004/03/07 16:56:04  goiwai
//  *** empty log message ***
//
//  Revision 1.2  2004/03/07 10:30:34  goiwai
//  ROOTに組みこむためのおまじないマクロを埋めこみました。
//  全てにおいて完全に動作するわけではありません。
//
//  Revision 1.1  2003/10/06 16:37:37  goiwai
//  ファイルの情報を表現するためのクラスです.
//
// ============================================================================
#include "TFileProperty.hh"
#include "TSystemClock.hh"

TFileProperty::TFileProperty()
  : thePathName( "?" ),
    theDirectoryName( "?" ),
    theFileName( "?" ),
    theFileRootName( "?" ),
    theFileExtensionName( "?" ),
    theDeviceNumber( -1 ),
    theDeviceMajorNumber( -1 ),
    theDeviceMiorNumber( -1 ),
    theInodeNumber( -1 ),
    theProtection( -1 ),
    theNumberOfHardLinks( -1 ),
    theDeviceType( -1 ),
    theTotalSize( -1 ),
    theBlockSize( -1 ),
    theNumberOfBlocks( -1 ),
    theUserID( -1 ),
    theGroupID( -1 ),
    theLastAccess( -1 ),
    theLastModification( -1 ),
    theLastChange( -1 ),
    theStringUserID( "?" ),
    theStringGroupID( "?" ),
    theStringLastAccess( "?" ),
    theStringLastModification( "?" ),
    theStringLastChange( "?" )
{;}

TFileProperty::TFileProperty( const Tstring& path )
  : thePathName( path ),
    theDirectoryName( "?" ),
    theFileName( "?" ),
    theFileRootName( "?" ),
    theFileExtensionName( "?" ),
    theDeviceNumber( -1 ),
    theDeviceMajorNumber( -1 ),
    theDeviceMiorNumber( -1 ),
    theInodeNumber( -1 ),
    theProtection( -1 ),
    theNumberOfHardLinks( -1 ),
    theDeviceType( -1 ),
    theTotalSize( -1 ),
    theBlockSize( -1 ),
    theNumberOfBlocks( -1 ),
    theUserID( -1 ),
    theGroupID( -1 ),
    theLastAccess( -1 ),
    theLastModification( -1 ),
    theLastChange( -1 ),
    theStringUserID( "?" ),
    theStringGroupID( "?" ),
    theStringLastAccess( "?" ),
    theStringLastModification( "?" ),
    theStringLastChange( "?" )
{
  Analyse();
}

TFileProperty::TFileProperty( const TFileProperty& right )
  : thePathName( right.thePathName ),
    theDirectoryName( "?" ),
    theFileName( "?" ),
    theFileRootName( "?" ),
    theFileExtensionName( "?" ),
    theDeviceNumber( -1 ),
    theDeviceMajorNumber( -1 ),
    theDeviceMiorNumber( -1 ),
    theInodeNumber( -1 ),
    theProtection( -1 ),
    theNumberOfHardLinks( -1 ),
    theDeviceType( -1 ),
    theTotalSize( -1 ),
    theBlockSize( -1 ),
    theNumberOfBlocks( -1 ),
    theUserID( -1 ),
    theGroupID( -1 ),
    theLastAccess( -1 ),
    theLastModification( -1 ),
    theLastChange( -1 ),
    theStringUserID( "?" ),
    theStringGroupID( "?" ),
    theStringLastAccess( "?" ),
    theStringLastModification( "?" ),
    theStringLastChange( "?" )
{
  Analyse();
}

TFileProperty::~TFileProperty()
{;}

const TFileProperty& TFileProperty::operator=( const TFileProperty& right )
{
  thePathName = right.thePathName;
  Analyse();
  return *this;
}

Tbool TFileProperty::operator==( const TFileProperty& right ) const
{
  return thePathName == right.thePathName;
}

Tbool TFileProperty::operator!=( const TFileProperty& right ) const
{
  return thePathName != right.thePathName;
}

Tvoid TFileProperty::Analyse()
{
  if ( thePathName.empty() ) {
    //CLDAQ_WARN( "file name unset" );
    Tcout << "file name unset" << Tendl;
    return;
  }

  theDirectoryName = dirname( thePathName );
  theFileName = basename( thePathName );

  if ( ! theFileName.empty() ) {
    Tint pos = theFileName.find_last_of( '.' );
    if ( pos >= 0 ) {
      theFileExtensionName = theFileName.substr( pos + 1, theFileName.size() - pos - 1 );
      theFileRootName = theFileName.substr( 0, pos );
    }
  }

  struct stat buf;
  const char* fname = thePathName.c_str();
  if ( stat( fname, &buf ) != 0 ) {
    //CLDAQ_WARN( "fail to get file" );
    Tcout << "fail to get file" << Tendl;
    return;
  }

  theDeviceNumber = (Tint)buf.st_dev;
  theDeviceMajorNumber = major( theDeviceNumber );
  theDeviceMiorNumber = minor( theDeviceMiorNumber );
  theInodeNumber = (Tint)buf.st_ino;
  theProtection = (Tint)buf.st_mode;
  theNumberOfHardLinks = (Tint)buf.st_nlink;
  theUserID = (Tint)buf.st_uid;
  theGroupID = (Tint)buf.st_gid;
  theDeviceType = (Tint)buf.st_rdev;
  theTotalSize = (Tint)buf.st_size;
  theBlockSize = (Tint)buf.st_blksize;
  theNumberOfBlocks = (Tint)buf.st_blocks;


  struct passwd* pw = getpwuid( (uid_t)theUserID );
  if ( pw != 0 ) {
    theStringUserID = pw -> pw_name;
  }


  struct group* gr = getgrgid( (gid_t)theGroupID );
  if ( gr != 0 ) {
    theStringGroupID = gr -> gr_name;
  }

  theLastAccess = (Tint)buf.st_atime;
  theLastModification = (Tint)buf.st_mtime;
  theLastChange = (Tint)buf.st_ctime;

  TSystemClock clock;
  theStringLastAccess = clock.WhatTimeIsIt( theLastAccess );
  theStringLastModification = clock.WhatTimeIsIt( theLastModification );
  theStringLastChange = clock.WhatTimeIsIt( theLastChange );

  return;
}

Tbool TFileProperty::IsCharacterDevice() const
{
  return S_ISREG( theProtection );
}

Tbool TFileProperty::IsBlockDevice() const
{
  return S_ISBLK( theProtection );
}

Tbool TFileProperty::IsFIFO() const
{
  return S_ISFIFO( theProtection );
}

Tbool TFileProperty::IsSocket() const
{
  return S_ISSOCK( theProtection );
}

Tbool TFileProperty::IsSymbolicLink() const
{
  return S_ISLNK( theProtection );
}

Tbool TFileProperty::IsRegularFile() const
{
  return S_ISREG( theProtection );
}

Tbool TFileProperty::IsDirectory() const
{
  return S_ISDIR( theProtection );
}

Tbool TFileProperty::IsReadable() const
{
  if ( access( thePathName.c_str(), R_OK ) == 0 ) {
    return Ttrue;
  } else {
    return Tfalse;
  }
}

Tbool TFileProperty::IsWritable() const
{
  if ( access( thePathName.c_str(), W_OK ) == 0 ) {
    return Ttrue;
  } else {
    return Tfalse;
  }
}

Tbool TFileProperty::IsExecutable() const
{
  if ( access( thePathName.c_str(), X_OK ) == 0 ) {
    return Ttrue;
  } else {
    return Tfalse;
  }
}

Tostream& operator<<( Tostream& tos, const TFileProperty& right )
{
  Tstring strbuf;
  if ( right.IsSymbolicLink() ) {
    strbuf = "l";
  } else if ( right.IsDirectory() ) {
    strbuf = "d";
  } else if ( right.IsRegularFile() ) {
    strbuf = "-";
  } else if ( right.IsCharacterDevice() ) {
    strbuf = "c";
  } else if ( right.IsBlockDevice() ) {
    strbuf = "b";
  } else if ( right.IsSocket() ) {
    strbuf = "s";
  } else if ( right.IsFIFO() ) {
    strbuf = "p";
  } else {
    strbuf = "?";
  }

  if ( right.IsReadable() ) {
    strbuf += "r";
  } else {
    strbuf += "-";
  }


  if ( right.IsWritable() ) {
    strbuf += "w";
  } else {
    strbuf += "-";
  }

  if ( right.IsExecutable() ) {
    strbuf += "x";
  } else {
    strbuf += "-";
  }

  tos << "Directory: " << right.theDirectoryName;
  tos << ", File: " << right.theFileName;
  tos << ", Root: " << right.theFileRootName;
  tos << ", Extension: " << right.theFileExtensionName << Tendl;
  tos << strbuf << "  ";
  tos << right.theStringUserID << "(" << right.theUserID << ")  ";
  tos << right.theStringGroupID << "(" << right.theGroupID << ")  ";
  tos << right.theTotalSize << "  ";
  tos << right.thePathName << Tendl;
  tos << "Last Access: " << right.theStringLastAccess << Tendl;
  tos << "Last Modification: " << right.theStringLastModification << Tendl;
  tos << "Last Change: " << right.theStringLastChange << Tflush;

  return tos;
}

#ifdef __CLDAQ_ROOT_DLL
    ClassImp(TFileProperty)
#endif
