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


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

#include "diapatrn.hh"
#include "StrPrintf.hh"

#define POWERRATEGREAT 0.2
#define TIMERATEGREAT 0.03
#define POWERRATEMEDIUM 0.1
#define TIMERATEMEDIUM 0.01
#define POWERRATELEAST 0.04	// setbuf 用フラグ
#define TIMERATELEAST 0.005	// setbuf 用フラグ

//#define DEBUG



// ダイヤパターンデータ部分の読み込み
int
diapattern :: readfile
( FILE * diapatrn ,
  char * n_file )
{
  bool ct , ph , nc , pc , ts ;
  ct = ph = nc = pc = ts = false ;
  double sda , sdb , sdd , sde ;
  car_stat sst ;
  int sia ;

  // 最初のコマンド nextsta の処理
  getcommandvalue ( diapatrn , n_file , NEXTSTA ) ;
  getint ( diapatrn , n_file , sia ) ;	    // nextsta object の数
  l_ofs << StrPrintf ( "number of nextsta objects = %i" , sia ) << endl ;
  for ( int i = 0 ; i < sia ; ++ i )
  {
    nextsta * x = new nextsta ;
    if ( ! x )
    {
      cerr << "Error: could allocate memory for nextsta" << endl ;
      exit ( 1 ) ;
    }
    np_push_back ( x ) ;
  }

  if ( ! p_xml )
  {
    l_ofs << "P_xml false; traindata command not allowed in N file" << endl ;
  }
  else
  {
    l_ofs << "P_xml true, so traindata command allowed in N file" << endl ;
  }

  while ( ! ( ct && ph && nc && pc && ts ) )
  {
    commandvalue comval = getcommandvalue ( diapatrn , n_file ) ;
    switch ( comval )
    {

    case CYCLETIME :
      err_eof ( ct , n_file ) ;
      getdouble ( diapatrn , n_file , twhole ) ;
      l_ofs << StrPrintf ( "run time per cycle = %.2f" , twhole ) << endl ;
      break ;

    case PHASE :
      err_eof ( ph , n_file ) ;
      getdouble ( diapatrn , n_file , phase ) ;
      l_ofs << StrPrintf ( "phase = %.2f" , phase ) << endl ;
      break ;

    case CARS :
      err_eof ( nc , n_file ) ;
      if ( p_xml )
      {
        getcommand ( diapatrn , n_file ) ;
        train_type_key = string ( tmpch ) ;
      }
      getint ( diapatrn , n_file , cars ) ;
      l_ofs << StrPrintf ( "number of cars = %i" , cars ) ;
      if ( p_xml )
      {
        l_ofs << ", car type = " << train_type_key ;
      }
      l_ofs << endl ;
      break ;

    case PATTERNCIRC :
      err_eof ( pc , n_file ) ;
      getint ( diapatrn , n_file , dptm ) ;
      l_ofs << StrPrintf ( "pattern circulation = %i", dptm ) << endl ;
      break ;

    case TRAINVAR :
      err_eof ( ts , n_file ) ;
      gettwodbls ( diapatrn , n_file , sda , sdb ) ;
      if ( getcommand ( diapatrn ) == EOF )
      {
        return EOF ;
      }
      static char tcx [ TMPCHSIZ ] ;
      strcpy ( tcx , tmpch ) ;
      if ( strcmp ( tmpch , "Power" ) == 0 )
      {
        sst = Power ;
      }
      else if ( strcmp ( tmpch , "0" ) == 0 )
      {
        sst = Power ;
        strcpy ( tcx , "Power" ) ;		    // ←表示用文字列の関係
      }
      else if ( strcmp ( tmpch , "Brake" ) == 0 )
      {
        sst = Brake ;
      }
      else if ( strcmp ( tmpch , "1" ) == 0 )
      {
        sst = Brake ;
        strcpy ( tcx , "Brake" ) ;
      }
      else if ( strcmp ( tmpch , "Coast" ) == 0 )
      {
        sst = Coast ;
      }
      else if ( strcmp ( tmpch , "2" ) == 0 )
      {
        sst = Coast ;
        strcpy ( tcx , "Coast" ) ;
      }
      else if ( strcmp ( tmpch , "Stn_stop" ) == 0 )
      {
        sst = Stn_stop ;
      }
      else if ( strcmp ( tmpch , "3" ) == 0 )
      {
        sst = Stn_stop ;
        strcpy ( tcx , "Stn_stop" ) ;
      }
      else if ( strcmp ( tmpch , "Const_vel" ) == 0 )
      {
        sst = Const_vel ;
      }
      else if ( strcmp ( tmpch , "4" ) == 0 )
      {
        sst = Const_vel ;
        strcpy ( tcx , "Const_vel" ) ;
      }
      else if ( strcmp ( tmpch , "Regenerate" ) == 0 )
      {
        sst = Regenerate ;
      }
      else if ( strcmp ( tmpch , "5" ) == 0 )
      {
        sst = Regenerate ;
        strcpy ( tcx , "Regenerate" ) ;
      }
      else if ( strcmp ( tmpch , "Between_stop" ) == 0 )
      {
        sst = Between_stop ;
      }
      else if ( strcmp ( tmpch , "6" ) == 0 )
      {
        sst = Between_stop ;
        strcpy ( tcx , "Between_stop" ) ;
      }
      else
      {
        return EOF ;
        sst = Power ;	// Warning を避ける
      }
      if ( g_sw_specify_tdept )
      {
        getdouble ( diapatrn , n_file , sde ) ;
      }
      getdouble ( diapatrn , n_file , sdd ) ;
      if ( g_sw_specify_tdept )
      {
        l_ofs << StrPrintf ( "train setvar = %.3f %.3f %s(%d) %.3f %.3f" ,
                             sda , sdb , tcx , sst , sdd , sde ) << endl ;
      }
      else
      {
        l_ofs << StrPrintf ( "train setvar = %.3f %.3f %s(%d) %.3f" ,
                             sda , sdb , tcx , sst , sdd ) << endl ;
      }
      settrain ( sda , sdb , sst , sdd ) ;
      if ( g_sw_specify_tdept )
      {
        settdept ( sde ) ;
      }
      break ;

    default :
      err_eof ( n_file ) ;
    }
  }

  setnxx () ;
  nextnxx () ;
  double twholex = 0 ;			// データチェック: twhole 計算
  for ( np_iterator j = np_begin () ; j < np_end () ; ++ j )
  {
    // nextsta 諸定数読込み
    if ( ( * j ) -> readfile ( diapatrn , n_file ) == EOF )
    {
      return EOF ;
    }
    if ( ! ( * j ) -> isnextswitch () )
    {
      // **** nextnxx が指定されていない場合だけ計算 ****
      // changed 1997.10.6 to work around bug in checking twhole
      twholex += ( * j ) -> tarrive () ;
      l_ofs << StrPrintf ( "twhole(arrive): %10.4f" , twholex ) << endl ;
      twholex += ( * j ) -> stoptime () ;
      l_ofs << StrPrintf ( "twhole(start):  %10.4f" , twholex ) << endl ;
    }
  }
  if ( fabs ( twholex - twhole ) > INVLIM )
  {
    l_ofs << StrPrintf ( "Diagram pattern %d: different twhole" , ndpt )
          << endl ;
    err_eof ( n_file ) ;
  }
  realphase_cal () ;	// phase を時間に「足し合わせられる」ものにする
  return 1 ;
}



