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

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <deque>
#include <algorithm>

#include "nextsta.hh"
#include "rtss_iconv.hh"

using std :: cerr ;
using std :: endl ;
using std :: ostringstream ;
using std :: setprecision ;
using std :: fixed ;
using std :: deque ;
using std :: sort ;



//#define DEBUG



// 代入演算子の overload
gradcrv &
gradcrv :: operator=
( const gradcrv & x )
{
  if ( & x == this )
    return * this ;
  _GCV_Container :: substitute ( x ) ;
  return * this ;
}




// gcvel の追加
gradcrv &
gradcrv :: operator+=
( gcvel const & x )
{
  if ( gc_size () > 0 )
  {
    if ( getElement ( gc_size () - 1 ) . endp != x . stp )
    {
      cerr << "Error: gcvel data not continuous in a gradcrv object" << endl ;
      cerr << " endp: " << getElement ( gc_size () - 1 ) . endp
           << ", stp: " << x . stp << ", gc_size: "
           << gc_size () << endl ;
      exit ( 31 ) ;	// gcvel データ不連続エラー
    }
  }
  if ( x . stp > x . endp )
  {
    cerr << "Error: gcvel data not correct" << endl ;
    exit ( 32 ) ;   // gcvel データ不連続エラー
  }
  gc_push_back ( x ) ;
  return * this ;
}




// gcvel データ書替え
gradcrv &
gradcrv :: renewpos
( int sw ,
  double zpost )
{
  //**********************************************************
  // 返り値が参照でないためこの関数は operator[] を使うとダメ
  //**********************************************************
  double sgn ;
  if ( sw < 0 )
  {
    // このときは gcvel を逆順に並べ替える
    static _GCV_Container gxold ;
    gxold . gc_renew () ;
    for ( gc_size_type i = 0 ; i < gc_size () ; ++ i )
    {
      gxold . gc_push_back ( getElement ( i ) ) ;
    }
    for ( gc_size_type i = 0 ; i < gc_size () ; ++ i )
    {
      getElement ( i ) = gxold . getElement ( gc_size () - i ) ;
      double tmp = getElement ( i ) . stp ;
      getElement ( i ) . stp = getElement ( i ) . endp ;
      getElement ( i ) . endp = tmp ;
    }
    sgn = - 1 ;
  }
  else
    sgn = 1 ;
  for ( gc_size_type i = 0 ; i < gc_size () ; ++ i )
  {
    // zpost 起点の距離に
    getElement ( i ) . stp -= zpost ;
    getElement ( i ) . endp -= zpost ;
    getElement ( i ) . stp *= sgn ;
    getElement ( i ) . endp *= sgn ;
  }
  return * this ;
}




// 二つの gradcrv を連結
gradcrv &
operator+
( gradcrv & a ,
  gradcrv & b )
{
  static gradcrv x , y , z ;
  if ( a . gc_size () > 0 )
  {
    if ( a . getElement( a . gc_size () - 1 ) . endp
         != b . getElement ( 0 ) . stp )
    {
      cerr << "Error: gcvel data not continuous" << endl ;
      exit ( 32 ) ;	// データ不連続エラー
    }

    // メモリコピー
    x = a ;
    y = b ;
    z . gc_renew ( x . gc_size () + y . gc_size () ) ;
    z = x ;
    for ( gradcrv :: gc_size_type i = 0 ; i < y . gc_size () ; ++ i )
      z += y . getElement ( i ) ;
  }
  else
    z = b ;
  return z ;
}




