// This may look like C code, but it is really -*- C++ -*-
// RTSS --- Railway Total System Simulator
// (c) TAKAGI Ryo (at Kogakuin University)
// rf_nfile.cc --- read data from files: N file
// -----
// ChangeLog:
// 2007. 11. 21
//  Redirected log messages to l_file.
// -----

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

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

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

// Reading N File
void
feeder :: rf_nfile
()
{
  if ( n_xml )
  {
    // -----
    // Loading file.
    // ファイルロード。
    // -----
    string n_file_full_path = "" ;
    if ( is_backslash )
    {
      n_file_full_path += n_drive_str ;
    }
    n_file_full_path += n_dir_str ;
    if ( is_backslash )
    {
      n_file_full_path += "\\" ;
    }
    else
    {
      n_file_full_path += "/" ;
    }
    n_file_full_path += n_file_str ;
    TiXmlDocument n_doc ( n_file_full_path ) ;
    bool loadOkay = n_doc . LoadFile () ;
    if ( ! loadOkay )
    {
      cerr << "Failed to load file \"" << n_file_full_path << "\"." << endl ;
      exit ( 1 ) ;
    }

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

    // -----
    // Allowed tags under <rtss_n_file> (in this order):
    // (1) <n_flags> : Flags. Up to one per file, can be omitted.
    // (2) <accompanying_file> : Acompanying file. As many as are required,
    //     including zero.
    // (3) <pattern> : Train schedule pattern data. As many as are required,
    //     one required.
    // <rtss_p_file> の子タグ（この順番で現れること）:
    // (1) <n_flags> : Flags. Up to one per file, can be omitted.
    // (2) <accompanying_file> : Accompanying file. As many as are required,
    //     including zero.
    // (3) <pattern> : Train schedule pattern data. As many as are required,
    //     at least one must exist.
    // -----
    bool sw_flags_ended = false ;
    bool sw_afiles_ended = false ;
    bool sw_pattern_found = false ;
    ndp = 0 ;
    for ( TiXmlNode const * _ch = n_doc_cd -> FirstChild () ;
          _ch ; _ch = _ch -> NextSibling () )
    {
      // -----
      // Ignore non-Element node.
      // エレメント以外は無視。
      // -----
      if ( _ch -> Type () != TiXmlNode :: TINYXML_ELEMENT )
      {
        continue ;
      }

      // -----
      // Check tag name.
      // タグ名チェック。
      // -----
      string _ch_v = _ch -> ValueStr () ;
      if ( _ch_v == "n_flags" )
      {
        if ( sw_flags_ended )
        {
          cerr << "Error: \"n_flags\" tag duplicate or incorrectly located."
               << endl ;
          exit ( 1 ) ;
        }
        sw_flags_ended = true ;
        rf_nxml_flags ( _ch ) ;
      }
      else if ( _ch_v == "accompanying_file" )
      {
        if ( sw_afiles_ended )
        {
          cerr << "Error: \"accompanying_file\" tag incorrectly located."
               << endl ;
          exit ( 1 ) ;
        }
        sw_flags_ended = true ;
        rf_nxml_accompanying_file ( _ch ) ;
      }
      else if ( _ch_v == "pattern" )
      {
        sw_flags_ended = sw_afiles_ended = true ;
        rf_nxml_pattern ( _ch , ndp ) ;
        ++ ndp ;
      }
      else
      {
        cerr << "Error: \"" << _ch_v << "\" tag not allowed in N_file."
             << endl ;
        exit ( 1 ) ;
      }
    }
  }
  else
  {
    FILE * diapatrn = fopen ( n_file , "r" ) ;

    if ( diapatrn == 0 )
    {
      err_access ( n_file ) ;
    }
    
    commandvalue comval ;
    while ( ( comval = getcommandvalue ( diapatrn , n_file ) ) != PATTERNS )
    {
      // Processing flags, until the first command "patterns" is found

      switch ( comval )
      {
      case STATION_OBJECT_VALID :
        if ( g_sw_station_object_valid )
        {
          g_sw_station_object_valid = false ;
          cerr << "OK, toggled g_sw_station_object_valid to false" << endl ;
        }
        else
        {
          g_sw_station_object_valid = true ;
          cerr << "OK, toggled g_sw_station_object_valid to true" << endl ;
        }
        break ;

      case CONGES_STATION :
        if ( g_sw_conges_station )
        {
          g_sw_conges_station = false ;
          cerr << "OK, toggled g_sw_conges_station to false" << endl ;
        }
        else
        {
          g_sw_conges_station = true ;
          cerr << "OK, toggled g_sw_conges_station to true" << endl ;
        }
        break ;

      case ONTPREC_DELAY_SET :
        getdouble ( diapatrn , n_file , ontprec_delay_set ) ;
        l_ofs << StrPrintf ( "ontprec_delay_set: %10.4f" , ontprec_delay_set )
              << endl ;
        break ;

      case STARTSTOP_PARAMETER :
        getdouble ( diapatrn , n_file , startstop_parameter ) ;
        l_ofs << StrPrintf ( "startstop_parameter: %10.4f" , 
                             startstop_parameter ) << endl ;
        break ;

      case ONTPREC :
        if ( g_sw_ont_prec )
        {
          g_sw_ont_prec = false ;
          cerr << "OK, toggled g_sw_ont_prec to false" << endl ;
        }
        else
        {
          g_sw_ont_prec = true ;
          cerr << "OK, toggled g_sw_ont_prec to true" << endl ;
        }
        break ;

      case INITIALDEPARTURETIME :
        if ( g_sw_specify_tdept )
        {
          g_sw_specify_tdept = false ;
          cerr << "OK, toggled g_sw_specify_tdept to false" << endl ;
        }
        else
        {
          g_sw_specify_tdept = true ;
          cerr << "OK, toggled g_sw_specify_tdept to true" << endl ;
        }
        break ;

      default :
        err_eof ( n_file ) ;
      }
    }

    // Processing command "patterns"
    getint ( diapatrn ,  n_file , ndp ) ;
    l_ofs << "number of diagram patterns = " << ndp << endl ;

    for ( int i = 0 ; i < ndp ; ++ i )
    {
      // Create diapattern object and store it in vec_dpt
      diapattern * x = new diapattern ;
      if ( ! x )
      {
        cerr << "Error: memory fault when initializing a diapattern object"
             << endl ;
        exit ( 40 ) ;
      }
      vec_dpt . push_back ( x ) ;

      // Send i as the serial number for this diagram pattern
      getDPT ( i ) . set_ndpt ( i ) ;

      // Reading data
      if ( getDPT ( i ) . readfile ( diapatrn , n_file ) == EOF )
      {
        err_eof ( n_file ) ;
      }
    }
    fclose ( diapatrn ) ;
  }

  gradcrv ky , kv , kr ;
  for ( int i = 0 ; i < ndp ; ++ i )
  {
    // ----
    // Jobs to be done here:
    // (1) Setting SOC_FeedForward_Data if any.
    // (2) Putting gradcrv data into a nextsta object
    // ----
    for ( diapattern :: np_iterator j = getDPT ( i ) . np_begin () ;
          j < getDPT ( i ) . np_end () ; ++ j )
    {
      nextsta * _nj = * j ;
      if ( ! _nj )
      {
        cerr << "Error in feeder::rf_nfile(): diapattern having null pointer"
             << endl ;
        exit ( 1 ) ;
      }

      // Job (1)
      if ( _nj -> wants_SOC_Curve () )
      {
        _nj -> set_SOC_Curve ( _soc . locate ( _nj -> get_SOC_Key () ) ) ;
      }

      // Job (2)
      nextsta :: gc_size_type kx ;
      int kw ;
      double ku ;
      bool greq_success = _nj -> get_greq ( kx , kw , ku ) ;
      ky . gc_renew () ;
      kv . gc_renew () ;
      while ( greq_success )
      {
	if ( kx >= ngrad ) err_eof ( n_file ) ;
	if ( kw != 0 )
	{
	  kr = getGCV ( kx ) ;
	  kv = ky + kr . renewpos ( kx , ku ) ;
	}
	else
	{
	  kv = ky + getGCV ( kx ) ;
	}
	ky = kv ;
	kv . gc_renew () ;
	greq_success = _nj -> get_greq ( kx , kw , ku ) ;
      }
      * _nj = ky ;
    }
    for ( diapattern :: np_iterator j = getDPT ( i ) . np_begin () ;
          j < getDPT ( i ) . np_end () ; ++ j )
    {
      // Processing arv
      ( * j ) -> arv_pass () ;
    }
  }

  // Determining the number of trains
  ncar = 0 ;
  for ( int i = 0 ; i < ndp ; ++ i )
  {
    ncar += getDPT ( i ) . car_number () ;
    for ( int j = 0 ; j < getDPT ( i ) . car_number () ; ++ j )
    {
      train * x = new train ( getDPT ( i ) . getTrainTypeKey () ) ;
      if ( ! x )
      {
        std :: cerr << "Error: memory allocation failed when creating "
                    << "a train object" << std :: endl ;
        exit ( 40 ) ;
      }
      vec_car . push_back ( x ) ;
    }
  }
}




