// This may look like C code, but it is really -*- C++ -*-
// RTSS --- Railway Total System Simulator
// (c) TAKAGI Ryo (at Kogakuin University)
// Substation_Control_VI_TS.cc
//  --- class Substation_Control_VI_TS implementations
// -----
// ChangeLog:
// 2007. 11. 19
//  File created.
// -----


#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <string>
#include "Substation_Control_VI_TS.hh"

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



// -----
// Constructor of class SubstationControlData_VI using two XML attributes
// SubstationControlData_VI クラスを2つのXML属性で初期化する
// -----
SubstationControlData_VI :: SubstationControlData_VI
( const SubstationControlData_VI :: Init & x )
{
  // -----
  // Two attributes are contained in TiXmlNode pointers x._v and x._i.
  // No pointer validity check is done here.
  // 2つの属性は x._v と x._i という TiXmlNode ポインタの先にある.
  // ポインタの有効性チェックはしない.
  // -----
  sscanf ( x . _v -> Value () , "%lf" , & _v ) ;
  sscanf ( x . _i -> Value () , "%lf" , & _i ) ;
}



// -----
// Constructor of class Substation_Control_VI_TS using a file
// Substation_Control_VI_TS クラスをファイルひとつで初期化する
// -----
Substation_Control_VI_TS :: Substation_Control_VI_TS
( const string & fn_in )
  : t_cyc ( 0 )
{
  // -----
  // Loading file.
  // ファイルロード。
  // -----

  TiXmlDocument vits_doc ( fn_in ) ;
  bool loadOkay = vits_doc . LoadFile () ;
  if ( ! loadOkay )
  {
    cerr << "Failed to load file \"" << fn_in << "\"." << endl ;
    exit ( 1 ) ;
  }

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

  // -----
  // Getting child elements of tag <rtss_subchar>.
  // Tags must all be <subchar>.
  // <rtss_subchar> の子を取得. すべて <subchar> タグ。
  // -----
  bool sw_first = true ;
  double _end_pre = 0 ;
  for ( const TiXmlNode * _cc = _ch -> FirstChild () ;
        _cc ; sw_first = false , _cc = _cc -> NextSibling () )
  {
    // -----
    // Ignore non-Element node.
    // エレメント以外は無視。
    // -----
    if ( _cc -> Type () != TiXmlNode :: TINYXML_ELEMENT )
      continue ;

    // -----
    // Check tag name.
    // タグ名チェック。
    // -----
    string _cc_val = string ( _cc -> Value () ) ;
    if ( _cc_val != "subchar" )
    {
      cerr << "Error: \"" << _cc_val << "\" tag not allowed." << endl ;
      exit ( 1 ) ;
    }

    double _st = 0 ;
    bool _sw_st = true ;
    double _end = 0 ;
    bool _sw_end = true ;
    const TiXmlAttribute * _v = 0 ;
    bool _sw_v = true ;
    const TiXmlAttribute * _i = 0 ;
    bool _sw_i = true ;
    for ( const TiXmlAttribute * attr
            = _cc -> ToElement () -> FirstAttribute () ;
          attr ; attr = attr -> Next () )
    {
      // -----
      // Get start and end times.
      // 開始・終了時間を取得.
      // -----
      if ( string ( attr -> Name () ) == "time_start" )
      {
        _sw_st = false ;
        sscanf ( attr -> Value () , "%lf" , & _st ) ;
      }
      else if ( string ( attr -> Name () ) == "time_end" )
      {
        _sw_end = false ;
        sscanf ( attr -> Value () , "%lf" , & _end ) ;
      }
      else if ( string ( attr -> Name () ) == "subchar_v" )
      {
        _sw_v = false ;
        _v = attr ;
      }
      else if ( string ( attr -> Name () ) == "subchar_i" )
      {
        _sw_i = false ;
        _i = attr ;
      }
      else
      {
        cerr << "ERROR: tag <subchar> with incorrect attribute "
             << attr -> Name () << endl ;
        exit ( 1 ) ;
      }
    }
    if ( _sw_st || _sw_end || _sw_v || _sw_i )
    {
      cerr << "ERROR: <subchar> data incorrect in <rtss_subchar>" << endl ;
      exit ( 1 ) ;
    }
    if ( ! ( sw_first || _end_pre == _st ) )
    {
      cerr << "ERROR: gap between data in <rtss_subchar>" << endl ;
      exit ( 1 ) ;
    }
    if ( _st >= _end )
    {
      cerr << "ERROR: section time length must be positive in <rtss_subchar>"
           << endl ;
      exit ( 1 ) ;
    }
    SubstationControlData_VI :: Init _vi ;
    _vi . _v = _v ;
    _vi . _i = _i ;

    // -----
    // Create a SubstationControlData_VI object instance, and put it in
    // the vector by push_back().
    // SubstationControlData_VI オブジェクトのインスタンスを生成し，
    // push_back() 関数で vector に挿入する.
    // -----
    push_back ( VISection ( _st , _end , _vi ) ) ;
    _end_pre = _end ;
  }

  // -----
  // Set t_ref and _current to the very first time. Also set t_first and
  // t_last.
  // t_ref と _current を最初の時間にセット。さらに t_first と t_last も
  // セット.
  // -----
  _current = begin () ;
  t_first = t_ref = _current -> getStartOfSection () ;
  vector < VISection > :: const_iterator _last = end () - 1 ;
  t_last = _last -> getEndOfSection () ;
}



