// =====================================================================
//  $Id: TUserInterface.cc,v 1.8 2004/03/07 10:30:31 goiwai Exp $
//  $Name: CLDAQ-1-14-06 $
//  $Log: TUserInterface.cc,v $
//  Revision 1.8  2004/03/07 10:30:31  goiwai
//  ROOTに組みこむためのおまじないマクロを埋めこみました。
//  全てにおいて完全に動作するわけではありません。
//
//  Revision 1.7  2003/10/06 17:02:40  goiwai
//  *** empty log message ***
//
//  Revision 1.6  2003/07/30 16:18:52  goiwai
//  ファイルにコミットログをつけることにしました.
//
// =====================================================================
#include "TUserInterface.hh"
#include "TCommand.hh"

//static const Tchar* _cup = "cup";
static Tchar* _clear = "clear";
static Tchar* _cols = "cols";
static Tchar* _lines = "lines";


TUserInterface::TUserInterface( const Tstring& history )
  : theCommandTable(),
    theHistoryFileStream(),
    theCurrentWorkingDirectory( Tslash ), 
    theCommandHistory()
{
  if ( isexist( history ) ) {
    // 同名のファイルがあればアペンドモードかつ,そのファイルをヒストリ追加
    theHistoryFileStream.open( history.c_str(), Tout|Tapp );
    if ( !( theHistoryFileStream.good() ) ) {
      Tcerr << "TUserInterface::TUserInterface: fail to open a file ";
      Tcerr << history << "." << Tendl;
    }

    // ヒストリ追加
    Tifstream ifs( history.c_str() );
    static const Tsize_t buflen = 1024;
    static Tchar buf[ buflen ];
    Tstring strbuf;
    while ( ifs.getline( buf, buflen ) && !ifs.eof() ) {
      if ( ifs.fail() || !ifs.good() ) {
        break;
      }
      strbuf = buf;
      if ( !strbuf.empty() ) {
        theCommandHistory.push_back( strbuf );
      }
    }
    ifs.close();

  } else {
    theHistoryFileStream.open( history.c_str(), Tout );
    if ( !( theHistoryFileStream.good() ) ) {
      Tcerr << "TUserInterface::TUserInterface: fail to open a file ";
      Tcerr << history << "." << Tendl;
    }
  }

  theCommandTable.Clear();

  ClearScreen();
}

TUserInterface::~TUserInterface()
{
  ClearCommands();
  if ( theHistoryFileStream.is_open() ) {
    theHistoryFileStream.close();
  }
}

Tint TUserInterface::AddCommand( TCommand* command )
{
  if ( theCommandTable.AlreadyExist( command ) ) {
    Tcerr << "TUserInterface::AddCommand: already exist command identified as " << command -> GetCommandName() << "." << Tendl;
  } else {
    theCommandTable.AddCommand( command );
  }
  return theCommandTable.GetSize();
}

Tint TUserInterface::RemoveCommand( Tint index )
{
  static const Tstring head = "TUserInterface::RemoveCommand: ";
  if ( index < 0 || index >= theCommandTable.GetSize() ) {
    Tcerr << head << "invalid index " << index << "." << Tendl;
    return theCommandTable.GetSize();
  }
  Tstring fullname = theCommandTable[ index ].GetFullName();
  if ( ! theCommandTable[ index ].IsAliasedCommand() ) {
    delete ( theCommandTable[ index ].GetCommand() );
  }
  Tcout << head << fullname << " was deleted." << Tendl;
  theCommandTable.RemoveCommand( index );

  return theCommandTable.GetSize();
}

Tvoid TUserInterface::ClearCommands()
{
  static const Tstring head = "TUserInterface::ClearCommands: ";
  for ( Tint i = 0; i < theCommandTable.GetSize(); i ++ ) {
    if ( theCommandTable[ i ].GetCommand() ) {
      Tstring fullname = theCommandTable[ i ].GetFullName();
      if ( ! theCommandTable[ i ].IsAliasedCommand() ) {
	delete ( theCommandTable[ i ].GetCommand() );
      }
      Tcout << head << fullname << " was deleted." << Tendl;
    }
  }
  theCommandTable.Clear();
  return;
}

TCommand* TUserInterface::FindCommand( const Tstring& fullname )
{
  return theCommandTable.FindCommand( fullname );
}

TCommand* TUserInterface::FindCommand( const Tstring& name, const Tstring& path )
{
  return theCommandTable.FindCommand( name, path );
}

TCommand* TUserInterface::GetCommand( Tint index )
{
  if ( index < 0 || index >= theCommandTable.GetSize() ) {
    Tcerr << "TUserInterface::GetCommand: invalid index" << Tendl;
    return 0;
  }
  return theCommandTable[ index ].GetCommand();
}

TCommand* TUserInterface::GetCommand( const Tstring& fullname )
{
  return FindCommand( fullname );
}

