// This may look like C code, but it is really -*- C++ -*-
// RTSS --- Railway Total System Simulator
// (c) TAKAGI Ryo (at Kogakuin University)
// nextsta.hh --- class nextsta and related classes and structs
// -----
// ChangeLog:
// 2007. 11. 22
//  Removed fprintf(...).
// -----

#include "globvar.hh"
#include "readdata.hh"
#include "enumerat.hh"
#include "stnobj.hh"
#include "tinyxml.h"

#include <vector>
#include <iostream>
#include <stdexcept>

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



#ifndef ___NEXTSTA_HH
#define ___NEXTSTA_HH		// こうしておくと2度インクルードしても大丈夫！


// ----
// Forward declaration of class SOC_FeedForward_Data.
// SOC_FeedForward_Data クラスの前方宣言.
// ----
class SOC_FeedForward_Data ;


// 勾配・曲線・制限速度データ
struct gcvel
{
  double stp ; 	// 区間開始地点
  double endp ;	// 区間終了地点 ; endp > stp
  double grad ;	// 勾配（direc = 1 に対する登りパーミル）
  double curve ;	// 曲線半径
  double vlimit ;	// 制限速度

  gcvel () : stp ( 0 ) , endp ( 0 ) , grad ( 0 ) , curve ( 0 ) , vlimit ( 0 )
  {}
} ;



// ----
// Replacement to NoRefTable
// ----
class _GCV_Container
  : private vector < gcvel >
{
public :
  typedef size_type gc_size_type ;
  typedef iterator gc_iterator ;

  gc_iterator gc_begin () { return begin () ; }
  gc_iterator gc_end () { return end () ; }
  gc_size_type gc_size () const { return size () ; }
  void gc_push_back ( gcvel x ) { push_back ( x ) ; }

  _GCV_Container & substitute ( _GCV_Container const & x )
  { return operator= ( x ) ; }

  gcvel & getElement ( gc_size_type i )
  { try { return at ( i ) ; } catch ( std :: out_of_range )
    { cerr << "Error: subscript out of range (_GCV_Container)" << endl ;
      exit ( 26 ) ; } }
  
  gcvel const & getElement ( gc_size_type i ) const
  { try { return at ( i ) ; } catch ( std :: out_of_range )
    { cerr << "Error: subscript out of range (_GCV_Container)" << endl ;
      exit ( 26 ) ; } }

  void gc_renew () { clear () ; }
  void gc_renew ( gc_size_type ix ) { clear () ; reserve ( ix ) ; }

  _GCV_Container () : vector < gcvel > () {}
  _GCV_Container ( _GCV_Container const & x ) : vector < gcvel > ( x ) {}

} ;

  

// 駅間の勾配曲線に関するデータ
class gradcrv
  : public _GCV_Container ,
    public readdata
{

public :
  // constructor
  gradcrv () : _GCV_Container () {}

  // constructor: X(X&)
  gradcrv ( gradcrv const & x ) : _GCV_Container ( x ) {}

  // destructor は定義しない

  // 代入用演算子のオーバーロード
  gradcrv & operator= ( gradcrv const & ) ;

  // gcvel の追加（データチェック付）
  gradcrv & operator+= ( gcvel const & ) ;

  // gcvel データの書替
  gradcrv & renewpos ( int , double ) ;

  // ファイルリード
  int readfile ( FILE * ) ;
  
} ;



// 2つつなげる（friend 不要）
gradcrv & operator+ ( gradcrv & , gradcrv & ) ;


class feeder ;
class diapattern ;



