// This may look like C code, but it is really -*- C++ -*-
// RTSS --- Railway Total System Simulator
// (c) TAKAGI Ryo (at Prof. SONE's Laboratory, the Univ. of Tokyo.)
// sigobj.hh --- class signalling and related classes and structs
// $Id: sigobj.hh,v 2.4 1994/12/27 12:03:47 rt Exp $

#include "globvar.hh"
#include "readdata.hh"
#include "NoRefTable.hh"
#include "enumerat.hh"

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

// 軌道回路オブジェクト
struct railsigcell {
    double stp;		// 区間開始地点
    double endp;	// 区間終了地点 ; endp > stp
    int trainhere;	// 列車在線: true
    int trainnum;	// 列車番号 ( ! trainhere のときは無意味 )
    double vlimit;	// 制限速度
};

// 駅位置に関するデータ
class 
: public NoRefTable<gcvel>, public readdata {

// 変数なし
//	gcvel* gxx;	// 勾配曲線データ（配列）
//	int gmax;	// 勾配曲線データの個数
//	int gmem;	// データのために確保したメモリの最大値
// 関数

  private:
    void error26_name() {
	fprintf(stderr, "Error: subscript out of range in\n");
	fprintf(stderr, "       gradcrv object gcvel data call\n");
    }

  public:
    gradcrv(): NoRefTable<gcvel>() {}			// constructor
    // destructor は定義しない
    gradcrv(gradcrv& x): NoRefTable<gcvel>(x) {}	// constructor: X(X&)
    gradcrv& operator=(gradcrv&);  	// 代入用演算子のオーバーロード
    gradcrv& operator+=(gcvel&);	// gcvel の追加（データチェック付）
    gradcrv& operator+=(gcvel);		// gcvel の追加（データチェック付）
    gradcrv& renewpos(int, double);	// gcvel データの書替

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

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

class train;
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;	// 次のデータに切替える点
    nextsta* nxx;	// 次の次駅データ
    double bufcont;	// 余裕時分調整変数
    double prt;		// 力行率
    bool setprt;	// 力行率セットしたら true
    double pfcont;	// pfi 回目の力行/回生のみ までは駅間走行時分を狂わせる
    int pfi;		// 走行時分合わせをした回数
    dp_command dcmd;	// 制御用変数
    double conges;	// 混雑率 g_sw_conges_station が true のときのみ有効
    bool ontprec;	// この区間は最初から ontime_prec で時間合わせ

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

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

// 関数
    inline void fpgrad(int& zz) {zz += direc;}
    inline void bpgrad(int& zz) {zz -= direc;}
       	// 勾配データ配列上の現在位置の前進(f)/後退(b)
    inline void chkdirec() {		// 列車方向設定確認ルーチン
	if (direc != 1 && direc != -1) {
	    fprintf(stderr, "Error: int direc must be 1 or -1\n");
	    exit(15);	// error 15: 方向設定エラー
	}
    }

  public:

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

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

    void setvar(double, int, double, double, double, int, double, double);
	// ８変数の代入ないしは初期化
    inline void set_ndp(int n) {ndp = n;}		// ndp のセット
    inline void set_ndpt(int n) {ndpt = n;}		// ndpt のセット

    inline void setpf(double x, int i) {pfcont = x; pfi = i;}
    inline void prate(double x) {prt = x; setprt = true;}
    inline void prtreset() {setprt = false;}
    inline void prtinit() {prtreset(); prt = bufcont = pfcont = 0.0;}
    inline void setbuf(double x) {bufcont += x;}
    inline void setdc(dp_command x) {dcmd = x;}
    inline void set_nextnxx(nextsta* x) {nxx = x;}
    inline void set_ontprec() {ontprec = true;}
    inline bool get_ontprec() {return ontprec;}
    void get_greq(int&, int&, double&);	// greq_* の中身を返す
					// なくなれば gnum = -1 を返す
    int dpgrad(double);			// 勾配データ配列上の現在位置決定
    void adjpgrad(int&, double);	// 勾配データ配列上の現在位置合わせ
    void arv_pass();			// arv の処理
    double tarrive(int);		// ontime 決定用, 少し変える
    double tarrive(bool);		// setbuf 用、さらに少し変える
    inline bool prtset() {return setprt;}
    inline double bufdiff() {return bufcont;}
    inline double prate() {return prt;}
    inline double congestion() {return conges;}
    inline double nextswitch() {return nextsw;}
    inline double parrive() {return arp;}
    inline double varrive() {return arv;}
    inline double tarrive() {return art;}
    inline nextsta_pattern nxxptn() {return nxp;}
    inline double stoptime() {return tstop;}
    inline double pstart() {return startp;}
    inline nextsta* nextnxx() {return nxx;}
    inline int feedlinenumber() {return nfline;}
    inline int direction() {return direc;}
    inline int dptnum() {return ndpt;}
    inline int dpttbl() {return ndp;}			// 変数参照用
    inline int dqgrad() {		// 勾配データの配列上の終点駅位置
	chkdirec();
	if (direc == 1) return (number() - 1);
	if (direc == -1) return 0;
    }
    inline int dsgrad() {		// 勾配データの配列上の起点駅位置
	chkdirec();
	if (direc == 1) return 0;
	if (direc == -1) return (number() - 1);
    }
    inline void fwpgrad(int& zz) {chkdirec();fpgrad(zz);}
    inline void bkpgrad(int& zz) {chkdirec();bpgrad(zz);}
		// 勾配データ配列上の現在位置の前進(fw)/後退(bk)

    inline double epoint(int pgrad) {	// データ終了地点を返す
	chkdirec();
	if (direc == 1)
	    return operator[]( pgrad ).endp;	// direc= 1 なら endp
	else return operator[]( pgrad ).stp;	//       -1 なら stp
    }
    inline double spoint(int pgrad) {	// データ開始地点を返す関数
	chkdirec();
	if (direc == 1)
	    return operator[]( pgrad ).stp;		// direc= 1 なら stp
	else return operator[]( pgrad ).endp;	//       -1 なら endp
    }

    inline double grad(int pgrad) {return operator[](pgrad).grad;}
    inline double curve(int pgrad) {return operator[](pgrad).curve;}
    double vlimit(int pgrad);
		// 配列上の位置から勾配・曲線半径・制限速度を返す関数

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

#endif /* ! ___SIGOBJ_HH */
