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

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

#include "kidenrt.hh"

//#define DEBUG


// gradcurv.dat を読むファイル
void
feeder :: rf_gfile
()
{
  if ( g_xml )
  {
    // -----
    // Loading file.
    // ファイルロード。
    // -----
    string g_file_full_path = "" ;
    if ( is_backslash )
    {
      g_file_full_path += g_drive_str ;
    }
    g_file_full_path += g_dir_str ;
    if ( is_backslash )
    {
      g_file_full_path += "\\" ;
    }
    else
    {
      g_file_full_path += "/" ;
    }
    g_file_full_path += g_file_str ;
    TiXmlDocument g_doc ( g_file_full_path ) ;
    bool loadOkay = g_doc . LoadFile () ;
    if ( ! loadOkay )
    {
      cerr << "Failed to load file \"" << g_file_full_path << "\"." << endl ;
      exit ( 1 ) ;
    }

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

    // -----
    // Getting child element(s) of tag <rtss_g_file>.
    // Tags must appear in this order:-
    //  <speed_restriction_margin>: Up to 1 appearance, can be omitted.
    //  <gradient_data_set>: As many appearances as possible, cannot be
    //  omitted.
    // <rtss_g_file> の子を取得. 以下の順で現れる必要がある。
    //  <speed_restriction_margin>: 1回まで。省略可。
    //  <gradient_data_set>: 何回でも，省略不可。
    // -----
    bool has_speed_restriction_margin_tag = false ;
    bool started_gradient_data_sets = false ;
    for ( const TiXmlNode * g_doc_cc = g_doc_ch -> FirstChild () ;
          g_doc_cc ; g_doc_cc = g_doc_cc -> NextSibling () )
    {
      // -----
      // Ignore non-Element node.
      // エレメント以外は無視。
      // -----
      if ( g_doc_cc -> Type () != TiXmlNode :: TINYXML_ELEMENT )
        continue ;

      // -----
      // Check tag name.
      // タグ名チェック。
      // -----
      string sdcc_val = string ( g_doc_cc -> Value () ) ;
      if ( sdcc_val == "speed_restriction_margin" )
      {
        // -----
        // Processing <speed_restriction_margin> tag.
        // <speed_restriction_margin> タグを処理.
        // -----
        if ( has_speed_restriction_margin_tag )
        {
          cerr << "Error: \"" << sdcc_val
               << "\" tag not allowed multiple times." << endl ;
          exit ( 1 ) ;
        }
        if ( started_gradient_data_sets )
        {
          cerr << "Error: \"" << sdcc_val
               << "\" tag at incorrect position in XML G file." << endl ;
          exit ( 1 ) ;
        }
        rf_gxml_speed_restriction_margin ( g_doc_cc ) ;
        has_speed_restriction_margin_tag = true ;
      }
      else if ( sdcc_val == "gradcrv_data_set" )
      {
        // -----
        // Processing <gradcrv_data_set> tag.
        // <gradcrv_data_set> タグを処理.
        // -----
        rf_gxml_data_sets ( g_doc_cc ) ;
        started_gradient_data_sets = true ;
      }
      else
      {
        cerr << "Error: \"" << sdcc_val << "\" tag not allowed." << endl ;
        exit ( 1 ) ;
      }
    }
    ngrad = vec_gcv . size () ;

    // ----
    // Copying "referenced" data, and do data checks.
    // ----
    for ( vector < gradcrv * > :: iterator ii = vec_gcv . begin () ;
          ii != vec_gcv . end () ; ++ ii )
    {
      ( * ii ) -> getReferencedXmlDataSetsAndConvert ( _gcv , vec_gcv ) ;
    }

    // ----
    // Deleting XML data sets.
    // ----
    for ( vector < gradcrv * > :: iterator ii = vec_gcv . begin () ;
          ii != vec_gcv . end () ; ++ ii )
    {
      ( * ii ) -> deleteXmlDataSets () ;
    }
  }
  else
  {
    FILE * gpoint = fopen ( g_file , "r" ) ;
    if ( gpoint == 0 ) err_access ( g_file ) ;
    while ( 1 )
    {
      // 最初の number を見つけるまで続ける
      getcommand ( gpoint , g_file ) ;
      if ( cmpcommand ( "vlimitmikomi" ) )
      {
        getdouble ( gpoint , g_file , g_vlimitmikomi ) ;
      }
      else if ( strcmp ( tmpch , "number" ) == 0 )
      {
        break ;
      }
      else
      {
        err_eof ( g_file ) ;
      }
    }
    int _ix_ngrad = 0 ;
    if ( getint ( gpoint , _ix_ngrad ) == EOF )
    {
      err_eof ( g_file ) ;
    }
    if ( _ix_ngrad < 0 )
    {
      cerr << "Error: number must be positive in G file" << endl ;
      exit ( 1 ) ;
    }
    ngrad = _ix_ngrad ;
    l_ofs << "number of gradcrv data: " << ngrad << endl ;

    for ( vector < gradcrv * > :: size_type i = 0 ; i < ngrad ; ++ i )
    {
      gradcrv * x = new gradcrv ;
      if ( ! x )
      {
        cerr << "Error: memory allocation failed in creating "
             << "a gradcrv object" << endl ;
        exit ( 40 ) ;
      }
      vec_gcv . push_back ( x ) ;

      // getGCV ( i ) . readfile のログにつなげる
      l_ofs << "No." << i << " " ;
      if ( getGCV ( i ) . readfile ( gpoint ) == EOF )
      {
        err_eof ( g_file ) ;
      }
    }
    fclose ( gpoint ) ;
  }
}



// Reading XML-based G File:
// Read parameters related to "vlimitmikomi"
void
feeder :: rf_gxml_speed_restriction_margin
( const TiXmlNode * tn_in )
{
  // -----
  // This tag must set the "vlimitmikomi" parameter.
  // このタグによって，"vlimitmikomi" パラメータが定義される必要がある。
  // -----
  const TiXmlAttribute * attr = tn_in -> ToElement () -> FirstAttribute () ;
  while ( attr )
  {
    if ( string ( attr -> Name () ) != "value" )
    {
      cerr << "ERROR: tag <speed_restriction_margin> "
           << "with incorrect attribute " << attr -> Name () << endl ;
      exit ( 1 ) ;
    }
    sscanf ( attr -> Value () , "%lf" , & g_vlimitmikomi ) ;
    attr = attr -> Next () ;
  }
}



// -----
// Reading XML-based G File: read tag "gradcrv_data_set"
// XML形式Gファイルを読む: タグ gradcrv_data_set の処理
// -----
void
feeder :: rf_gxml_data_sets
( const TiXmlNode * tn_in )
{

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

  // -----
  // Save the pointer in vector vec_gcv.
  // ポインタを，vec_gcg ベクトルに格納。
  // -----
  vec_gcv . push_back ( x ) ;

  // -----
  // Save the pointer in map _gcv. The name (key for the map) can be
  // extracted from the object itself.
  // ポインタを，_gcv マップに格納。マップのキーとして利用する名前は
  // オブジェクトそのものから取り出すことができる。
  // -----
  if ( _gcv . find ( x -> getName () ) != _gcv . end () )
  {
    cerr << "Error: duplicate name found in XML G file." << endl ;
    exit ( 1 ) ;
  }
  _gcv [ x -> getName () ] = vec_gcv . size () - 1 ;
}
