// This may look like C code, but it is really -*- C++ -*-
// RTSS --- Railway Total System Simulator
// (c) TAKAGI Ryo (at Kogakuin University)
// rf_sfile.cc --- read data from the "S File" -- substation-related
// -----
// ChangeLog:
// 2007. 11. 21
//  Redirected log messages to l_file.
// 2007. 11. 10
//  Added function feeder :: rf_sxml_ctrl_a ( const TiXmlNode * const ).
//  This function reads the attributes for tag <substation_control_a> in the
//  new XML-formatted S file.
//  Added function feeder :: rf_sxml_substation ( const TiXmlNode * const ).
//  This function reads the tag <substation> in the new XML-formatted S file.
// 2007. 10. 19
//  Modified the #include's to ISO C++ style. Removed the old comment lines
//  that preserved the section reading "T File". I do not think it is useful
//  anymore, now that the very powerful PCs are available...
// -----

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

#include "kidenrt.hh"
#include "StrPrintf.hh"

using std :: cerr ;
using std :: endl ;
using std :: string ;

// Reading S File (substation related data)
void
feeder :: rf_sfile
()
{
  if ( s_xml )
  {
    // -----
    // Loading file.
    // ファイルロード。
    // -----
    string s_file_full_path = "" ;
    if ( is_backslash )
    {
      s_file_full_path += s_drive_str ;
    }
    s_file_full_path += s_dir_str ;
    if ( is_backslash )
    {
      s_file_full_path += "\\" ;
    }
    else
    {
      s_file_full_path += "/" ;
    }
    s_file_full_path += s_file_str ;
    TiXmlDocument s_doc ( s_file_full_path ) ;
    bool loadOkay = s_doc . LoadFile () ;
    if ( ! loadOkay )
    {
      cerr << "Failed to load file \"" << s_file_full_path << "\"." << endl ;
      exit ( 1 ) ;
    }

    // -----
    // The file must have one "root" element of tag <rtss_s_file>.
    // If multiple <rtss_s_file> tags exist, only the first one is read.
    // このXMLファイルには <rtss_s_file> というタグがなければならない。
    // <rtss_s_file> タグが複数あれば最初のだけを読む。
    // -----
    const TiXmlNode * s_doc_ch = s_doc . FirstChild () ;
    while ( s_doc_ch && s_doc_ch -> Type () != TiXmlNode :: TINYXML_ELEMENT )
    {
      s_doc_ch = s_doc_ch -> NextSibling () ;
    }
    if ( ! s_doc_ch
         || s_doc_ch -> Type () != TiXmlNode :: TINYXML_ELEMENT
         || string ( s_doc_ch -> Value () ) != "rtss_s_file" )
    {
      cerr << "Failed to find element \"rtss_s_file\"" << endl
           << " in file \"" << s_file_full_path << "\"." << endl ;
      exit ( 1 ) ;
    }

    // -----
    // Getting child element(s) of tag <rtss_s_file>.
    // Tags must appear in this order:-
    //  <substation_control_a>: Up to 1 appearance, can be omitted.
    //  <substation>: As many appearances as possible, cannot be omitted.
    // <rtss_s_file> の子を取得. 以下の順で現れる必要がある。
    //  <substation_control_a>: 1回まで。省略可。
    //  <substation>: 何回でも，省略不可。
    // -----
    bool has_substation_control_a_tag = false ;
    bool started_substation_tags = false ;
    for ( const TiXmlNode * s_doc_cc = s_doc_ch -> FirstChild () ;
          s_doc_cc ; s_doc_cc = s_doc_cc -> NextSibling () )
    {
      // -----
      // Ignore non-Element node.
      // エレメント以外は無視。
      // -----
      if ( s_doc_cc -> Type () != TiXmlNode :: TINYXML_ELEMENT )
        continue ;
      // -----
      // Check tag name.
      // タグ名チェック。
      // -----
      string sdcc_val = string ( s_doc_cc -> Value () ) ;
      if ( sdcc_val == "substation_control_a" )
      {
        // -----
        // Processing <substation_control_a> tag.
        // <substation_control_a> タグを処理.
        // -----
        if ( has_substation_control_a_tag )
        {
          cerr << "Error: \"" << sdcc_val
               << "\" tag not allowed multiple times." << endl ;
          exit ( 1 ) ;
        }
        g_sw_substn_ctl_a = true ;
        rf_sxml_ctrl_a ( s_doc_cc ) ;
        has_substation_control_a_tag = true ;
      }
      else if ( sdcc_val == "substation" )
      {
        // -----
        // Processing <substation> tag.
        // <substation> タグを処理.
        // -----
        rf_sxml_substation ( s_doc_cc ) ;
        started_substation_tags = true ;
      }
      else
      {
        cerr << "Error: \"" << sdcc_val << "\" tag not allowed." << endl ;
        exit ( 1 ) ;
      }
    }
    // -----
    // Set numbers
    // 番号関連のセット
    // -----
    ncss = nss + ncar ;
    for ( int i = 0 ; i < ncar ; ++ i )
    {
      vec_csd . push_back ( ( elecchar * ) & ( getCAR ( i ) ) ) ;

      // Substation/train serial number sent to each train object instance.
      getCAR ( i ) . setcsno ( i + nss ) ;

      // Train serial number sent to each train object instance.
      getCAR ( i ) . setcarno ( i ) ;
    }
  }
  else
  {
    FILE * ssdata = fopen ( s_file , "r" ) ;
    if  ( ssdata == 0 ) err_access ( s_file ) ;

    // If any one of the real-time control algorithms is enabled,
    // sw_onlyonetype is to be true. If two or more types are specified,
    // then it is data error.
    bool sw_onlyonetype = false ;
    while ( 1 )
    {
      // Continue until first command "substations" is found
      getcommand ( ssdata , s_file ) ;
      if ( strcmp ( tmpch , "substation_control_a" ) == 0 )
      {
        if ( g_sw_substn_ctl_a || sw_onlyonetype )
        {
          err_eof ( s_file ) ;
        }
        else
        {
          g_sw_substn_ctl_a = true ;
          cerr << "OK, substation realtime control Type A: true" << endl ;

          // Reading parameters for the Type A control
          gettwoints ( ssdata , s_file , TYPEA_REGMAX , TYPEA_IPCMAX ) ;
          getdouble ( ssdata , s_file , TYPEA_MINVOLT ) ;
          getint ( ssdata , s_file , TYPEA_TRNMAX ) ;
          gettwodbls ( ssdata , s_file , TYPEA_REGR_D , TYPEA_DELTA_C ) ;
          cerr << "Type A parameters:" << endl ;
          l_ofs << StrPrintf ( "%4d, %4d, %10.3f, %4d, %10.6f, %10.7f" ,
                               TYPEA_REGMAX , TYPEA_IPCMAX , TYPEA_MINVOLT ,
                               TYPEA_TRNMAX , TYPEA_REGR_D , TYPEA_DELTA_C )
                << endl ;
          TYPEA_DCLIM = 1e-5 ;
          TYPEA_DCMAX = 0.002 ;
          sw_onlyonetype = true ;
        }
      }
      else if ( strcmp ( tmpch , "substation_control_a_8" ) == 0 )
      {
        if ( g_sw_substn_ctl_a || sw_onlyonetype )
        {
          err_eof ( s_file ) ;
        }
        else
        {
          g_sw_substn_ctl_a = true ;
          cerr << "OK, substation realtime control Type A: true" << endl ;

          // Reading parameters for the Type A control
          gettwoints ( ssdata , s_file , TYPEA_REGMAX , TYPEA_IPCMAX ) ;
          getdouble ( ssdata , s_file , TYPEA_MINVOLT ) ;
          getint ( ssdata , s_file , TYPEA_TRNMAX ) ;
          gettwodbls ( ssdata , s_file , TYPEA_REGR_D , TYPEA_DELTA_C ) ;
          gettwodbls ( ssdata , s_file , TYPEA_DCMAX , TYPEA_DCLIM ) ;
          cerr << "Type A parameters:" << endl ;
          l_ofs << StrPrintf
            ( "%4d, %4d, %10.3f, %4d, %10.6f, %10.7f %10.7f %10.7f" ,
              TYPEA_REGMAX , TYPEA_IPCMAX , TYPEA_MINVOLT , TYPEA_TRNMAX ,
              TYPEA_REGR_D , TYPEA_DELTA_C , TYPEA_DCMAX , TYPEA_DCLIM )
                << endl ;
          sw_onlyonetype = true ;
        }
      }
      else if ( strcmp ( tmpch , "substations" ) == 0 ) 
      {
        break ;
      }
      else
      {
        err_eof ( s_file ) ;
      }
    }
    int submax ;
    getint ( ssdata , s_file , submax ) ;
    l_ofs << endl << StrPrintf ( "Number of substations: %d" , submax )
          << endl ;

    nss = submax ;

    // *** Assume ncar is already defined at this stage ***
    ncss = nss + ncar ;

    // *** Define the serial numbers for all substations and trains here ***
    for ( int i = 0 ; i < nss ; ++ i )
    {
      elecchar * x = new elecchar ;
      if ( ! x )
      {
        cerr << "Error: memory allocation failed when creating "
             << "an elecchar object" << endl ;
        exit ( 40 ) ;
      }
      vec_sub . push_back ( x ) ;
      vec_csd . push_back ( x ) ;
      // Substation number sent to each substation object instance.
      getCSD ( i ) -> setcsno ( i ) ;
    }
    for ( int i = 0 ; i < ncar ; ++ i )
    {
      vec_csd . push_back ( ( elecchar * ) & ( getCAR ( i ) ) ) ;

      // Substation/train serial number sent to each train object instance.
      getCAR ( i ) . setcsno ( i + nss ) ;

      // Train serial number sent to each train object instance.
      getCAR ( i ) . setcarno ( i ) ;
    }

    for ( int i = 0 ; i < nss ; i++ )
    {
      // Reading substation characteristics data
      getSUB ( i ) . readfile ( ssdata , s_file ) ;
    }
    fclose ( ssdata ) ;
  }
}