// ----
// Reading train schedule pattern data --- XML N file.
// Returns true if successful.
// ダイヤパターンデータ部分の読み込み, XML版. 成功すれば true を返す.
// ----
bool
diapattern :: readfile_xml
( TiXmlNode const * _in )
{
  bool ct , ph , nc , pc , _sw_tcp , _sw_tcv , _sw_tcs , _sw_tcx ;
  ct = ph = nc = pc = _sw_tcp = _sw_tcv = _sw_tcs = _sw_tcx = false ;
  bool _sw_tcd = ! g_sw_specify_tdept ;
  double sda , sdb , sdd , sde ;
  car_stat sst = Power ;

  bool _sw_tc = ! p_xml ;
  if ( ! p_xml )
  {
    l_ofs << "P_xml false; train_class atribute not allowed in N file"
          << endl ;
  }
  else
  {
    l_ofs << "P_xml true; train_class attribute allowed in N file" << endl ;
  }

  // ----
  // Count the number of <nextsta> child tags under tag <pattern> (_in).
  // <pattern> タグ (_in) の子タグ <nextsta> の数を数える.
  // ----
  np_size_type _i_nx = 0 ;
  for ( TiXmlNode const * _in_c = _in -> FirstChild () ;
        _in_c ; _in_c = _in_c -> NextSibling () )
  {
    // -----
    // Ignore non-Element node.
    // エレメント以外は無視。
    // -----
    if ( _in_c -> Type () != TiXmlNode :: TINYXML_ELEMENT )
    {
      continue ;
    }

    // -----
    // Check if _in_c is of tag <nextsta>.
    // _in_c が <nextsta> タグか調べる。
    // -----
    if ( _in_c -> ValueStr () == "nextsta" )
    {
      ++ _i_nx ;
    }
  }

  l_ofs << "number of nextsta objects = " << _i_nx << endl ;
  for ( nextsta :: gc_size_type i = 0 ; i < _i_nx ; ++ i )
  {
    nextsta * x = new nextsta ;
    if ( ! x )
    {
      cerr << "Error: could allocate memory for nextsta" << endl ;
      exit ( 1 ) ;
    }
    if ( ! x )
    {
      cerr << "Error parsing <pattern> tag in N file:" << endl
           << "  Could not allocate memory for an nextsta object." << endl ;
      exit ( 1 ) ;
    }
    np_push_back ( x ) ;
  }

  // ----
  // Reading attributes of tag <pattern> (_in).
  // <pattern> タグ (_in) の属性を読み込む。
  // ----
  for ( TiXmlAttribute const * _in_a = _in -> ToElement ()
          -> FirstAttribute () ; _in_a ; _in_a = _in_a -> Next () )
  {
    string _atn = string ( _in_a -> Name () ) ;
    string _atv = string ( _in_a -> Value () ) ;

    if ( _atn == "cycletime" )
    {
      // Attribute "cycletime"
      if ( ct )
      {
        cerr << "Error parsing <pattern> tag in N file:" << endl
             << "  Duplicate attribute \"cycletime\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%lf", & twhole ) ;
      l_ofs << StrPrintf ( "run time per cycle = %.2f" , twhole ) << endl ;
      ct = true ;
    }
    else if ( _atn == "phase" )
    {
      // Attribute "phase"
      if ( ph )
      {
        cerr << "Error parsing <pattern> tag in N file:" << endl
             << "  Duplicate attribute \"phase\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%lf", & phase ) ;
      l_ofs << StrPrintf ( "phase = %.2f" , phase ) << endl ;
      ph = true ;
    }
    else if ( _atn == "cars" )
    {
      // Attribute "cars"
      if ( nc )
      {
        cerr << "Error parsing <pattern> tag in N file:" << endl
             << "  Duplicate attribute \"cars\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%d", & cars ) ;
      l_ofs << StrPrintf ( "number of cars = %i" , cars ) << endl ;
      nc = true ;
    }
    else if ( _atn == "train_class" )
    {
      // Attribute "train_class"
      if ( _sw_tc )
      {
        cerr << "Error parsing <pattern> tag in N file:" << endl ;
        if ( p_xml )
        {
          cerr << "  Attribute \"train_class\" not allowed." << endl ;
        }
        else
        {
          cerr << "  Duplicate attribute \"train_class\"?" << endl ;
        }
        exit ( 1 ) ;
      }
      train_type_key = _atv ;
      l_ofs << "car type = " << train_type_key << endl ;
      _sw_tc = true ;
    }
    else if ( _atn == "patterncirc" )
    {
      // Attribute "patterncirc"
      if ( pc )
      {
        cerr << "Error parsing <pattern> tag in N file:" << endl
             << "  Duplicate attribute \"patterncirc\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%d", & dptm ) ;
      l_ofs << StrPrintf ( "pattern circulation = %i" , dptm ) << endl ;
      pc = true ;
    }
    else if ( _atn == "init_train_position" )
    {
      // Attribute "init_train_position"
      //  (formerly the first parameter of "trainvar")
      if ( _sw_tcp )
      {
        cerr << "Error parsing <pattern> tag in N file:" << endl
             << "  Duplicate attribute \"init_train_position\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%lf", & sda ) ;
      l_ofs << StrPrintf ( "initial train position = %10.4f" , sda ) << endl ;
      _sw_tcp = true ;
    }
    else if ( _atn == "init_train_velocity" )
    {
      // Attribute "init_train_velocity"
      //  (formerly the second parameter of "trainvar")
      if ( _sw_tcv )
      {
        cerr << "Error parsing <pattern> tag in N file:" << endl
             << "  Duplicate attribute \"init_train_velocity\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%lf", & sdb ) ;
      l_ofs << StrPrintf ( "initial train velocity = %8.2f" , sdb ) << endl ;
      _sw_tcv = true ;
    }
    else if ( _atn == "init_train_state" )
    {
      // Attribute "init_train_state"
      //  (formerly the third parameter of "trainvar")
      if ( _sw_tcs )
      {
        cerr << "Error parsing <pattern> tag in N file:" << endl
             << "  Duplicate attribute \"init_train_state\"?" << endl ;
        exit ( 1 ) ;
      }
      string tcx = _atv ;
      if ( _atv == "Power" || _atv == "0"
           || _atv == "power" || _atv == "POWER" )
      {
        sst = Power ;
        tcx = "Power" ;
      }
      else if ( _atv == "Brake" || _atv == "1"
                || _atv == "brake" || _atv == "BRAKE" )
      {
        sst = Brake ;
        tcx = "Brake" ;
      }
      else if ( _atv == "Coast" || _atv == "2"
                || _atv == "coast" || _atv == "COAST" )
      {
        sst = Coast ;
        tcx = "Coast" ;
      }
      else if ( _atv == "Stn_stop" || _atv == "3"
                || _atv == "stn_stop" || _atv == "STN_STOP" )
      {
        sst = Stn_stop ;
        tcx = "Stn_stop" ;
      }
      else if ( _atv == "Const_vel" || _atv == "4"
                || _atv == "const_vel" || _atv == "CONST_VEL" )
      {
        sst = Const_vel ;
        tcx = "Const_vel" ;
      }
      else if ( _atv == "Regenerate" || _atv == "5"
                || _atv == "regenerate" || _atv == "REGENERATE" )
      {
        sst = Regenerate ;
        tcx = "Regenerate" ;
      }
      else if ( _atv == "Between_stop" || _atv == "6"
                || _atv == "between_stop" || _atv == "BETWEEN_STOP" )
      {
        sst = Between_stop ;
        tcx = "Between_stop" ;
      }
      else
      {
        cerr << "Error parsing <pattern> tag in N file:" << endl
             << "  Attribute \"init_train_state\" with wrong value "
             << _atv << endl ;
        exit ( 1 ) ;
      }
      l_ofs << "initial train state = " << tcx << endl ;
      _sw_tcs = true ;
    }
    else if ( _atn == "init_train_departure_time" )
    {
      // Attribute "init_train_departure_time"
      //  (formerly the fourth parameter of "trainvar" when
      //  "initialdeparturetime" flag is set in <n_flag> tag)
      if ( _sw_tcd )
      {
        cerr << "Error parsing <pattern> tag in N file:" << endl ;
        if ( g_sw_specify_tdept )
        {
          cerr << "  Attribute \"initial_train_departure_time\" not allowed."
               << endl ;
        }
        else
        {
          cerr << "  Duplicate attribute \"initial_train_departure_time\"?"
               << endl ;
        }
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%lf", & sde ) ;
      l_ofs << StrPrintf ( "initial train departure time = %10.3f" , sde )
            << endl ;
      _sw_tcd = true ;
    }
    else if ( _atn == "init_train_delay" )
    {
      // Attribute "init_train_delay"
      //  (formerly the last parameter of "trainvar")
      if ( _sw_tcx )
      {
        cerr << "Error parsing <pattern> tag in N file:" << endl
             << "  Duplicate attribute \"init_train_delay\"?" << endl ;
        exit ( 1 ) ;
      }
      sscanf ( _atv . c_str () , "%lf", & sdd ) ;
      l_ofs << StrPrintf ( "initial train delay = %10.3f" , sdd ) << endl ;
      _sw_tcx = true ;
    }
    else
    {
      cerr << "Error parsing <pattern> tag in N file:" << endl
           << "  Attribute \"" << _atn << "\" not allowed." << endl ;
      exit ( 1 ) ;
    }
  }
  if ( ! ( ct && ph && nc && pc && _sw_tc && _sw_tcp && _sw_tcv
           && _sw_tcs && _sw_tcx && _sw_tcd ) )
  {
    cerr << "Error parsing <pattern> tag in N file:" << endl
         << "  Required attribute(s) missing." << endl ;
    exit ( 1 ) ;
  }
  settrain ( sda , sdb , sst , sdd ) ;
  if ( g_sw_specify_tdept )
  {
    settdept ( sde ) ;
  }

  setnxx () ;
  nextnxx () ;

  // ----
  // Creating an nextsta instance using child tag <nextsta> under <pattern>.
  // nextsta インスタンスを <pattern> の子タグ <nextsta> を用い作成.
  // ----
  _i_nx = 0 ;
  double twholex = 0 ;
  for ( TiXmlNode const * _cn = _in -> FirstChild () ; _cn ;
        _cn = _cn -> NextSibling () )
  {
    // -----
    // Ignore non-Element node.
    // エレメント以外は無視。
    // -----
    if ( _cn -> Type () != TiXmlNode :: TINYXML_ELEMENT )
    {
      continue ;
    }

    // -----
    // Check if _in_c is of tag <nextsta>.
    // _in_c が <nextsta> タグか調べる。
    // -----
    if ( _cn -> ValueStr () == "nextsta" )
    {
      ++ _i_nx ;
    }
    else
    {
      cerr << "Error parsing <pattern> tag in N file:" << endl
           << "  Child tag \"" << _cn -> ValueStr () << "\" not allowed."
           << endl ;
      exit ( 1 ) ;
    }

    // -----
    // Pass the found element node to constructor of nextsta object.
    // 見つかったエレメントノードを nextsta のコンストラクタに渡す。
    // -----
    nextsta * x = getElement ( _i_nx - 1 ) ;
    if ( ! x )
    {
      cerr << "Error parsing <pattern> tag in N file:" << endl
           << "  Null pointer found in twhole check." << endl ;
      exit ( 1 ) ;
    }
    if ( ! x -> readfile_xml ( _cn ) )
    {
      cerr << "Error parsing <pattern> tag in N file:" << endl
           << "  File read error." << endl ;
      exit ( 1 ) ;
    }

    // ----
    // Data check: calculating "twhole"
    // データチェック: twhole 計算
    // ----

    if ( ! x -> isnextswitch () )
    {
      // **** nextnxx が指定されていない場合だけ計算 ****
      // changed 1997.10.6 to work around bug in checking twhole
      twholex += x -> tarrive () ;
      l_ofs << StrPrintf ( "twhole(arrive): %10.4f" , twholex ) << endl ;
      twholex += x -> stoptime () ;
      l_ofs << StrPrintf ( "twhole(start):  %10.4f" , twholex ) << endl ;
    }
  }

  if ( fabs ( twholex - twhole ) > INVLIM )
  {
    cerr << "Error parsing <pattern> tag in N file:" << endl
         << "  Cycletime check error." << endl ;
    exit ( 1 ) ;
  }

  realphase_cal () ;	// phase を時間に「足し合わせられる」ものにする
  return true ;
}