// -----
// Returns true if the time is "within the region".
// 与えられた時間がデータの「範囲内」かどうかを答える.
// -----
bool
Substation_Control_VI_TS :: timeIsInRegion
( double _t )
  const
{
  // -----
  // If t_ref is equal to _t, then return true. Otherwise, if (_t - t_cyc)
  // is between t_first and t_last, return true.
  // t_ref と _t が等しければ true をリターン. それ以外で，(_t - t_cyc) が
  // t_first と t_last の間にあれば，true を返す.
  // -----
  if ( t_ref == _t ) return true ;
  double tx = _t - t_cyc ;
  return t_first <= tx && tx <= t_last ;
}




// -----
// Returns true if the time is "before the region".
// 与えられた時間がデータの「範囲より前」かどうかを答える.
// -----
bool
Substation_Control_VI_TS :: timeIsBeforeRegion
( double _t )
  const
{
  // -----
  // If t_ref is equal to _t, then return false. Otherwise, if (_t - t_cyc)
  // is before t_first, return true.
  // t_ref と _t が等しければ false をリターン. それ以外で，(_t - t_cyc) が
  // t_first より前なら，true を返す.
  // -----
  if ( t_ref == _t ) return false ;
  double tx = _t - t_cyc ;
  return t_first > tx ;
}




// -----
// Returns true if the time is "after the region".
// 与えられた時間がデータの「範囲より後」かどうかを答える.
// -----
bool
Substation_Control_VI_TS :: timeIsAfterRegion
( double _t )
  const
{
  // -----
  // If t_ref is equal to _t, then return false. Otherwise, if (_t - t_cyc)
  // is after t_last, return true.
  // t_ref と _t が等しければ false をリターン. それ以外で，(_t - t_cyc) が
  // t_last より後なら，true を返す.
  // -----
  if ( t_ref == _t ) return false ;
  double tx = _t - t_cyc ;
  return t_last < tx ;
}



// -----
// Get data.
// データを得る.
// -----
const SubstationControlData_VI &
Substation_Control_VI_TS :: getData
( double _t )
  const
{
  if ( t_ref == _t ) return _current -> getData () ;

  if ( ! timeIsInRegion ( _t ) )
  {
    cerr << "ERROR: _t out of range in Substation_Control_VI_TS::getData(...)"
         << endl ;
    exit ( 1 ) ;
  }
  if ( _current -> isInSection ( _t ) )
  {
    t_ref = _t ;
    return _current -> getData () ;
  }
  vector < VISection > :: const_iterator _cur_bk = _current ;
  bool sw_x = false ;
  while ( _cur_bk -> isBeforeSection ( _t ) )
  {
    -- _cur_bk ;
    sw_x = true ;
  }
  while ( _cur_bk -> isAfterSection ( _t ) )
  {
    if ( sw_x )
    {
      cerr
        << "ERROR: internal error in Substation_Control_VI_TS::getData(...)"
        << endl ;
      exit ( 1 ) ;
    }
    ++ _cur_bk ;
  }
  t_ref = _t ;
  _current = _cur_bk ;
  return _current -> getData () ;
}