// Reading XML-based S File:
// Read parameters related to "substation control type A"
void
feeder :: rf_sxml_ctrl_a
( const TiXmlNode * tn_in )
{
  // -----
  // This tag must set all elements in struct typea_data, which is defined
  // at the top of kidenrt.hh
  // このタグによって，kidenrt.hh ファイルの冒頭で定義されている typea_data
  // 構造体のすべての要素が定義される必要がある。
  // -----
  bool regmax_not_set = true ;
  bool ipcmax_not_set = true ;
  bool minvolt_not_set = true ;
  bool trnmax_not_set = true ;
  bool regr_d_not_set = true ;
  bool delta_c_not_set = true ;
  bool dcmax_not_set = true ;
  bool dclim_not_set = true ;
  
  const TiXmlAttribute * attr = tn_in -> ToElement () -> FirstAttribute () ;
  while ( attr )
  {
    if ( string ( attr -> Name () ) == "regmax" )
    {
      // Attribute "regmax"
      sscanf ( attr -> Value () , "%d" , & ( TYPEA_REGMAX ) ) ;
      regmax_not_set = false ;
    }
    else if ( string ( attr -> Name () ) == "ipcmax" )
    {
      // Attribute "ipcmax"
      sscanf ( attr -> Value () , "%d" , & ( TYPEA_IPCMAX ) ) ;
      ipcmax_not_set = false ;
    }
    else if ( string ( attr -> Name () ) == "minvolt" )
    {
      // Attribute "minvolt"
      sscanf ( attr -> Value () , "%lf" , & ( TYPEA_MINVOLT ) ) ;
      minvolt_not_set = false ;
    }
    else if ( string ( attr -> Name () ) == "trnmax" )
    {
      // Attribute "trnmax"
      sscanf ( attr -> Value () , "%d" , & ( TYPEA_TRNMAX ) ) ;
      trnmax_not_set = false ;
    }
    else if ( string ( attr -> Name () ) == "regr_d" )
    {
      // Attribute "regr_d"
      sscanf ( attr -> Value () , "%lf" , & ( TYPEA_REGR_D ) ) ;
      regr_d_not_set = false ;
    }
    else if ( string ( attr -> Name () ) == "delta_c" )
    {
      // Attribute "delta_c"
      sscanf ( attr -> Value () , "%lf" , & ( TYPEA_DELTA_C ) ) ;
      delta_c_not_set = false ;
    }
    else if ( string ( attr -> Name () ) == "dcmax" )
    {
      // Attribute "dcmax"
      sscanf ( attr -> Value () , "%lf" , & ( TYPEA_DCMAX ) ) ;
      dcmax_not_set = false ;
    }
    else if ( string ( attr -> Name () ) == "dclim" )
    {
      // Attribute "dclim"
      sscanf ( attr -> Value () , "%lf" , & ( TYPEA_DCLIM ) ) ;
      dclim_not_set = false ;
    }
    else
    {
      cerr << "ERROR: tag <substation_control_a> with incorrect attribute "
           << attr -> Name () << endl ;
      exit ( 1 ) ;
    }
    attr = attr -> Next () ;
  }
  if ( regmax_not_set || ipcmax_not_set || minvolt_not_set || trnmax_not_set
       || regr_d_not_set || delta_c_not_set || dcmax_not_set
       || dclim_not_set )
  {
    cerr << "ERROR: tag <substation_control_a> with "
         << "incorrect number of attributes" << endl ;
    exit ( 1 ) ;
  }
}