// 次の駅までの走行に関するデータ
class nextsta
  : public gradcrv
{

private :

// 変数
  int direc ;  	// 列車方向
  double startp ;	// 出発点
  double arp ;		// 到達点
  double arv ; 	// 目標速度, nxp = Pass_station 時 nonzero 可
  double art ;		// 到達時間
  int nfline ;  	// 饋電線番号
  nextsta_pattern nxp ;	// 次駅情報の切替方法
  double tstop ;	// 駅停車時間
  double vnoff ;	// ノッチオフ速度（一応いれとくが使わないだろ）
  int ndpt ;	// diapattern の番号
  int ndp ;	// diapattern 配列内の番号
  double nextsw ;	// 次のデータに切替える点

  // isnextsw added 1997.10.6 to work around bug in
  // checking of twhole in dpt-rf.cc --- RT
  bool isnextsw ;	// nextsw を指定した場合に true
  nextsta * nxx ;	// 次の次駅データ
  double bufcont ;	// 余裕時分調整変数

  dp_command dcmd ;	// 制御用変数
  double conges ;	// 混雑率 g_sw_conges_station が true のときのみ有効

  // station_obj はポインタで格納
  station_obj * x_stnobj ;	// この次駅データによって到着すべき駅
  int n_stnobj ;	// stnobj が持つべき station_obj の番号
  int voie ;		// 入るべき番線
  int ilno ;		// 駅にアプローチする線路の番号
  int olno ;		// 駅を出る線路の番号
  int notrw ;		// 駅で待つべき列車数
  bool is_pass ;	// 通過列車であれば true

  // *********************************************************************
  // Mutables / const メンバ関数から変更可能な変数群
  // *********************************************************************

  // pfi 回目の力行/回生のみ までは駅間走行時分を狂わせる
  mutable double pfcont ;

  // 走行時分合わせをした回数
  mutable int pfi ;

  // この区間は最初から ontime_prec で時間合わせ
  mutable bool ontprec ;

  // prt: 力行率, setprt: 力行率セットしたら true
  mutable double prt ;
  mutable bool setprt ;


  // この変数初期化・代入の必要なし
  vector < gc_size_type > greq_gnum ;		// gradcrv 配列のなかの番号
  vector < int > greq_renposf ; 	// renewpos のためのフラグ
  vector < double > greq_gzpos ;	// renewpos のための更新起点距離
  int greq_x ;				// 要求制御、最初はゼロ

  // この変数は将来 copy コマンドが機能できるようになったときのため
  bool sw_nreq ;	// readfile で copy を指定したか？
  int nreq_kz ;	// copy のための変数 (ndpt)
  int nreq_kx ;	// 同上              (ndp)

  // ----
  // SOC curve related.
  // SOCカーブ関連.
  // ----
  SOC_FeedForward_Data const * _soc ;
  string _soc_name ;
  bool _wants_soc ;

  // 関数

  // ----
  // Stepping forward in gcvel vector.
  // gcvel ベクトルにおける1個前進.
  // ----
  bool fpgrad ( gc_size_type & ) const ;

  // ----
  // Stepping backward in gcvel vector.
  // gcvel ベクトルにおける1個後進.
  // ----
  bool bpgrad ( gc_size_type & ) const ;
  // 勾配データ配列上の現在位置の前進(f)/後退(b)

  void chkdirec () const {		// 列車方向設定確認ルーチン
    if ( direc != 1 && direc != - 1 ) {
      cerr << "Error: int direc must be 1 or -1" << endl ;
      exit ( 15 ) ;	// error 15: 方向設定エラー
    }
  }

public :

// 関数
//	nextsta(int) ;		// constructor: gxx の個数が (int)
  nextsta ( nextsta & ) ;		// constructor: 初期化用
  nextsta () ;				// empty constructor
  ~nextsta () { nxx = 0 ; }	// destructor
  nextsta & operator= ( nextsta const & ) ;
  nextsta & operator= ( gradcrv const & ) ;  	// 代入用演算子のオーバーロード

  // ----
  // Reading the input file.
  // ファイルの読み込み.
  // ----
  int readfile ( FILE * , char * ) ;
  bool readfile_xml ( TiXmlNode const * ) ;	// XML node

  // ８変数の代入ないしは初期化
  void setvar
  ( double , int , double , double , double , int , double , double) ;

  // ----
  // The first three of the below "set" functions use "mutable" variables
  // 以下の変数セット用関数の最初の3つは mutable な変数を使用する
  // ----
  void setpf ( double x , int i ) const { pfcont = x ; pfi = i ; }
  void prate ( double x ) const { prt = x ; setprt = true ; }
  void set_ontprec () const { ontprec = true ; }
  void set_ndp ( int n ) { ndp = n ; }		// ndp のセット
  void set_ndpt ( int n ) { ndpt = n ; }	// ndpt のセット
  void prtreset () { setprt = false ; }
  void prtinit () { prtreset () ; prt = bufcont = pfcont = 0.0 ; }
  void setbuf ( double x ) { bufcont += x ; }
  void setdc ( dp_command x ) { dcmd = x ; }
  void set_nextnxx ( nextsta * x ) { nxx = x ; }
  void set_stnobj ( station_obj * x ) { x_stnobj = x ; }

  // greq_* の中身を返す。bool 返り値は，あれば true, なくなれば false
  bool get_greq ( gc_size_type & , int & , double & ) ;

  // 勾配データ配列上の現在位置決定
  gc_size_type dpgrad ( double ) const ;

  // 勾配データ配列上の現在位置合わせ
  void adjpgrad ( gc_size_type & , double ) const ;

  void arv_pass () ;			// arv の処理

  void push_to_station ( to_station ) ;		// to_station オブジェクト
  void push_to_station_init ( to_station ) ;	// を station_obj に
  void push_from_station_init ( from_station ) ;
			// from_station オブジェクトを station_obj に
  double tarr_delay ( const train * ) const ;	// 信号系から指示される遅れ時分

  bool prtset () const { return setprt ; }
  double bufdiff () const { return bufcont ; }
  double prate () const { return prt ; }
  double congestion () const { return conges ; }
  bool get_ontprec () const { return ontprec ; }

  // isnextswitch() added 1997.10.6 to work around bug in
  // checking of twhole in dpt-rf.cc
  bool isnextswitch () const { return isnextsw ; }
  double nextswitch () const { return nextsw ; }
  double parrive () const { return arp ; }
  double varrive () const { return arv ; }
  double tarrive () const { return art ; }
  double tarrive ( int ) const ;	// ontime 決定用, 少し変える
  double tarrive ( bool ) const ;	// setbuf 用、さらに少し変える
  nextsta_pattern nxxptn () const { return nxp ; }
  double stoptime () const { return tstop ; }
  double pstart () const { return startp ; }
  nextsta * nextnxx () { return nxx ; }
  nextsta const * nextnxx () const { return nxx ; }
  station_obj * stnobj () const { return x_stnobj ; }
  int feedlinenumber () const { return nfline ; }
  int direction () const { return direc ; }
  int dptnum () const { return ndpt ; }
  int stnobjnum () const { return n_stnobj ; }
  int voienum () const { return voie ; }
  int ilinenum () const { return ilno ; }
  int olinenum () const { return olno ; }
  int trwaitnum () const { return notrw ; }
  bool pass_stn () const { return is_pass ; }
  int dpttbl () const { return ndp ; }		// 変数参照用
  gc_size_type dqgrad () const {	// 勾配データの配列上の終点駅位置
    chkdirec () ;
    if ( direc == 1 ) return ( gc_size () - 1 ) ;
    if ( direc == - 1 ) return 0 ;
  }
  gc_size_type dsgrad () const {	// 勾配データの配列上の起点駅位置
    chkdirec () ;
    if ( direc == 1 ) return 0 ;
    if ( direc == - 1 ) return ( gc_size () - 1 ) ;
  }
  void fwpgrad ( gc_size_type & zz ) const { chkdirec () ; fpgrad ( zz ) ; }
  void bkpgrad ( gc_size_type & zz ) const { chkdirec () ; bpgrad ( zz ) ; }
		// 勾配データ配列上の現在位置の前進(fw)/後退(bk)

  double epoint ( gc_size_type pgrad ) const {	// データ終了地点を返す
    chkdirec () ;
    if ( direc == 1 )
      return getElement ( pgrad ) . endp ;	// direc= 1 なら endp
    else return getElement ( pgrad ) . stp ;	//       -1 なら stp
  }
  double spoint ( gc_size_type pgrad ) const {	// データ開始地点を返す関数
    chkdirec () ;
    if ( direc == 1 )
      return getElement ( pgrad ) . stp ;		// direc= 1 なら stp
    else return getElement ( pgrad ) . endp ;	//       -1 なら endp
  }
  
  double grad ( gc_size_type pgrad ) const
  { return getElement ( pgrad ) . grad ; }
  double curve ( gc_size_type pgrad ) const
  { return getElement ( pgrad ) . curve ; }
  double vlimit ( gc_size_type pgrad ) const ;
		// 配列上の位置から勾配・曲線半径・制限速度を返す関数

  double grad ( double pos ) const { return grad ( dpgrad ( pos ) ) ; }
  double curve ( double pos ) const { return curve ( dpgrad ( pos ) ) ; }
  double vlimit ( double pos ) const { return vlimit ( dpgrad ( pos ) ) ; }
		// 絶対位置から勾配・曲線半径・制限速度を返す関数

  double out_of_station () const ;

  // ----
  // SOC curve related.
  // SOCカーブ関連.
  // ----
  SOC_FeedForward_Data const * get_SOC_Curve () const { return _soc ; }
  string const & get_SOC_Key () const { return _soc_name ; }
  bool wants_SOC_Curve () const { return _wants_soc ; }
  void set_SOC_Curve ( SOC_FeedForward_Data const * x ) { _soc = x ; }

} ;



#endif /* ! ___NEXTSTA_HH */
