// This may look like C code, but it is really -*- C++ -*-
// RTSS --- Railway Total System Simulator
// (c) TAKAGI Ryo (at Kogakuin University)
// nxx_rf.cc --- readfile function for class nextsta
// -----
// ChangeLog:
// 2007. 11. 21
//  Redirected log messages to l_file.
// -----

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>

#include "matrix.hh"
#include "enumerat.hh"
#include "nextsta.hh"
#include "StrPrintf.hh"

//#define DEBUG



// ファイルリード
int
nextsta :: readfile
( FILE * diapatrn ,
  char * n_file )
{

  // ファイルリード確認用変数の宣言と初期化
  // "isnextsw" member variable added 1997.10.6 to work around bug in
  // checking of twhole in dpt-rf.cc. remove variable "nx". isnextsw
  // used in place of nx. --- RT
  bool sp , ep , ev , st , sta , nof , dr , nf , np , gv , /* nx , */ ncg ;
  bool sw_nstnobj ;
  isnextsw = sp = ep = ev = st = sta = nof = dr = nf = np = gv = ncg
    = sw_nstnobj = false ;

  if ( ! g_sw_conges_station )
  {
    // conges_station がセットされていない場合
    // congestion コマンドは N file に入っていてはいけない
    ncg = true ;
  }

  if ( ! g_sw_station_object_valid )
  {
    // station_object_valid がセットされていない場合
    // station_object_number コマンドは N file に入っていてはいけない
    sw_nstnobj = true ;
  }

  //     nocp = true ;
  int kz ;
  //    char c = 'x' ;

  while ( ( ! ( sp && ep && ev && st && sta && nof && dr
		&& nf && np && gv && ncg && sw_nstnobj ) ) )
  {

    commandvalue comval = getcommandvalue ( diapatrn , n_file ) ;

    int ii ;
    switch ( comval )
    {
    case STARTPOINT:
      // 開始地点
      err_eof ( sp , n_file ) ;
      getdouble ( diapatrn , n_file , startp ) ;
      l_ofs << StrPrintf ( "startpoint %.3f" , startp ) << endl ;
      break ;

    case ENDPOINT:
      // 終了地点
      err_eof ( ep , n_file ) ;
      getdouble ( diapatrn , n_file , arp ) ;
      l_ofs << StrPrintf ( "endpoint %.3f" , arp ) << endl ;
      break ;

    case ENDVELOCITY:
      // 次駅データ終了地点での速度
      err_eof ( ev , n_file ) ;
      getdouble ( diapatrn , n_file , arv ) ;
      l_ofs << StrPrintf ( "endvelocity %.3f" , arv ) << endl ;
      break ;

    case NEXTNXX:
      // 次データ移行点
      err_eof ( isnextsw , n_file ) ;
      getdouble ( diapatrn , n_file , nextsw ) ;
      l_ofs << StrPrintf ( "nextnxx point %.3f" , nextsw ) << endl ;
      break ;

    case STATION_OBJECT_NUMBER:
      // 対応する駅オブジェクト番号
      err_eof ( sw_nstnobj , n_file ) ;
      getint ( diapatrn , n_file , n_stnobj ) ;
      l_ofs << "station object number: " << n_stnobj << endl ;
      break ;

    case STARTSTOPTIME:
      // 駅間走行時分
      err_eof ( st , n_file ) ;
      getdouble ( diapatrn , n_file , art ) ;
      art -= startstop_parameter ;		// 感度解析用変数(通常0) -
      l_ofs << StrPrintf ( "start-to-stop time %.3f" , art ) << endl ;
      break ;

    case STATIONSTOP:
      // 駅停車時間
      err_eof ( sta , n_file ) ;
      getdouble ( diapatrn , n_file , tstop ) ;
      tstop += startstop_parameter ;	// 感度解析用変数(通常0) +
      l_ofs << StrPrintf ( "station stop time %.3f" , tstop ) << endl ;
      break ;

    case NOTCHOFF:
      // ノッチオフ速度
      err_eof ( nof , n_file ) ;
      getdouble ( diapatrn , n_file , vnoff ) ;
      l_ofs << StrPrintf ( "notchoff velocity %.3f" , vnoff ) << endl ;
      break ;

    case DIREC:
      // 列車進行方向（下り = 1）
      err_eof ( dr , n_file ) ;
      getint ( diapatrn , n_file , direc ) ;
      l_ofs << StrPrintf ( "direction %i" , direc ) << endl ;
      break ;

    case NFLINE:
      // 饋電線番号
      err_eof ( nf , n_file ) ;
      getint ( diapatrn , n_file , nfline ) ;
      l_ofs << StrPrintf ( "feedline No.%i" , nfline ) << endl ;
      break ;

    case CONGESTION:
      // 当該区間での列車混雑率
      if ( ncg || ( ! g_sw_conges_station ) )
	err_eof ( n_file ) ;
      getdouble ( diapatrn , n_file , conges ) ;
      l_ofs << StrPrintf ( "congestion rate %7.4f" , conges ) << endl ;
      ncg = true ;
      break ;

    case NEXTSTA_PATTERN:
      // 次駅データのタイプ
      err_eof ( np , n_file ) ;
      getcommand ( diapatrn , n_file ) ;
      if ( cmpcommand ( "Station_pass" ) )
	nxp = Station_pass ;
      else if ( cmpcommand ( "Station" ) )
	nxp = Station ;
      else if ( cmpcommand ( "Pass_station" ) )
	nxp = Pass_station ;
      else if ( cmpcommand ( "Pass_pass" ) )
	nxp = Pass_pass ;
      else
	err_eof ( n_file ) ;
      l_ofs << StrPrintf ( "nextsta_pattern %s" , tmpch ) << endl ;
      // if ( nxp != Station )
      //   ontprec = true ;
      if ( g_sw_ont_prec )
	ontprec = true ;	// フラグを見る
      break ;

    case GRADCRVNUMBER:
      // gradcrv コマンドの数
      err_eof ( gv , n_file ) ;
      getint ( diapatrn , n_file , kz ) ;
      gc_size_type kx ;
      int kw ;
      double ku ;
      greq_gnum . clear () ;
      greq_gnum . reserve ( kz ) ;
      greq_renposf . clear () ;
      greq_renposf . reserve ( kz ) ;
      greq_gzpos . clear () ;
      greq_gzpos . reserve ( kz ) ;

      for ( ii = 0 ; ii < kz ; ++ ii )
      {
	// コマンド gradcrv(gradcrv 配列の番号)の読み込み
	getcommandvalue ( diapatrn , n_file , GRADCRV ) ;
        int i_kx ;
	gettwoints ( diapatrn , n_file , i_kx , kw ) ;
	l_ofs << StrPrintf ( "gradcrv %i %i" , i_kx , kw ) << endl ;
	if ( i_kx < 0 )
	  return EOF ;
	if ( kw != 0 )
	{
	  getdouble ( diapatrn , n_file , ku ) ;
	}
	else
	{
	  ku = 0.0 ;
	}
        kx = gc_size_type ( i_kx ) ;
	greq_gnum . push_back ( kx ) ;
	greq_renposf . push_back ( kw ) ;
	greq_gzpos . push_back ( ku ) ;
      }
      break ;

    default:
      err_eof ( n_file ) ;
    }
  }

  if ( ! isnextsw )
  {
    nextsw = arp + double ( direc ) ;
  }
  if ( ! ( direc == 1 || direc == - 1 ) )
  {
    return EOF ;
  }
  return 1 ;
}