// -----
// Reading XML-based S File: read tag "substation"
// XML形式Sファイルを読む: タグ substation の処理
// -----
void
feeder :: rf_sxml_substation
( const TiXmlNode * tn_in )
{
  // -----
  // The variable nss will (must) show how many substations have been
  // initialised so far.
  // 変数 nss が，現在までにいくつの変電所が初期化されたかを示しているはず。
  // -----

  // -----
  // Construct an object of type elecchar using "new".
  // 型が elecchar であるオブジェクトをひとつ，"new" で作成する。
  // -----
  elecchar * x = new elecchar ;
  if ( ! x )
  {
    cerr << "Error: memory allocation failed when creating "
         << "an elecchar object" << endl ;
    exit ( 40 ) ;
  }

  // -----
  // Save the pointer in vectors.
  // ポインタなので，vector に格納。
  // -----
  vec_sub . push_back ( x ) ;
  vec_csd . push_back ( x ) ;

  // -----
  // Send substation number to this substation object instance.
  // 変電所番号を当該オブジェクトに送信。
  // -----
  getCSD ( nss ) -> setcsno ( nss ) ;

  // -----
  // Read substation characteristics data.
  // 変電所特性データを読み込む。
  // -----
  getSUB ( nss ) . readfile_xml ( tn_in ) ;

  // -----
  // Increment variable nss, which will show how many substations have been
  // initialised so far.
  // 変数 nss をインクリメントする。nss が，現在までにいくつの変電所が初期化
  // されたかを示すことになる。
  // -----
  ++ nss ;
}