// ファイルリード
int
gradcrv :: readfile
( FILE * gpoint )
{
  if ( getcommand ( gpoint , false ) == EOF )
    return EOF ;
  if ( strcmp ( tmpch , "gcvel" ) != 0 )
    return EOF ;
  int sia ;
  if ( getint ( gpoint , sia ) == EOF )
    return EOF ;
  l_ofs << "gradcrv: " << sia << " gcvel data" << endl ;
  gc_renew ( sia ) ;
  gcvel gv ;
  for ( int j = 0 ; j < sia ; ++ j )
  {
    if ( gettwodbls ( gpoint , gv . stp , gv . endp ) == EOF )
      return EOF ;
    if ( getthreedbls ( gpoint , gv . grad , gv . curve , gv . vlimit )
	 == EOF )
      return EOF ;
    ostringstream cx ;
    cx . clear () ;
    cx . str ( "" ) ;
    cx << fixed << setprecision ( 3 ) << gv . stp << " " << gv . endp << " "
       << setprecision ( 1 ) << gv . grad << " " << gv . curve << " "
       << gv . vlimit ;
    l_ofs << cx . str () << endl ;
    operator+= ( gv ) ;
  }
  return 1 ;
}



// ----
// Class for reading XML G file
// ----
struct _G_Data_Pointer
{
  _TrackProfileDataSet :: const_iterator _x ;
  _TrackProfileDataSet :: const_iterator _g ;
  _TrackProfileDataSet :: const_iterator _c ;
  _TrackProfileDataSet :: const_iterator _v ;
} ;

class _Sort_G_Data
{
public :
  bool operator () ( _G_Data_Pointer const & a ,
                     _G_Data_Pointer const & b ) const
  { return a . _x -> getStartOfSection () < b . _x -> getStartOfSection () ; }
} ;




