// This may look like C code, but it is really -*- C++ -*-
// RTSS --- Railway Total System Simulator
// (c) TAKAGI Ryo (at Kogakuin University)
// kidenrt.hh --- header file that defines class feeder
// -----
// ChangeLog:
// 2007. 11. 7
//  Added function feeder :: rf_sxml_ctrl_a ( const TiXmlNode * const ).
//  This function reads the attributes for tag <substation_control_a> in the
//  new XML-formatted S file.
//  Added function feeder :: rf_sxml_substation ( const TiXmlNode * const ).
//  This function reads the tag <substation> in the new XML-formatted S file.
// -----

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <vector>
#include <stdexcept>
#include <map>

#include "globvar.hh"
#include "matrix.hh"
#include "enumerat.hh"
#include "nextsta.hh"
#include "elecchar.hh"
#include "train.hh"
#include "feed_y.hh"
#include "feedline.hh"
#include "diapatrn.hh"
#include "stnobj_s.hh"
#include "train.hh"
#include "Ref_SOC_Curve_Container.hh"

#include "tinyxml.h"

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

using std :: map ;
using std :: string ;


// タイプA・変電所リアルタイム送出電圧制御用データ
struct typea_data
{
  int regmax ;		// 回生絞り込み防止を何回やるか
  int ipcmax ;		// 同一車両に対する回数制限，回生時
  double minvolt ;	// 最低電圧
  int trnmax ;		// 最低電圧割り込み防止を何回やるか
  double regr_d ;	// 回生絞り込み防止制御の有効性判定差分
  double delta_c ;	// 変電所で微分をとるときの差分値
  double dcmax ;	// Step maximum limit
  double dclim ;	// Step minimum limit
} ;

// -----
// タイプA・変電所電圧制御に対応する変数: simulate.cc より移動
// ファイルから入力するように変更する
// Typical な値:
//#define TYPEA_REGMAX	50	// 回生絞り込み防止を何回やるか
//#define TYPEA_IPCMAX	15	// 同一車両に対する回数制限，回生時
//#define TYPEA_MINVOLT	1350.0	// 最低電圧
//#define TYPEA_TRNMAX	30	// 最低電圧割り込み防止を何回やるか
//#define TYPEA_REGR_D	0.05	// 回生絞り込み防止制御の有効性判定差分
//#define TYPEA_DELTA_C	0.1	// 変電所で微分をとるときの差分値
// 2007. 1. 9 -- New functions added
//#define TYPEA_DCMAX	0.002	// Step maximum limit
//#define TYPEA_DCLIM	1e-5	// Step minimum limit
// -----
#define TYPEA_REGMAX	realtime_data . typea . regmax
#define TYPEA_IPCMAX	realtime_data . typea . ipcmax
#define TYPEA_MINVOLT	realtime_data . typea . minvolt
#define TYPEA_TRNMAX	realtime_data . typea . trnmax
#define TYPEA_REGR_D	realtime_data . typea . regr_d
#define TYPEA_DELTA_C	realtime_data . typea . delta_c
#define TYPEA_DCMAX	realtime_data . typea . dcmax
#define TYPEA_DCLIM	realtime_data . typea . dclim

