// =====================================================================
//  $Id: TRunInformation.cc,v 1.7 2004/08/27 07:34:46 goiwai Exp $
//  $Name: CLDAQ-1-14-06 $
//  $Log: TRunInformation.cc,v $
//  Revision 1.7  2004/08/27 07:34:46  goiwai
//  setFreeText()でtermiosをいじくるのをやめました。
//  これでBSはきくようになりました。
//
//  Revision 1.6  2004/03/07 10:30:34  goiwai
//  ROOTに組みこむためのおまじないマクロを埋めこみました。
//  全てにおいて完全に動作するわけではありません。
//
//  Revision 1.5  2003/10/06 17:02:45  goiwai
//  *** empty log message ***
//
//  Revision 1.4  2003/07/30 16:20:30  goiwai
//  ファイルにコミットログをつけることにしました.
//
// =====================================================================
#include "TRunInformation.hh"
#include "TOutputHtmlFileStream.hh"

static const Tstring _defaultvalue = "***";

TRunInformation::TRunInformation()
  : theInformationType( tInfoUnknown ),
    theItem(),
    theDefaultValue( _defaultvalue ),
    theValue( theDefaultValue ),
    theSelectableList()
{
  theSelectableList.clear();
}

TRunInformation::TRunInformation( const Tstring& item )
  : theInformationType( tInfoSelectableValue ),
    theItem( item ),
    theDefaultValue( _defaultvalue ),
    theValue( theDefaultValue ),
    theSelectableList()
{
  theSelectableList.clear();
}

TRunInformation::TRunInformation( const Tstring& item, Truninfo_t type )
  : theInformationType( type ),
    theItem( item ),
    theDefaultValue( _defaultvalue ),
    theValue( theDefaultValue ),
    theSelectableList()
{
  theSelectableList.clear();
}

TRunInformation::TRunInformation( const Tstring& item, const TstringList& list )
  : theInformationType( tInfoSelectableValue ),
    theItem( item ),
    theDefaultValue( _defaultvalue ),
    theValue( theDefaultValue ),
    theSelectableList( list )
{;}

TRunInformation::TRunInformation( const Tstring& item, const Tstring& value )
  : theInformationType( tInfoFreeValue ),
    theItem( item ),
    theDefaultValue( value ),
    theValue( theDefaultValue ),
    theSelectableList()
{;}

TRunInformation::TRunInformation( const Tstring& item, const Tstring& value, Truninfo_t type )
  : theInformationType( type ),
    theItem( item ),
    theDefaultValue( value ),
    theValue( theDefaultValue ),
    theSelectableList()
{;}

TRunInformation::TRunInformation( const Tstring& item, const Tstring& value, const TstringList& list )
  : theInformationType( tInfoSelectableValue ),
    theItem( item ),
    theDefaultValue( value ),
    theValue( theDefaultValue ),
    theSelectableList( list )
{;}

TRunInformation::TRunInformation( const TRunInformation& right )
  : theInformationType( right.theInformationType ),
    theItem( right.theItem ),
    theDefaultValue( right.theDefaultValue ),
    theValue( right.theValue ),
    theSelectableList( right.theSelectableList )
{;}

TRunInformation::~TRunInformation()
{;}

const TRunInformation& TRunInformation::operator=( const TRunInformation& right )
{
  theInformationType = right.theInformationType;
  theItem = right.theItem;
  theDefaultValue = right.theDefaultValue;
  theValue = right.theValue;
  theSelectableList = right.theSelectableList;
  return *this;
}

Tbool TRunInformation::operator==( const TRunInformation& right ) const
{
  Tbool retval = Ttrue;
  retval &= ( theInformationType == right.theInformationType );
  retval &= ( theItem == right.theItem );
  retval &= ( theValue == right.theValue );
  return retval;
}

Tbool TRunInformation::operator!=( const TRunInformation& right ) const
{
  Tbool retval = Tfalse;
  retval |= ( theInformationType != right.theInformationType );
  retval |= ( theItem != right.theItem );
  retval |= ( theValue != right.theValue );
  return retval;
}

Tostream& operator<<( Tostream& tos, const TRunInformation& right )
{
  switch ( right.theInformationType ) {
    case tInfoFreeValue:
    case tInfoSelectableValue:
      tos << right.theItem << ": " << right.theValue << Tflush;
      break;
    case tInfoFreeText:
      tos << right.theItem << ", follow as:" << Tendl;
      tos << right.theValue << Tflush;
      break;
    case tInfoUnknown:
    default:
      tos << right.theItem << ": " << right.theValue << Tflush;
      break;
  }
  return tos;
}

TOutputHtmlFileStream& operator<<( TOutputHtmlFileStream& html, const TRunInformation& right )
{
  if ( html.IsOpen() ) {
    if ( !html.OpenTable() ) {
      html.OpenTable();
    }
    html << "<tr><td><b>" << right.theItem << "</b></td>" << Tflush;
    html << "<td>" << right.theValue << "</td></tr>" << Tendl;
    if ( !html.CloseTable() ) {
      html.CloseTable();
    }
  }
  return html;
}

Tvoid SetInformation( TRunInformation& info )
{
  switch ( info.theInformationType ) {
    case tInfoFreeValue:
      info.setFreeValue();
      break;
    case tInfoSelectableValue:
      info.setSelectableValue();
      break;
    case tInfoFreeText:
      info.setFreeText();
      break;
    case tInfoUnknown:
    default:
      info.setInformation();
      break;
  }
  return;
}