// ----
// XML file reading. Programmed as constructor.
// XML ファイル読み込み. コンストラクタとして実装.
// ----
bool
nextsta :: readfile_xml
( TiXmlNode const * _in )
{
  // "isnextsw" member variable added 1997.10.6 to work around bug in
  // checking of twhole in dpt-rf.cc. Remove variable "nx". isnextsw
  // used in place of nx. --- RT
  bool sp , ep , ev , st , sta , nof , dr , nf , np ;
  sp = ep = ev = st = sta = nof = dr = nf = np = false ;

  // ----
  // congestion attribute not allowed when conges_station = false.
  // conges_station = false なら congestion 属性使用不可.
  // ----
  bool ncg = ! g_sw_conges_station ;

  // ----
  // station_object_number not allowed when station_object_valid = false.
  // station_object_valid = false なら station_object_number 属性使用不可.
  // ----
  bool sw_nstnobj = ! g_sw_station_object_valid ;

  // ----
  // Flag for SOC curve data.
  // SOCカーブデータ用フラグ。
  // ----
  _wants_soc = false ;

  // ----
  // The given TiXmlNode must be of tag <nextsta>.
  // 与えられた TiXmlNode は <nextsta> タグでなければならない。
  // ----
  string _tn_in = _in -> ValueStr () ;
  if ( _tn_in != "nextsta" )
  {
    cerr << "Error parsing N file:" << endl
         << "  Tag " << _tn_in << " wrongly given to nextsta constructor"
         << endl ;
    exit ( 1 ) ;
  }

  // ----
  // All former "N commands" related to nextsta objects are now attributes
  // of <nextsta>, except gradcrvnumber and gradcrv.
  // 旧形式ファイルの N コマンドのうち nextsta オブジェクトに関係するものは
  // すべて <nextsta> タグの属性とした。例外: gradcrvnumber, gradcrv.
  // ----
  for ( TiXmlAttribute const * _att = _in -> ToElement ()
          -> FirstAttribute () ; _att ; _att = _att -> Next () )
  {
    string _atn = string ( _att -> Name () ) ;
    string _atv = string ( _att -> Value () ) ;
    if ( _atn == "start_point" )
    {
      // Attribute "start_point" (formerly startpoint)
      if ( sp )
      {
        cerr << "Error parsing <nextsta> tag in N file:" << endl
             << "  Duplicate attribute \"start_point\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%lf", & startp ) ;
      l_ofs << StrPrintf ( "startpoint %.3f" , startp ) << endl ;
      sp = true ;
    }
    else if ( _atn == "end_point" )
    {
      // Attribute "end_point" (formerly endpoint)
      if ( ep )
      {
        cerr << "Error parsing <nextsta> tag in N file:" << endl
             << "  Duplicate attribute \"end_point\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%lf", & arp ) ;
      l_ofs << StrPrintf ( "endpoint %.3f" , arp ) << endl ;
      ep = true ;
    }
    else if ( _atn == "end_velocity" )
    {
      // Attribute "end_velocity" (formerly endvelocity)
      if ( ev )
      {
        cerr << "Error parsing <nextsta> tag in N file:" << endl
             << "  Duplicate attribute \"end_velocity\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%lf", & arv ) ;
      l_ofs << StrPrintf ( "endvelocity %.3f" , arv ) << endl ;
      ev = true ;
    }
    else if ( _atn == "nextsta_switch_point" )
    {
      // Attribute "nextsta_switch_point" (formerly nextnxx)
      if ( isnextsw )
      {
        cerr << "Error parsing <nextsta> tag in N file:" << endl
             << "  Duplicate attribute \"nextsta_switch_point\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%lf", & nextsw ) ;
      l_ofs << StrPrintf ( "nextnxx point %.3f" , nextsw ) << endl ;
      isnextsw = true ;
    }
    else if ( _atn == "station_object_number" )
    {
      // Attribute "station_object_number"
      if ( sw_nstnobj )
      {
        cerr << "Error parsing <nextsta> tag in N file:" << endl ;
        if ( g_sw_station_object_valid )
        {
          cerr << "  Duplicate attribute \"station_object_number\"?" ;
        }
        else
        {
          cerr << "  Attribute \"station_object_number\" not allowed" ;
        }
        cerr << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%d", & n_stnobj ) ;
      l_ofs << "station object number: " << n_stnobj << endl ;
      sw_nstnobj = true ;
    }
    else if ( _atn == "start_stop_time" )
    {
      // Attribute "start_stop_time" (formerly startstoptime)
      if ( st )
      {
        cerr << "Error parsing <nextsta> tag in N file:" << endl
             << "  Duplicate attribute \"start_stop_time\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%lf", & art ) ;
      l_ofs << StrPrintf ( "start-to-stop time %.3f" , art ) << endl ;
      st = true ;
    }
    else if ( _atn == "dwell_time" )
    {
      // Attribute "dwell_time" (formerly stationstop)
      if ( sta )
      {
        cerr << "Error parsing <nextsta> tag in N file:" << endl
             << "  Duplicate attribute \"dwell_time\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%lf", & tstop ) ;
      tstop += startstop_parameter ;	// 感度解析用変数(通常0) +
      l_ofs << StrPrintf ( "dwell time %.3f" , tstop ) << endl ;
      sta = true ;
    }
    else if ( _atn == "notch_off_velocity" )
    {
      // Attribute "notch_off_velocity" (formerly notchoff)
      if ( nof )
      {
        cerr << "Error parsing <nextsta> tag in N file:" << endl
             << "  Duplicate attribute \"notch_off_velocity\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%lf", & vnoff ) ;
      l_ofs << StrPrintf ( "notchoff velocity %.3f" , vnoff ) << endl ;
      nof = true ;
    }
    else if ( _atn == "direction" )
    {
      // Attribute "direction" (formerly direc)
      if ( dr )
      {
        cerr << "Error parsing <nextsta> tag in N file:" << endl
             << "  Duplicate attribute \"direction\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%d", & direc ) ;
      l_ofs << "direction " << direc << endl ;
      if ( ! ( direc == 1 || direc == - 1 ) )
      {
        cerr << "Error parsing <nextsta> tag in N file:" << endl
             << "  Direction value not correct." << endl ;
        exit ( 1 ) ;
      }
      dr = true ;
    }
    else if ( _atn == "feeder_number" )
    {
      // Attribute "feeder_number" (formerly nfline)
      if ( nf )
      {
        cerr << "Error parsing <nextsta> tag in N file:" << endl
             << "  Duplicate attribute \"feeder_number\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%d", & nfline ) ;
      l_ofs << "feedline No." << nfline << endl ;
      nf = true ;
    }
    else if ( _atn == "congestion" )
    {
      // Attribute "congestion"
      if ( ncg )
      {
        cerr << "Error parsing <nextsta> tag in N file:" << endl ;
        if ( g_sw_conges_station )
        {
          cerr << "  Duplicate attribute \"congestion\"?" << endl ;
        }
        else
        {
          cerr << "  Attribute \"congestion\" not allowed" << endl ;
        }
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%lf", & conges ) ;
      l_ofs << StrPrintf ( "congestion rate %7.4f" , conges ) << endl ;
      ncg = true ;
    }
    else if ( _atn == "nextsta_pattern" )
    {
      // Attribute "nextsta_pattern"
      if ( np )
      {
        cerr << "Error parsing <nextsta> tag in N file:" << endl
             << "  Duplicate attribute \"nextsta_pattern\"?" << endl ;
        exit ( 1 ) ;
      }
      if ( _atv == "Station_pass" )
      {
        nxp = Station_pass ;
      }
      else if ( _atv == "Station" )
      {
        nxp = Station ;
      }
      else if ( _atv == "Pass_station" )
      {
        nxp = Pass_station ;
      }
      else if ( _atv == "Pass_pass" )
      {
        nxp = Pass_pass ;
      }
      else
      {
        cerr << "Error parsing <nextsta> tag in N file:" << endl
             << "  Attribute \"nextsta_pattern\" with wrong value"
             << _atv << endl ;
        exit ( 1 ) ;
      }
      l_ofs << "nextsta_pattern " << _atv << endl ;
      np = true ;
      // if ( nxp != Station )
      //   ontprec = true ;
      if ( g_sw_ont_prec )
 	ontprec = true ;	// フラグを見る
    }
    else if ( _atn == "soc_feedforward_data" )
    {
      // Attribute "soc_feedforward_data"
      if ( _wants_soc )
      {
        cerr << "Error parsing <nextsta> tag in N file:" << endl
             << "  Duplicate attribute \"soc_feedforward_data\"?" << endl ;
        exit ( 1 ) ;
      }
      _soc_name = _atv ;
      l_ofs << "SOC curve data name: " << _soc_name << endl ;
      _wants_soc = true ;
    }
    else
    {
      cerr << "Error parsing <nextsta> tag in N file:" << endl
           << "  Wrong attribute \"" << _atv << "\" given." << endl ;
      exit ( 1 ) ;
    }
  }
  if ( ! ( sp && ep && ev && st && sta && nof && dr && nf && np
           && ncg && sw_nstnobj ) )
  {
    cerr << "Error parsing <nextsta> tag in N file:" << endl
         << "  Some required attribute(s) missing." << endl ;
    exit ( 1 ) ;
  }

  // ----
  // <nextsta> will have one or more child tag(s) of <gradcrv>.
  // <nextsta> タグは1つまたはそれ以上の <gradcrv> 子タグを持つ。
  // ----
  bool _sw_gv = false ;
  for ( TiXmlNode const * _c_in = _in -> FirstChild () ;
        _c_in ; _c_in = _c_in -> NextSibling () )
  {
    // -----
    // Ignore non-Element node.
    // エレメント以外は無視。
    // -----
    if ( _c_in -> Type () != TiXmlNode :: TINYXML_ELEMENT )
    {
      continue ;
    }

    // ----
    // _c_in must be of tag <gradcrv>.
    // _c_in は <gradcrv> タグでなければならない。
    // ----
    string _v_cin = _c_in -> ValueStr () ;
    if ( _v_cin != "gradcrv" )
    {
      cerr << "Error parsing <nextsta> tag in N file:" << endl << "  Tag \""
           << _v_cin << "\" cannot be a child of <nextsta>." << endl ;
      exit ( 1 ) ;
    }
    _sw_gv = true ;

    gc_size_type kx = 0 ;
    int kw = 0 ;
    double ku = 0.0 ;

    bool _sw_gc_n = false ;
    bool _sw_gc_r = false ;
    bool _sw_gc_o = false ;
    for ( TiXmlAttribute const * _atc = _c_in -> ToElement ()
            -> FirstAttribute () ; _atc ; _atc = _atc -> Next () )
    {
      string _atn = string ( _atc -> Name () ) ;
      string _atv = string ( _atc -> Value () ) ;
      if ( _atn == "number" )
      {
        // Attribute "number"
        if ( _sw_gc_n )
        {
          cerr << "Error parsing <gradcrv> tag in N file:" << endl
               << "  Duplicate attribute \"number\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%d", & kx ) ;
        _sw_gc_n = true ;
      }
      else if ( _atn == "rewrite" )
      {
        // Attribute "rewrite" -- defaults to "No" (kw = 0). 
        if ( _sw_gc_r )
        {
          cerr << "Error parsing <gradcrv> tag in N file:" << endl
               << "  Duplicate attribute \"rewrite\"?" << endl ;
          exit ( 1 ) ;
        }
        if ( _atv == "No" )
        {
          kw = 0 ;
        }
        else if ( _atv == "KeepOrder" )
        {
          kw = 1 ;
        }
        else if ( _atv == "ReverseOrder" )
        {
          kw = - 1 ;
        }
        _sw_gc_r = true ;
      }
      else if ( _atn == "new_origin" )
      {
        // Attribute "new_origin"
        if ( _sw_gc_o )
        {
          cerr << "Error parsing <gradcrv> tag in N file:" << endl
               << "  Duplicate attribute \"new_origin\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf", & ku ) ;
        _sw_gc_o = true ;
      }
      else
      {
        cerr << "Error parsing <gradcrv> tag in N file:" << endl
             << "  Wrong attribute \"" << _atn << "\" found." << endl ;
        exit ( 1 ) ;
      }
    }
    if ( ! _sw_gc_n )
    {
      cerr << "Error parsing <gradcrv> tag in N file:" << endl
           << "  Rquired attribute \"number\" not found." << endl ;
      exit ( 1 ) ;
    }
    l_ofs << StrPrintf ( "gradcrv %i %i" , kx , kw ) << endl ;
    greq_gnum . push_back ( kx ) ;
    greq_renposf . push_back ( kw ) ;
    greq_gzpos . push_back ( ku ) ;
  }
  if ( ! _sw_gv )
  {
    cerr << "Error parsing <nextsta> tag in N file:" << endl
         << "  Rquired child tag <gradcrv> not found." << endl ;
    exit ( 1 ) ;
  }

  if ( ! isnextsw )
  {
    nextsw = arp + double ( direc ) ;
  }

  return true ;
}