// 饋電システムデータ
class feeder
  : public readdata
{

  // 書き出しファイル... quick hack だから汚いけど許してね（タカギ）
  std :: ofstream csvout_nogi ;
  bool nogi_header_required ;

  // 定数、初期化以降変更なし
  int feeders ;	// 饋電線数
  int ncar ;	// 列車数
  int nss ;	// 変電所数
  int ncss ;	// = ncar + nss;
  int ndp ;	// ダイヤパターン数
  int ngrad ;	// 縦断面パターン数
  double delta ;	// 差分値
  int nsim ;	// シミュレートさせる回数

  // Ｙ行列関連
  feed_y feedy ;	// Ｙ行列計算用
  matrix ymtx ;		// Ｙ行列
  matrix gff_xx ; 	// grad ｆ 行列
  matrix gamma ;
  matrix fvec ;	// ｆ関数（縦）ベクトル
  diagmatrix dy ;	// ブランチアドミタンス行列（対角行列形式）
  matrix ht ;	// 接続行列, 転置で入れるのでブランチ×ノード

  // システムデータ
  std :: vector < feedline * > vec_fln ;	// 饋電線データ
  std :: vector < train * > vec_car ;           // 列車データ
  std :: vector < elecchar * > vec_csd ;        // 変電所・列車データ
  std :: vector < diapattern * > vec_dpt ;      // ダイヤパターンデータ
  std :: vector < gradcrv * > vec_gcv ;         // 縦断面パターンデータ
  std :: vector < elecchar * > vec_sub ;        // 変電所データ

  // 信号用駅データ
  RefTable < station_obj * > stnobj ;
  RefTable < station_obj > x_stnobj ;
  RefTable < station_obj_stationstop_variation > x_stnobj_s ;

  // ----
  // Map of traindata for use in rf_pfile() function.
  // rf_pfile() 関数で用いる traindata クラスインスタンスの map。
  // ----
  map < string , traindata * > _trd ;

  // ----
  // Map of reference SOC data for use in rf_nfile() function.
  // rf_pfile() 関数で用いるリファレンスSOCデータクラスインスタンスの map。
  // ----
  Ref_SOC_Curve_Container _soc ;

  // ----
  // XML reader to be used for reference SOC data.
  // リファレンスSOCデータ詠み込み用XMLリーダ.
  // ----
  RS_XmlReader _xread ;

  union {		// *** 一応将来を考え共用体化
    typea_data typea ;	// タイプA用データ
  } realtime_data;	// 変電所リアルタイム送出電圧制御用データ

private :
  void runtrsub ( int ) ;	// runtrain, disttrain の subprogram
  void disttr_trinit () ;	// disttrain の subprogram: 列車状態初期化

  // 車両に隣接変電所までの饋電線インピーダンスを教える
  void tellimp () ;
  void tisub ( feed_y & ) ;	// tellimp の subprogram
  void ti_for ( int , int , feed_y & ) ; // tisub の subprogram, 前進部分
  void ti_efor ( bran_node & ) ; // ti_for の subprogram
  void ti_bak ( int , int , feed_y & ) ; // tisub の subprogram, 前進部分
  void ti_sbak ( bran_node & ) ; // ti_bak の subprogram
  void ti_cc () ;	         // tellimp の subprogram

  void rf_ffile () ;	// f_file を読み込む
  void rf_gfile () ;	// g_file を読み込む
  void rf_hfile () ;	// h_file を読み込む
  void rf_nfile () ;	// n_file を読み込む
  void rf_pfile () ;	// p_file を読み込む
  void rf_sfile () ;	// s_file を読み込む

  // XML S file reading subprograms
  void rf_sxml_ctrl_a ( TiXmlNode const * ) ;
  void rf_sxml_substation ( TiXmlNode const * ) ;

  // XML N file reading subprograms
  void rf_nxml_flags ( TiXmlNode const * ) ;
  void rf_nxml_accompanying_file ( TiXmlNode const * ) ;
  void rf_nxml_pattern ( TiXmlNode const * , int ) ;

  // simulate.cc のサブルーチン
  void resetsubcntl () {
    for ( int i = 0 ; i < nss ; ++ i ) getSUB ( i ) . setsubcntl ( 1.0 ) ;
  }
  void simcccore ( int & ) ;	 // ccal まわり, 中心部分
  void simccsub ( int & ) ;	 // ccal まわり
  void simcc_ssctl_a ( int & ) ; // ccal まわり, 変電所電圧制御タイプA
  void simcc_ssctl_a_regipc ( int & , double & ) ;
				 // タイプA, 回生率チェック
  void simcc_ssctl_a_volipc ( int & , double & ) ;
				 // タイプA, パンタ点電圧チェック
  void simcc_ssctl_a_setctl ( double ) ;
                                 // タイプA, setsubcntl を行なう
  void simcc_ssctl_a_addctl ( double ) ;
    				 // タイプA, addtosubcntl を行なう
  void simcc_ssctl_a_dreg
  (int & , double , double & , double & , double , int ) ;
				 // タイプA, 回生率微分まわりの回路演算
  void siminteg () ;		 // 積分部分
  void simssdirec () ;		 // 変電所方向別
  void simccalresult () ;	 // 回路演算結果の出力

  // -----
  // Renew the electrical state variables that all objects have.
  // すべてのオブジェクトが保有する電気的状態変数を更新。
  // -----
  void simRenewElectricalStates () ;

  // -----
  // Calculate voltage and current of all ESD's
  // -----
  void simCalculateESDVoltagesAndCurrents () ;

public :
  feeder () ;	// empty constructor
  feeder ( const feeder & ) ;	// X(X&) 禁止
  feeder & operator= ( const feeder & ) ;	// 代入禁止
  ~feeder () ;	// destructor

  void setvar ( int , int , int , int , double ) ;
            	// 変数値セット 引数: feeders, ncar, nss, ndp, delta
            	// しかも配列領域の確保までやってくれる

  void readfile () ;	// ファイルリードと初期化
  void setviold () {
    for ( int i = 0 ; i < ncss ; ++ i ) getCSD ( i ) -> setviold () ;
  }
  void restorevi () {
    for ( int i = 0 ; i < ncss ; ++ i ) getCSD ( i ) -> restorevi () ;
  }
  void notchrate () ;
  void setpeak () {
    for ( int i = 0 ; i < nss ; ++ i ) getSUB ( i ) . setpeak () ;
  }
  void settetazero () {
    for ( int i = 0 ; i < ncss ; ++ i ) getCSD ( i ) -> teta () = 0.0 ;
  }

  int ccal () ; 	// 饋電等価回路演算ルーチン
  void ycal () ; 	// Y行列演算ルーチン
  void gradf () ;	// grad ｆ を求める
  double ffunc ( matrix & , matrix & ) ;
  double ffunc ( matrix & ) ;	// ｆ関数ベクトルを求める

  // void emcc ( bool ) ;	// train.emccal をすべて引数値にする

  // feedline への参照
  feedline & getFLN ( int gx )
  {
    feedline * x ;
    try
    {
      x = vec_fln . at ( gx ) ;
    }
    catch ( std :: out_of_range )
    {
      std :: cerr << "Error: subscript out of range in feedline data call"
		  << std :: endl
		  << "       within the feeder object" << std :: endl ;
      exit ( 26 ) ;
    }
    return * x ;
  }

  // diapattern の size
  std :: vector < diapattern * > :: size_type getDPTsize ()
  {
    return vec_dpt . size () ;
  }

  // diapattern への参照
  diapattern & getDPT ( int gx )
  {
    diapattern * x ;
    try
    {
      x = vec_dpt . at ( gx ) ;
    }
    catch ( std :: out_of_range )
    {
      std :: cerr << "Error: subscript out of range in diapattern data call"
		  << std :: endl
		  << "       within the feeder object" << std :: endl ;
      exit ( 26 ) ;
    }
    return * x ;
  }

  // gradcrv への参照
  gradcrv & getGCV ( int gx )
  {
    gradcrv * x ;
    try
    {
      x = vec_gcv . at ( gx ) ;
    }
    catch ( std :: out_of_range )
    {
      std :: cerr << "Error: subscript out of range in gradcrv data call"
		  << std :: endl
		  << "       within the feeder object" << std :: endl ;
      exit ( 26 ) ;
    }
    return * x ;
  }

  // train への参照
  train & getCAR ( int gx )
  {
    train * x ;
    try
    {
      x = vec_car . at ( gx ) ;
    }
    catch ( std :: out_of_range )
    {
      std :: cerr << "Error: subscript out of range in train data call"
		  << std :: endl
		  << "       within the feeder object" << std :: endl ;
      exit ( 26 ) ;
    }
    return * x ;
  }

  // elecchar への参照
  elecchar & getSUB ( int gx )
  {
    elecchar * x ;
    try
    {
      x = vec_sub . at ( gx ) ;
    }
    catch ( std :: out_of_range )
    {
      std :: cerr << "Error: subscript out of range in elecchar data call"
		  << std :: endl
		  << "       within the feeder object" << std :: endl ;
      exit ( 26 ) ;
    }
    return * x ;
  }

  // elecchar * への参照
  elecchar * getCSD ( int gx )
  {
    elecchar * x ;
    try
    {
      x = vec_csd . at ( gx ) ;
    }
    catch ( std :: out_of_range )
    {
      std :: cerr << "Error: subscript out of range in elecchar pointer call"
		  << std :: endl
		  << "       within the feeder object" << std :: endl ;
      exit ( 26 ) ;
    }
    return x ;
  }

  void runtrain () ;	// 列車を走らせる
  void disttrain () ;	// 列車の初期位置を求める

  void simulation () ;	// シミュレーションプログラム本体
  void runcurve () ;
};


#endif /* ! ___KIDENRT_HH */