// ----
// Constructor using a TiXmlNode.
// ----
gradcrv :: gradcrv
( TiXmlNode const * tn_in )
{
  // -----
  // The TiXmlNode argument here will be of tag "gradcrv_data_set".
  // This tag must have, as an only attribute, the name of this data set.
  // Also, "gradient", "curvrature" and "speed_restriction" tags must
  // appear as subdata.
  // ここで与えられる TiXmlNode 型の引数は "gradcrv_data_set" タグである。
  // このタグは，唯一の属性としてこのデータセットの名前が指定される。また，
  // 子データとして "gradient", "curvature" および "speed_restriction" タ
  // グが指定されなければならない。
  // -----
  string tnin_val = string ( tn_in -> Value () ) ;
  if ( tnin_val != "gradcrv_data_set" )
  {
    cerr << "Error: \"" << tnin_val
         << "\" tag given to function elecchar::readfile_xml(...)." << endl ;
    exit ( 1 ) ;
  }

  // -----
  // Get the name of this gradcrv data set.
  // この gradcrv データセット名を得る。
  // -----
  TiXmlAttribute const * attr = tn_in -> ToElement () -> FirstAttribute () ;
  while ( attr )
  {
    if ( string ( attr -> Name () ) == "name" )
    {
      // Attribute "name"
      string name_utf8 = attr -> ValueStr () ;
#ifdef SJIS_ICONV
      // Enable this on Japanese Windows environment only
      iconv_t ixx = iconv_open ( "SHIFT_JIS" , "UTF-8" ) ;
      if ( ixx == ( iconv_t ) ( - 1 ) )
      {
        cerr << "ERROR: ICONV initialisation failed" << endl ;
        exit ( 1 ) ;
      }
      string :: size_type len = name_utf8 . length () ;
      char * buf_out = new char [ len + 1 ] ;
      convertFromUTF8ToSJIS ( name_utf8 . c_str () , buf_out , len ) ;
      name_sjis = string ( buf_out ) ;
      delete [] buf_out ;
#else
      name_sjis = name_utf8 ;
#endif // SJIS_ICONV
      setName ( name_utf8 ) ;
      setNameSjis ( name_sjis ) ;
    }
    else
    {
      cerr << "ERROR: tag <gradcrv_data_set> with incorrect attribute "
           << attr -> Name () << endl ;
      exit ( 1 ) ;
    }
    attr = attr -> Next () ;
  }

  // -----
  // Process subdata.
  // 子データを処理する。
  // -----
  bool sw_grad = true ;
  bool sw_curve = true ;
  bool sw_vlimit = true ;
  _ds_g = 0 ;
  _ds_c = 0 ;
  _ds_v = 0 ;
  sw_ref_g = false ;
  sw_ref_c = false ;
  sw_ref_v = false ;
  name_ref_g = "" ;
  name_ref_c = "" ;
  name_ref_v = "" ;

  for ( const TiXmlNode * tn_ch = tn_in -> FirstChild () ;
        tn_ch ; tn_ch = tn_ch -> NextSibling () )
  {
    // -----
    // Ignore non-Element node.
    // エレメント以外は無視。
    // -----
    if ( tn_ch -> Type () != TiXmlNode :: TINYXML_ELEMENT )
      continue ;

    // -----
    // Check tag name.
    // タグ名チェック。
    // -----
    string tnch_val = string ( tn_ch -> Value () ) ;
    if ( tnch_val == "gradient" )
    {
      if ( ! sw_grad )
      {
        cerr << "ERROR: multiple <gradient> tags in tag <gradcrv_data_set>"
             << endl ;
        exit ( 1 ) ;
      }

      // -----
      // Processing <gradient> tag, which has either one or more <data>
      // subtags or an attribute called "ref".
      // <gradient> タグを処理. このタグは1つまたはそれ以上の <data> 子タ
      // グ，もしくは属性 ref を持っている。
      // -----
      TiXmlAttribute const *
        _ga = tn_ch -> ToElement () -> FirstAttribute () ;
      while ( _ga )
      {
        if ( string ( _ga -> Name () ) == "ref" )
        {
          // Attribute "name"
          sw_ref_g = true ;
          name_ref_g = _ga -> ValueStr () ;
        }
        else
        {
          cerr << "Error: tag <" << tnch_val << "> with incorrect attribute "
               << _ga -> Name () << endl ;
          exit ( 1 ) ;
        }
        _ga = _ga -> Next () ;
      }
      if ( ! sw_ref_g )
      {
        _ds_g = new _TrackProfileDataSet ( tn_ch ) ;
        if ( ! _ds_g )
        {
          cerr << "Error: memory allocation failed in creating a new "
               << "_TrackProfileDataSet object for tag <gradient>" << endl ;
          exit ( 1 ) ;
        }
      }
      sw_grad = false ;
    }
    else if ( tnch_val == "curvature" )
    {
      if ( ! sw_curve )
      {
        cerr << "ERROR: multiple <curvature> tags in tag <gradcrv_data_set>"
             << endl ;
        exit ( 1 ) ;
      }

      // -----
      // Processing <curvature> tag, which has either one or more <data>
      // subtags or an attribute called "ref".
      // <curvature> タグを処理. このタグは1つまたはそれ以上の <data> 子タ
      // グ，もしくは属性 ref を持っている。
      // -----
      TiXmlAttribute const *
        _ca = tn_ch -> ToElement () -> FirstAttribute () ;
      while ( _ca )
      {
        if ( string ( _ca -> Name () ) == "ref" )
        {
          // Attribute "name"
          sw_ref_c = true ;
          name_ref_c = _ca -> ValueStr () ;
        }
        else
        {
          cerr << "Error: tag <" << tnch_val << "> with incorrect attribute "
               << _ca -> Name () << endl ;
          exit ( 1 ) ;
        }
        _ca = _ca -> Next () ;
      }
      if ( ! sw_ref_c )
      {
        _ds_c = new _TrackProfileDataSet ( tn_ch ) ;
        if ( ! _ds_c )
        {
          cerr << "Error: memory allocation failed in creating a new "
               << "_TrackProfileDataSet object for tag <curvature>" << endl ;
          exit ( 1 ) ;
        }
      }
      sw_curve = false ;
    }
    else if ( tnch_val == "speed_restriction" )
    {
      if ( ! sw_vlimit )
      {
        cerr << "ERROR: multiple <speed_restriction> tags in tag "
             << "<gradcrv_data_set>" << endl ;
        exit ( 1 ) ;
      }

      // -----
      // Processing <speed_restriction> tag, which has either one or more
      // <data> subtags or an attribute called "ref".
      // <speed_restriction> タグを処理. このタグは1つまたはそれ以上の
      // <data> 子タグ，もしくは属性 ref を持っている。
      // -----
      TiXmlAttribute const *
        _va = tn_ch -> ToElement () -> FirstAttribute () ;
      while ( _va )
      {
        if ( string ( _va -> Name () ) == "ref" )
        {
          // Attribute "name"
          sw_ref_v = true ;
          name_ref_v = _va -> ValueStr () ;
        }
        else
        {
          cerr << "Error: tag <" << tnch_val << "> with incorrect attribute "
               << _va -> Name () << endl ;
          exit ( 1 ) ;
        }
        _va = _va -> Next () ;
      }
      if ( ! sw_ref_v )
      {
        _ds_v = new _TrackProfileDataSet ( tn_ch ) ;
        if ( ! _ds_v )
        {
          cerr << "Error: memory allocation failed in creating a new "
               << "_TrackProfileDataSet object for tag <speed_restriction>"
               << endl ;
          exit ( 1 ) ;
        }
      }
      sw_vlimit = false ;
    }
    else if ( tnch_val == "three_data" )
    {
      if ( ! ( sw_grad && sw_curve && sw_vlimit ) )
      {
        cerr << "ERROR: <three_data> tag must not coincide with other "
             << "<three_data>, <gradient>, <curvature> or <speed_restriction> "
             << "tags in <gradcrv_data_set>" << endl ;
        exit ( 1 ) ;
      }

      // -----
      // Processing <three_data> tag, which has either one or more
      // <data> subtags.
      // <three_data> タグを処理. このタグは1つまたはそれ以上の
      // <data> 子タグを持っている。
      // -----
      _ds_g = new _TrackProfileDataSet ( tn_ch , GRADIENT ) ;
      if ( ! _ds_g )
      {
        cerr << "Error: memory allocation failed in creating a new "
             << "_TrackProfileDataSet object with gradient data for tag "
             << "<three_data>"
             << endl ;
        exit ( 1 ) ;
      }
      sw_grad = false ;
      _ds_c = new _TrackProfileDataSet ( tn_ch , CURVATURE ) ;
      if ( ! _ds_c )
      {
        cerr << "Error: memory allocation failed in creating a new "
             << "_TrackProfileDataSet object with curvature data for tag "
             << "<three_data>"
             << endl ;
        exit ( 1 ) ;
      }
      sw_curve = false ;
      _ds_v = new _TrackProfileDataSet ( tn_ch , SPEED_RESTRICTION ) ;
      if ( ! _ds_v )
      {
        cerr << "Error: memory allocation failed in creating a new "
             << "_TrackProfileDataSet object with speed restriction data "
             << "for tag <three_data>"
             << endl ;
        exit ( 1 ) ;
      }
      sw_vlimit = false ;
    }
  }
  if ( sw_grad || sw_curve || sw_vlimit )
  {
    cerr << "ERROR: one or more of tags <gradient>, <curvature> or "
         << "<speed_restriction> missing in tag <gradcrv_data_set>" << endl ;
    exit ( 1 ) ;
  }

  cerr << "Gradcrv data set " << name_sjis << " read all done." << endl ;
}