// ----
// Subroutine of feeder::rf_nfile(...), reading XML tag <n_flags>
// feeder::rf_nfile(...)のサブルーチン，XMLタグ <n_flags> を解釈。
// ----
void
feeder :: rf_nxml_flags
( TiXmlNode const * _in )
{
  // ----
  // All former "N flags" are now attributes of tag <n_flags>.
  // 旧形式ファイルの N フラグはすべて <n_flags> タグの属性とした。
  // ----
  for ( TiXmlAttribute const * _att = _in -> ToElement ()
          -> FirstAttribute () ; _att ; _att = _att -> Next () )
  {
    string _atn = string ( _att -> Name () ) ;
    string _atv = string ( _att -> Value () ) ;
    if ( _atn == "station_object_valid" )
    {
      if ( _atv == "true" || _atv == "TRUE" || _atv == "t" || _atv == "T" )
      {
        g_sw_station_object_valid = true ;
        cerr << "OK, set g_sw_station_object_valid to true" << endl ;
      }
      else if ( _atv == "false" || _atv == "FALSE" || _atv == "f"
                || _atv == "F" )
      {
        g_sw_station_object_valid = false ;
        cerr << "OK, set g_sw_station_object_valid to false" << endl ;
      }
      else
      {
        cerr << "Error in <n_flag>: station_object_valid"
             << " must be either true or false" << endl ;
        exit ( 1 ) ;
      }
    }
    else if ( _atn == "conges_station" )
    {
      if ( _atv == "true" || _atv == "TRUE" || _atv == "t" || _atv == "T" )
      {
        g_sw_conges_station = true ;
        cerr << "OK, set g_sw_conges_station to true" << endl ;
      }
      else if ( _atv == "false" || _atv == "FALSE" || _atv == "f"
                || _atv == "F" )
      {
        g_sw_conges_station = false ;
        cerr << "OK, set g_sw_conges_station to false" << endl ;
      }
      else
      {
        cerr << "Error in <n_flag>: conges_station"
             << " must be either true or false" << endl ;
        exit ( 1 ) ;
      }
    }
    else if ( _atn == "ontprec_delay_set" )
    {
      sscanf ( _atv . c_str () , "%lf", & ontprec_delay_set ) ;
      l_ofs << StrPrintf ( "ontprec_delay_set: %10.4f" , ontprec_delay_set )
            << endl ;
    }
    else if ( _atn == "startstop_parameter" )
    {
      sscanf ( _atv . c_str () , "%lf", & startstop_parameter ) ;
      l_ofs << StrPrintf ( "startstop_parameter: %10.4f" , 
                           startstop_parameter ) << endl ;
    }
    else if ( _atn == "ontprec" )
    {
      if ( _atv == "true" || _atv == "TRUE" || _atv == "t" || _atv == "T" )
      {
        g_sw_ont_prec = true ;
        cerr << "OK, set g_sw_ont_prec to true" << endl ;
      }
      else if ( _atv == "false" || _atv == "FALSE" || _atv == "f"
                || _atv == "F" )
      {
        g_sw_ont_prec = false ;
        cerr << "OK, set g_sw_ont_prec to false" << endl ;
      }
      else
      {
        cerr << "Error in <n_flag>: ontprec"
             << " must be either true or false" << endl ;
        exit ( 1 ) ;
      }
    }
    else if ( _atn == "initialdeparturetime" )
    {
      if ( _atv == "true" || _atv == "TRUE" || _atv == "t" || _atv == "T" )
      {
        g_sw_specify_tdept = true ;
        cerr << "OK, set g_sw_specify_tdept to true" << endl ;
      }
      else if ( _atv == "false" || _atv == "FALSE" || _atv == "f"
                || _atv == "F" )
      {
        g_sw_specify_tdept = false ;
        cerr << "OK, set g_sw_specify_tdept to false" << endl ;
      }
      else
      {
        cerr << "Error in <n_flag>: initialdeparturetime"
             << " must be either true or false" << endl ;
        exit ( 1 ) ;
      }
    }
    else
    {
      cerr << "Error in <n_flag>: attribute " << _atn << " not allowed"
           << endl ;
      exit ( 1 ) ;
    }
  }
}