Tvoid TRunInformation::setFreeValue()
{
  static const Tsize_t bufflen = 1024;
  Tstring strbuf;
  Tchar linebuf[ bufflen ];

  Tbool validinput = Tfalse;
  while ( validinput == Tfalse ) {
    Tcout << theItem << " [" << theValue << "]: " << Tflush;
    Tcin.getline( linebuf, bufflen );
    strbuf = linebuf;

    if ( !strbuf.empty() ) {
      for ( Tsize_t i = 0; i < strbuf.size(); i ++ ) {
        if ( isprint( strbuf[ i ] ) == 0 ) {
          Tcerr << "TRunInformation::setFreeValue: invalid input." << Tendl;
          strbuf.erase();
          break;
        }
      }
      if ( !strbuf.empty() ) {
        theValue = strbuf;
        validinput = Ttrue;
      }
    } else {
      validinput = Ttrue;
    }
  }

  return;
}

Tvoid TRunInformation::setSelectableValue()
{
  if ( theSelectableList.empty() ) {
    Tcerr << "TRunInformation::setSelectableValue: list is empty." << Tendl;
    theInformationType = tInfoFreeValue;
    setFreeValue();
    return;
  }

  Tcout << theItem << " [" << theValue << "]:" << Tendl;
  for ( Tsize_t i = 0; i < theSelectableList.size(); i ++ ) {
    Tcout.setf( Tios::right );
    Tcout << setw( 6 ) << i + 1 << ". " << theSelectableList[ i ] << Tendl;
    Tcout.unsetf( Tios::right );
  }

  Tbool validinput = Tfalse;
  while ( validinput == Tfalse ) {
    Tcout << "Select: " << Tflush;
    Tchar cbuf;
    Tstring strbuf;
    while ( Tcin.get( cbuf ).gcount() == 1 && !Tcin.fail() && cbuf != '\n' ) {
      strbuf += cbuf;
    }
    if ( strbuf.empty() ) {
      // 空だったら直前の値を使う
      validinput = Ttrue;
    } else {
      Tbool validdigit = Ttrue;
      //全入力が数字かどうかチェック
      for ( Tsize_t i = 0; i < strbuf.size(); i ++ ) {
        if ( isdigit( strbuf[ i ] ) == 0 ) {
          //数字以外を含めばやりなおし
          Tcerr << "enable key: 1 to " << theSelectableList.size() << Tendl;
          validdigit = Tfalse;
          break;
        }
      }
      if ( validdigit ) {
        Tint input = strtol( strbuf.c_str(), 0, 0 ) - 1;
        if ( input >= 0 && input < (Tint)theSelectableList.size() ) {
          //全て数字でリストの範囲内なら
          theValue = theSelectableList[ input ];
          validinput = Ttrue;
        } else {
          //全て数字でリストの範囲外なら
          Tcerr << "enable key: 1 to " << theSelectableList.size() << Tendl;
          validdigit = Tfalse;
        }
      }
    }
  }
  return;
}

Tvoid TRunInformation::setFreeText()
{
  static const Tstring terminater = "\n.\n";
  static const Tsize_t termlen = terminater.size();
  static const Tstring emp = ".\n";
  static const Tsize_t emplen = emp.size();

  Tcout << theItem << " ('.' to escape, like as SMTP):" << Tendl;
  Tstring text;
  Tchar cbuf;

  /*
  struct termios tiosbuf;
  struct termios tiosorg;
  tcgetattr( 0, &tiosorg );
  tiosbuf = tiosorg;
  tiosbuf.c_iflag |= IGNBRK;
  tiosbuf.c_iflag |= IGNPAR;
  tiosbuf.c_lflag &= ~ICANON;
  tiosbuf.c_lflag |= ECHO;
  tiosbuf.c_lflag |= ISIG;
  tiosbuf.c_cc[ VMIN ] = 1;
  tiosbuf.c_cc[ VTIME ] = 0;
  tcsetattr( 0, TCSANOW, &tiosbuf );
  */

  while ( Tcin.read( &cbuf, 1 ).gcount() == 1 && !Tcin.fail() ) {
    if ( isprint( cbuf ) != 0 || isspace( cbuf ) != 0 ) {
      text += cbuf;
    }

    if ( text.size() >= termlen && text.substr( text.size() - termlen, termlen ) == terminater ) {
      //ラスト3文字が 改行,.,改行なら終了
      text.erase( text.size() - termlen, termlen );
      theValue = text;
      break;
    } else if ( text.size() == emplen && text == emp ) {
      //.,改行 としか打たれなければ終了
      break;
    } else if ( text.size() == 1 && text[ 0 ] == '\n' ) {
      //いきなり改行が打たれれば終了
      break;
    }
  }

  //tcsetattr( 0, TCSANOW, &tiosorg );
  return;
}

Tvoid TRunInformation::setInformation()
{
  Tcout << "TRunInformation::setInformation: not implemented." << Tendl;
  return;
}

Tvoid TRunInformation::Clear()
{
  theValue = theDefaultValue;
  return;
}

#ifdef __CLDAQ_ROOT_DLL
    ClassImp(TRunInformation)
#endif