// ----
// Copy "referenced" data, do data checks, and convert data.
// ----
void
gradcrv :: getReferencedXmlDataSetsAndConvert
( map < string , vector < gradcrv * > :: size_type > const & _gcv ,
  vector < gradcrv * > const & vec_gcv )
{
  cerr << "Now check data and converting to original data structure: name = "
       << getNameSjis () << endl ;
  l_ofs << "Gradcrv data set name: " << name_sjis << endl ;

  // ----
  // Copying data.
  // ----
  if ( sw_ref_g )
  {
    map < string , vector < gradcrv * > :: size_type > :: const_iterator
      _ig = _gcv . find ( name_ref_g ) ;
    if ( _ig == _gcv . end () )
    {
      cerr << "Error: no reference gradcrv data set named \"" << name_ref_g
           << "\" found in the search for gradient data" << endl ;
      exit ( 1 ) ;
    }
    if ( _ds_g )
    {
      cerr << "Error: gradient data already set while reference searched"
           << endl ;
      exit ( 1 ) ;
    }
    _TrackProfileDataSet const *
      _g_ref = vec_gcv [ _ig -> second ] -> getGradientDataSet () ;
    if ( ! _g_ref )
    {
      cerr << "Error: reference gradcrv data set named \"" << name_ref_g
           << "\" found but gradient data is empty" << endl ;
      exit ( 1 ) ;
    }
    _ds_g = new _TrackProfileDataSet ( * _g_ref ) ;
  }

  if ( sw_ref_c )
  {
    map < string , vector < gradcrv * > :: size_type > :: const_iterator
      _ic = _gcv . find ( name_ref_c ) ;
    if ( _ic == _gcv . end () )
    {
      cerr << "Error: no reference gradcrv data set named \"" << name_ref_c
           << "\" found in the search for curvature data" << endl ;
      exit ( 1 ) ;
    }
    if ( _ds_c )
    {
      cerr << "Error: curvature data already set while reference searched"
           << endl ;
      exit ( 1 ) ;
    }
    _TrackProfileDataSet const *
      _c_ref = vec_gcv [ _ic -> second ] -> getCurvatureDataSet () ;
    if ( ! _c_ref )
    {
      cerr << "Error: reference gradcrv data set named \"" << name_ref_c
           << "\" found but curvature data is empty" << endl ;
      exit ( 1 ) ;
    }
    _ds_c = new _TrackProfileDataSet ( * _c_ref ) ;
  }

  if ( sw_ref_v )
  {
    map < string , vector < gradcrv * > :: size_type > :: const_iterator
      _iv = _gcv . find ( name_ref_v ) ;
    if ( _iv == _gcv . end () )
    {
      cerr << "Error: no reference gradcrv data set named \"" << name_ref_v
           << "\" found in the search for speed restriction data" << endl ;
      exit ( 1 ) ;
    }
    if ( _ds_v )
    {
      cerr << "Error: speed restriction data already set "
           << "while reference searched" << endl ;
      exit ( 1 ) ;
    }
    _TrackProfileDataSet const *
      _v_ref = vec_gcv [ _iv -> second ] -> getSpeedRestrictionDataSet () ;
    if ( ! _v_ref )
    {
      cerr << "Error: reference gradcrv data set named \"" << name_ref_v
           << "\" found but speed restriction data is empty" << endl ;
      exit ( 1 ) ;
    }
    _ds_v = new _TrackProfileDataSet ( * _v_ref ) ;
  }

  // ----
  // Data check: If the beginning and end of all data are equal...
  // ----
  if ( _ds_g -> getStartPosition () != _ds_c -> getStartPosition ()
       || _ds_c -> getStartPosition () != _ds_v -> getStartPosition ()
       || _ds_g -> getEndPosition () != _ds_c -> getEndPosition ()
       || _ds_c -> getEndPosition () != _ds_v -> getEndPosition () )
  {
    cerr << "ERROR: subtags <gradient>, <curvature> or <speed_restriction> "
         << "with different start and/or end positions in tag "
         << "<gradcrv_data_set>" << endl ;
    exit ( 1 ) ;
  }

  // ----
  // Converting data _ds_g, _ds_c and _ds_v to "original" gcvel vector.
  // ----
  vector < _G_Data_Pointer > _gdp ;
  _gdp . clear () ;
  _gdp . reserve ( _ds_g -> size () + _ds_c -> size () + _ds_v -> size () ) ;
  gc_renew ( _ds_g -> size () + _ds_c -> size () + _ds_v -> size () ) ;

  for ( _TrackProfileDataSet :: const_iterator ii = _ds_g -> begin () ;
        ii != _ds_g -> end () ; ++ ii )
  {
    _G_Data_Pointer _gx ;
    _gx . _x = _gx . _g = ii ;
    _gx . _c = _ds_c -> end () ;
    _gx . _v = _ds_v -> end () ;
    _gdp . push_back ( _gx ) ;
  }

  for ( _TrackProfileDataSet :: const_iterator ii = _ds_c -> begin () ;
        ii != _ds_c -> end () ; ++ ii )
  {
    _G_Data_Pointer _gx ;
    _gx . _x = _gx . _c = ii ;
    _gx . _g = _ds_g -> end () ;
    _gx . _v = _ds_v -> end () ;
    _gdp . push_back ( _gx ) ;
  }

  for ( _TrackProfileDataSet :: const_iterator ii = _ds_v -> begin () ;
        ii != _ds_v -> end () ; ++ ii )
  {
    _G_Data_Pointer _gx ;
    _gx . _x = _gx . _v = ii ;
    _gx . _g = _ds_g -> end () ;
    _gx . _c = _ds_c -> end () ;
    _gdp . push_back ( _gx ) ;
  }

  sort ( _gdp . begin () , _gdp . end () , _Sort_G_Data () ) ;

  _G_Data_Pointer _gx ;
  _gx . _g = _ds_g -> end () ;
  _gx . _c = _ds_c -> end () ;
  _gx . _x = _gx . _v = _ds_v -> end () ;
  for ( vector < _G_Data_Pointer > :: iterator ii = _gdp . begin () ;
        ii != _gdp . end () ; ++ ii )
  {
    if ( _gx . _g != _ds_g -> end ()
         && _gx . _c != _ds_c -> end ()
         && _gx . _v != _ds_v -> end ()
         && _gx . _x != _ds_g -> end ()
         && _gx . _x != _ds_c -> end ()
         && _gx . _x != _ds_v -> end ()
         && ( _gx . _x -> getStartOfSection ()
              <= ii -> _x -> getStartOfSection () - INVLIM ) )
    {
      gcvel gv ;
      gv . stp = _gx . _x -> getStartOfSection () ;
      gv . endp = ii -> _x -> getStartOfSection () ;
      gv . grad = _gx . _g -> getData () . _v ;
      gv . curve = _gx . _c -> getData () . _v ;
      gv . vlimit = _gx . _v -> getData () . _v ;
      ostringstream cx ;
      cx . clear () ;
      cx . str ( "" ) ;
      cx << fixed << setprecision ( 3 ) << gv . stp << " " << gv . endp
         << " " << setprecision ( 1 ) << gv . grad << " " << gv . curve
         << " " << gv . vlimit ;
      l_ofs << cx . str () << endl ;
      operator+= ( gv ) ;
    }
    if ( _gx . _x == _ds_g -> end ()
         || _gx . _x == _ds_c -> end ()
         || _gx . _x == _ds_v -> end ()
         || ( _gx . _x -> getStartOfSection ()
              <= ii -> _x -> getStartOfSection () - INVLIM ) )
    {
      _gx . _x = ii -> _x ;
    }
    if ( ii -> _g != _ds_g -> end () )
    {
      _gx . _g = ii -> _g ;
    }
    if ( ii -> _c != _ds_c -> end () )
    {
      _gx . _c = ii -> _c ;
    }
    if ( ii -> _v != _ds_v -> end () )
    {
      _gx . _v = ii -> _v ;
    }
  }
  gcvel gv ;
  gv . stp = _gx . _x -> getStartOfSection () ;
  gv . endp = _ds_g -> getEndPosition () ;
  gv . grad = _gx . _g -> getData () . _v ;
  gv . curve = _gx . _c -> getData () . _v ;
  gv . vlimit = _gx . _v -> getData () . _v ;
  ostringstream cx ;
  cx . clear () ;
  cx . str ( "" ) ;
  cx << fixed << setprecision ( 3 ) << gv . stp << " " << gv . endp
     << " " << setprecision ( 1 ) << gv . grad << " " << gv . curve
     << " " << gv . vlimit ;
  l_ofs << cx . str () << endl ;
  operator+= ( gv ) ;
}