TCommand* TUserInterface::GetCommand( const Tstring& name, const Tstring& path )
{
  return FindCommand( name, path );
}

Tvoid TUserInterface::ExecuteCommand( const Tstring& command, const TstringList& arguments )
{
  Tstring abspath = ModifyPath( command );
  TCommand* com = FindCommand( abspath );
  if ( com ) {
    com -> Execute( arguments );
  }
  return;
}

Tvoid TUserInterface::ExecuteCommand( const Tstring& command )
{
  TstringList args;
  args.clear();
  ExecuteCommand( command, args );
  return;
}

Tvoid TUserInterface::NotFoundCommand( const Tstring& commandname ) const
{
  // should be overwritten in derived class.
  Tcout << commandname << ": Command not found." << Tendl;
  return;
}

Tvoid TUserInterface::ClearScreen() const
{
  setupterm( 0, 1, 0 );
  //DEBUG//putp( tigetstr( _cup ) );
  putp( tparm( tigetstr( _clear ), 0, 0 ) );
  return;
}

Tint TUserInterface::GetNumberOfColumns() const
{
  setupterm( 0, 1, 0 );
  Tint ncol = tigetnum( _cols );
  return ncol;
}

Tint TUserInterface::GetNumberOfLines() const
{
  setupterm( 0, 1, 0 );
  Tint nlines = tigetnum( _lines );
  return nlines;
}

Tint TUserInterface::GetCurrentWorkingDirectoryLevel() const
{
  Tint nslash = 0;
  for ( Tsize_t i = 0; i < theCurrentWorkingDirectory.size(); i ++ ) {
    if ( theCurrentWorkingDirectory[ i ] == '/' ) {
      nslash ++;
    }
  }
  Tint level = nslash - 1;
  if ( level < 0 ) {
    Tcerr << "TUserInterface::GetCurrentWorkingDirectoryLevel: unexpected level." << Tendl;
  }
  return level;
}

Tvoid TUserInterface::SetCurrentWorkingDirectory( const Tstring& directory )
{
  Tstring path = ModifyPath( directory );

  if ( theCommandTable.AlreadyExistDirectory( path ) ) {
    theCurrentWorkingDirectory = path;
  } else {
    Tcerr << directory << ": No such file or directory." << Tendl;
  }
  return;
}

Tstring TUserInterface::ModifyPath( const Tstring& path ) const
{
  Tstring temppath = path;
  Tstring newpath = theCurrentWorkingDirectory;

  // if global command, nothig to do.
  for ( Tint i = 0; i < theCommandTable.GetSize(); i ++ ) {
    if ( theCommandTable[ i ].IsBuiltinCommand() ) {
      if ( theCommandTable[ i ].GetName() == path ) {
	return path;
      }
    }
  }


  // erase continuas slash
  for ( Tsize_t i = 0; i < temppath.size() - 1; i ++ ) {
    if ( temppath[ i ] == '/' && temppath[ i + 1 ] == '/' ) {
      temppath.erase( i, 1 );
      i --;
    }
  }

  if ( temppath == "." || temppath == "./" ) {
    return newpath;
  }


  if ( temppath.size() > 0 ) {
    if ( temppath[ 0 ] == '/' ) {
      // full path is given
      newpath = temppath;
    } else if ( temppath[ 0 ] != '.' ) {
      // add current prefix
      if ( newpath == "/" ) {
	newpath += temppath;
      } else {
	newpath = newpath + '/' + temppath;
      }
    } else if ( temppath.substr( 0, 2 ) == "./" ) {
      // add current prefix
      if ( newpath == "/" ) {
	newpath += temppath.substr( 2, temppath.size() - 2 );
      } else {
	newpath = newpath + '/' + temppath.substr( 2, temppath.size() - 2 );
      }
    } else {
      // swim up with ".."
      while ( 1 ) {
	if ( temppath.substr( 0, 2 ) == ".." ) {
	  if ( newpath != "/" ) { 
	    newpath = newpath.substr( 0, newpath.rfind( '/' ) + 1 );
	  }
	  if ( temppath == ".." || temppath == "../" ) {
	    break;
	  }
	  temppath = temppath.substr( 3, temppath.size() - 3 );
	} else {
	  newpath += temppath;
	  break;
	}
      }
    }
  }

  if ( newpath != "/" && newpath[ newpath.size() - 1 ] == '/' ) {
    newpath.erase( newpath.size() - 1, 1 );
  }

  if ( newpath[ newpath.size() - 1 ] == '*' ) {
    newpath.erase( newpath.size() - 1, 1 );
  }

  if ( newpath[ newpath.size() - 1 ] == '@' ) {
    newpath.erase( newpath.size() - 1, 1 );
  }

  return newpath;
}

#ifdef __CLDAQ_ROOT_DLL
    ClassImp(TUserInterface)
#endif