// ----
// Subroutine of feeder::rf_nfile(...), reading XML tag <accompanying_file>
// feeder::rf_nfile(...)のサブルーチン，XMLタグ <accompanying_file> を解釈。
// ----
void
feeder :: rf_nxml_accompanying_file
( TiXmlNode const * _in )
{
  // -----
  // Getting file name.
  // ファイル名を取得.
  // -----
  for ( TiXmlAttribute const * atvi = _in -> ToElement ()
          -> FirstAttribute () ; atvi ; atvi = atvi -> Next () )
  {
    string _n_in = atvi -> Name () ;
    if ( _n_in != "name" )
    {
      cerr << "ERROR: tag <accompanying_file> with incorrect attribute \""
           << _n_in << "\"" << endl ;
      exit ( 1 ) ;
    }
    RTSS_Path_String vifn ( atvi -> Value () ) ;
    l_ofs << "Reference SOC vifn: " << vifn << endl ;
    string ffsoc_drive = "" ;
    string ffsoc_dir = "" ;
    string ffsoc_file = "" ;
    if ( ! vifn . processPath ( is_backslash , n_drive_str , n_dir_str ,
                                ffsoc_drive , ffsoc_dir , ffsoc_file ) )
    {
      cerr << "ERROR: unknown error in processPath at rf_nfile.cc"
           << endl ;
      exit ( 1 ) ;
    }
    string ffsoc_c_fname = ffsoc_drive ;
    ffsoc_c_fname += ffsoc_dir ;
    if ( is_backslash )
    {
      ffsoc_c_fname += "\\" ;
    }
    else
    {
      ffsoc_c_fname += "/" ;
    }
    ffsoc_c_fname += ffsoc_file ;
    l_ofs << "Ref SOC filename: " << ffsoc_c_fname << endl ;

    // -----
    // Constructing the object.
    // オブジェクトを構成.
    // -----
    _xread . openXmlDocument ( ffsoc_c_fname , ffsoc_drive , ffsoc_dir ) ;
    do
    {
      _xread . processElement () ;
    }
    while ( _xread . hasNextElement () ) ;
  }
}



// ----
// Subroutine of feeder::rf_nfile(...), reading XML tag <pattern>
// feeder::rf_nfile(...)のサブルーチン，XMLタグ <pattern> を解釈。
// ----
void
feeder :: rf_nxml_pattern
( TiXmlNode const * _in ,
  int i_x )
{
  // ----
  // Create a diapattern class object and store it in vec_dpt.
  // diapattern クラスのオブジェクトを作成し，vec_dpt に格納する.
  // ----
  diapattern * x = new diapattern ;
  if ( ! x )
  {
    cerr << "Error: memory fault when initializing a diapattern object"
         << endl ;
    exit ( 1 ) ;
  }
  vec_dpt . push_back ( x ) ;

  // Send i_x as the serial number for this diagram pattern
  x -> set_ndpt ( i_x ) ;

  // Reading data
  if ( ! x -> readfile_xml ( _in ) )
  {
    cerr << "Error: interpreting <pattern> tag in XML N file failed."
         << endl ;
    exit ( 1 ) ;
  }
}