// -----
// Constructor of class _TrackProfileDataElement using an XML attribute
// _TrackProfileDataElement クラスを1つのXML属性で初期化する
// -----
_TrackProfileDataElement :: _TrackProfileDataElement
( _TrackProfileDataElement :: Init const & 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 ) ;
}



// -----
// Constructor of class _TrackProfileDataSet using a TiXmlNode
// _TrackProfileDataSet クラスを TiXmlNode ひとつで初期化する
// -----
_TrackProfileDataSet :: _TrackProfileDataSet
( TiXmlNode const * _ch ,
  _TPDS_Switch _tsw /* = THREE_DATA */ )
{
  // -----
  // The argument _ch must have a "root" element, which has one or more
  // <data> subtags. No check of _ch is done here.
  // Getting child elements of _ch.
  // 引数 _ch には <data> タグを子タグとしてひとつまたはそれ以上含む親要素
  // がなければならない。_ch のチェックはここではしない。
  // _ch の子を取得.
  // -----
  bool sw_first = true ;
  double _end_pre = 0 ;
  for ( TiXmlNode const * _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 != "data" )
    {
      cerr << "Error: \"" << _cc_val << "\" tag not allowed as child of <"
           << _ch -> ValueStr () << ">." << endl ;
      exit ( 1 ) ;
    }
    double _st = 0 ;
    bool _sw_st = true ;
    double _end = 0 ;
    bool _sw_end = true ;
    TiXmlAttribute const * _v = 0 ;
    bool _sw_v = true ;
    for ( TiXmlAttribute const * attr
            = _cc -> ToElement () -> FirstAttribute () ;
          attr ; attr = attr -> Next () )
    {
      // -----
      // Get start and end positions.
      // 開始・終了位置を取得.
      // -----
      if ( string ( attr -> Name () ) == "from" )
      {
        _sw_st = false ;
        sscanf ( attr -> Value () , "%lf" , & _st ) ;
      }
      else if ( string ( attr -> Name () ) == "to" )
      {
        _sw_end = false ;
        sscanf ( attr -> Value () , "%lf" , & _end ) ;
      }
      else if ( ( _tsw == THREE_DATA
                  && string ( attr -> Name () ) == "value" )
                || ( _tsw == GRADIENT
                     && string ( attr -> Name () ) == "gradient" )
                || ( _tsw == CURVATURE
                     && string ( attr -> Name () ) == "curvature" )
                || ( _tsw == SPEED_RESTRICTION
                     && string ( attr -> Name () ) == "speed_restriction" ) )
      {
        _sw_v = false ;
        _v = attr ;
      }
      else if ( _tsw != THREE_DATA &&
                ( string ( attr -> Name () ) == "gradient"
                  || string ( attr -> Name () ) == "curvature"
                  || string ( attr -> Name () ) == "speed_restriction" ) )
      {
        continue ;
      }
      else
      {
        cerr << "ERROR: subtag <data> in tag <" << _ch -> ValueStr ()
             << "> with incorrect attribute "
             << attr -> Name () << endl ;
        exit ( 1 ) ;
      }
    }
    if ( _sw_st || _sw_end || _sw_v )
    {
      cerr << "ERROR: subtag <data> in tag <" << _ch -> ValueStr ()
           << "> incorrect" << endl ;
      exit ( 1 ) ;
    }
    if ( ! ( sw_first || _end_pre == _st ) )
    {
      cerr << "ERROR: gap between data in tag <" << _ch -> ValueStr ()
           << ">" << endl ;
      exit ( 1 ) ;
    }
    if ( _st >= _end )
    {
      cerr << "ERROR: section length must be positive in tag <"
           << _ch -> ValueStr () << ">" << endl ;
      exit ( 1 ) ;
    }
    _TrackProfileDataElement :: Init _vi ;
    _vi . _v = _v ;

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

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