// This may look like C code, but it is really -*- C++ -*-
// RTSS --- Railway Total System Simulator
// (c) TAKAGI Ryo (at Kogakuin University)
// elecchar.hh --- defines class elecchar and related classes
// -----
// ChangeLog:
// 2008. 1. 18
//  Added elecchar::writeToCSV(), elecchar::writeHeaderToCSV() functions.
// 2008. 1. 17
//  Added variable elecchar::suppress_csv.
// 2007. 12. 5
//  Added variables a_conv and di_conv in class elecchar.
//  Added teta_vi_core() and teta_vi_ESS() in class elecchar.
// 2007. 12. 4
//  Added classes ESS_Substation and No_ESS_Substation.
//  Added elecchar::sub_ess.
// 2007. 11. 20
//  Added elecchar::scvits.
// 2007. 11. 16
//  Class sscon now derived from vector<ssfeedconnect>. Use of RefTable.hh
//  eliminated.
// 2007. 11. 8
//  Added functions elecchar::readfile_xml(), sschar::readxml_vichars().
//  These functions will be used to parse XML-based S files.
// -----

#include "globvar.hh"
#include "enumerat.hh"
#include "readdata.hh"
#include "EnergyStorage.hh"
#include "ElectricChars.hh"

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

#include "tinyxml.h"
#include "Substation_Control_VI_TS.hh"

using std :: cerr ;
using std :: endl ;
using std :: string ;
using std :: vector ;
using std :: ostream ;

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


// -----
// The vertex of the substation V-I characteristics curve.
// 変電所特性の折れ線の折れ曲がり点のデータ.
// -----
struct subchar
{
  double teta ; 	// 媒介変数値
  double volt ; 	// 電圧
  double ampere ;	// 電流

  double voltlow ;	// コントロール変数ゼロのときの電圧
  double amplow ;	// コントロール変数ゼロのときの電流

  subchar () ;
  subchar ( const TiXmlNode * ) ;
} ;


// 変電所の特性データ
class sschar
  : public vector < subchar > ,
    public readdata
{

public :

// 変数

// 以下の変数は cs_command = Ea_cvauto0 の場合にのみ有効
// しかし必ずデータファイルには記入する。公開はプログラムの都合
  double ar ;  	// 変電所定格電流値
  double isl ;  	// 変電所電流、これ以下ならば大丈夫[pu]
  double isc ;  	// 変電所電流、これ以上ならば要警戒[pu]
  double ism ;  	// 変電所電流最大値[pu]

  bool already_set ;

// 関数

private :
  void membercopy ( const sschar & ) ;		// メンバコピー

public :

  // コンストラクタ
  sschar () : vector < subchar > ()
  { ar = isl = isc = ism = 0 ;	already_set = false ; }

  // destructor は暗黙に用意されるものを用い、改めて定義しない

  sschar ( const sschar & ) ;      	// X(X&)
  sschar & operator= ( const sschar & ) ; 	// 代入の定義

  // ファイル読み込み
  int readfile ( FILE * , char * ) ;
  int readxml_vichars ( const TiXmlNode * ) ;
  int readxml_ratedcurrent ( const TiXmlNode * ) ;

  const subchar & operator[] ( sschar :: size_type i ) const {
    try
    {
      return at ( i ) ;
    }
    catch ( std :: out_of_range )
    {
      cerr << "Error: subscript out of range (sschar)" << endl ;
      exit ( 26 ) ;
    }
  }

  subchar & operator[] ( sschar :: size_type i ) {
    return const_cast < subchar & >
      ( static_cast < const sschar * > ( this ) -> operator[] ( i ) ) ;
  }
} ;


// 変電所の饋電線接続点データ
struct feedpos
{
  int nfline ;	// 饋電線番号
  int csno ;	// 変電所／車両番号
  double pos ;	// 饋電線上の位置
  double sttimp ;	// 始点側(pos が小さい方)の挿入インピーダンス
  double endimp ;	// 終点側(pos が大きい方)の挿入インピーダンス
} ;


// 変電所の饋電線接続点データ（変電所側が所有）
struct ssfeedconnect
{
  int nfline ;	// 饋電線番号
  int csno ;	// 変電所／車両番号
  double pos ;	// Position of the connection
  double sttcurr ;	// 始点側(pos が小さい方)の電流
  double sttenrgy ;	// 始点側(pos が小さい方)のエネルギー
  double sttpeak ;	// 始点側(pos が小さい方)のピーク電流
  double sttnpeak ;	// 始点側(pos が小さい方)のピーク電流
  double sttpower [ 2 ] ;
  double endcurr ;	// 終点側(pos が大きい方)の電流
  double endenrgy ;	// 終点側(pos が大きい方)へのエネルギー
  double endpeak ;	// 終点側(pos が大きい方)のピーク電流
  double endnpeak ;	// 終点側(pos が大きい方)のピーク電流
  double endpower [ 2 ] ;

  ssfeedconnect () ;	// コンストラクタ、デフォルト値を決定
  ~ssfeedconnect () {}	// destructor
  ssfeedconnect ( ssfeedconnect const & ) ;	// X(X&)
  ssfeedconnect & operator= ( ssfeedconnect const & ) ;	// こちらも同様？
  ssfeedconnect ( feedpos const & ) ;	// こういうのがあると便利なので
  ssfeedconnect & operator= ( feedpos const & ) ;	// こちらも同様

private :
  void membercopy ( ssfeedconnect const & ) ;

} ;



// 変電所の接続点データ
// readdata から派生は必要なし
class sscon
  : public vector < ssfeedconnect >
{
public :

  sscon () : vector < ssfeedconnect > () {}	// コンストラクタ
  // destructor は暗黙に用意されるものを用い、改めて定義しない

  sscon ( const sscon & x ) : vector < ssfeedconnect > ( x ) {}	// X(X&)

  const ssfeedconnect & operator[] ( sscon :: size_type i ) const {
    try
    {
      return at ( i ) ;
    }
    catch ( std :: out_of_range )
    {
      cerr << "Error: subscript out of range (sscon)" << endl ;
      exit ( 26 ) ;
    }
  }

  ssfeedconnect & operator[] ( sscon :: size_type i ) {
    return const_cast < ssfeedconnect & >
      ( static_cast < const sscon * > ( this ) -> operator[] ( i ) ) ;
  }

  sscon :: size_type number () const { return size () ; }
  sscon & operator+= ( const ssfeedconnect & x ) { push_back ( x ) ; }
} ;



// -----
// Class expressing electric characteristics
// As base class, it is a substation.
// 電気的特性データと関数（基本クラス）
// 導出しなければ、変電所データ
// -----
class elecchar
  : public ElectricChars
{
                	
// 変数

private :

  sschar subc ; 	// 変電所の特性データ
  sscon ssfeedcon ;	// 変電所の接続点データ

  double subcntl ;	// 変電所制御変数，0〜1の間の値をとらせる

  // -----
  // Store substation control variable. Used by the tag <subchar_vi_file>
  // upon initialisation. Defaults to zero.
  // 変電所制御変数を保存する。初期化時に <subchar_vi_file> タグにより利用
  // される. デフォルトはゼロ.
  // -----
  Substation_Control_VI_TS * scvits ;

  // -----
  // Energy storage system at a substation. Defaulted to an instance of class
  // No_ESS_Substation.
  // 変電所設置のエネルギー蓄積装置。初期化時デフォルトは No_ESS_Substation
  // クラスのインスタンス。
  // -----
  ESS_Substation * sub_ess ;

  string name_utf8 ;
  string name_sjis ;

  // -----
  // If true then suppress output to CSV file.
  // もし真なら CSV ファイルへの出力を抑制する。
  // -----
  bool suppress_csv ;

protected :

// 計算により求めるもの
  double ccv ;		// Cc
  double clv ;		// Cl

  cs_mode mode ; 	// 列車モード
  double tt ;   	// 媒介変数
  double v ;    	// 饋電線接続点電圧
  double a ;    	// 饋電線接続点電流
  double a_conv ;    	// 饋電線接続点電流のうち変換器分（変電所のみ）
  double aax ;  	// 饋電線接続点電流のうち補機の分
  double v_old ;	// 饋電線接続点電圧の古い値
  double a_old ;	// 饋電線接続点電流の古い値
  double a_conv_old ;	// 饋電線接続点変換器分電流の古い値（変電所のみ）
  double tt_old ;	// 媒介変数の古い値
  double dv ;   	// 電圧差分値
  double di ;   	// 電流差分値
  double di_conv ;   	// 電流差分値のうち変換器分（変電所のみ）
  double diax ; 	// 電流差分値のうち補機の分
  double cmd_main ;	// 主回路指令値
  double amx ;  	// ピーク電流 (正値)
  double amy ;  	// ピーク電流 (負値)
  double voltpeak ;	// 電圧ピーク（最高）値
  double voltbottom ;	// 電圧ボトム（最低）値
  bool sw_voltpeak ;	// 電圧ピーク／ボトム値の初期値セットしたら false
  double enrgy ;	// 変電所毎の入力エネルギー
  double renrgy ;	// 変電所毎の回生エネルギー
  double pwr [ 2 ] ;	// enrgy に対応
  double rpwr [ 2 ] ;	// renrgy に対応

// 定数、初期化以後変更なし
  cs_command ccmd ; 	// 指令値の種類
  int csno ;    	// 変電所番号……外から初期化

// 関数

private :

  // -----
  // Copying members.
  // メンバコピー。
  // -----
  void membercopy ( const elecchar & ) ;

  // -----
  // The subprogram of teta_vi, which actually is the "original" part of the
  // function that processes the "core" jobs.
  // teta_vi のサブプログラム。従来の「オリジナルな」パートで，コアの仕事を
  // する部分。
  // -----
  void teta_vi_core () ;

  // -----
  // The subprogram of teta_vi, which does ESS-related tasks.
  // teta_vi のサブプログラム。エネルギー蓄積装置がらみの仕事をする。
  // -----
  void teta_vi_ESS () ;

public :
  elecchar () ;	// Default constructor

  elecchar ( const elecchar & ) ;	// X(X&)
  elecchar & operator= ( const elecchar & ) ;	// 代入

  double cc () { return ccv ; }	// Cc
  double cl () { return clv ; }	// Cl
  double & teta () { return tt ; }	// 媒介変数への参照
  double & volt () { return v ; }	// 電圧への参照
  double & ampere () { return a ; }	// 電流への参照
  double & dvi () { return dv ; }	// 電圧差分値への参照
  double & dii () { return di ; }	// 電流差分値への参照
  virtual double & gva () { return v ; }	// 既知側変数（電圧）
  virtual double & uva () { return a ; }	// 未知側変数（電流）
  virtual double & dgva () { return dv ; }	// 既知側差分値（電圧）
  virtual double & duva () { return di ; }	// 未知側差分値（電流）

  const double volt () const { return v ; }	// 電圧への参照
  const double ampere () const { return a ; }	// 電流への参照

  virtual bool getSuppressCSVFlag () const { return suppress_csv ; }

  // -----
  // Output to CSV file. Boolean argument: suppress leading comma if false.
  // CSVファイルへの出力. 論理値引数: 偽ならカンマの出力を抑制
  // -----
  virtual bool writeHeaderToCSV ( ostream & , bool = true ) const ;
  virtual bool writeToCSV ( ostream & , bool = true ) const ;

  const string & getNameInUTF8 () const { return name_utf8 ; }
  const string & getNameInSJIS () const { return name_sjis ; }

  double & energy () { return enrgy ; }
  double & renergy () { return renrgy ; }
  double * power () { return pwr ; }
  double * rpower () { return rpwr ; }

  void setcsno ( int x ) { csno = x ; }	// 変電所番号のセット

  // -----
  // Renew the electrical state variables.
  // 電気的状態変数を更新。
  // -----
  void renewElectricalStates () ;


  // -----
  // Calculate voltage and current of the ESD
  // -----
  void calculateESDVoltageAndCurrent () ;

  // -----
  // SOC-related initialisation upon start of the simulation cycle.
  // -----
  void setStartSOC () { sub_ess -> setStartSOC () ; }

  // -----
  // Typing out SOC-related data to the RES file.
  // -----
  void printSOCStoredResults
  ( ostream & x , ostringstream & y , ostringstream & z ) const
  { sub_ess -> printSOCStoredResults ( x , y , z ) ; }

  // -----
  // Recording and restoring of the old voltage and current values
  // 古い電圧・電流値の記録と再設定
  // -----
  virtual void setviold ()
  { v_old = v ; a_old = a ; tt_old = tt ; a_conv_old = a_conv ; }
  virtual void restorevi ()
  { v = v_old ; a = a_old ; tt = tt_old ; a_conv = a_conv_old ; }

  virtual void teta_vi () ; 	// teta から volt, ampere への変換
  virtual void add_to_teta ( double , bool ) ; // teta に加える

  // 変電所接続点データ
  sscon & feedcon () { return ssfeedcon ; }
  const sscon & feedcon () const { return ssfeedcon ; }

  void setpeak () ;			// ピーク電流・電圧値のセット
  double peakcur () { return amx ; }	// ピーク電流正値を返す
  double npeakcur () { return amy ; }	// ピーク電流負値を返す
  double peakvolt () { return voltpeak ; }	// 最高電圧値を返す
  double bottomvolt () { return voltbottom ; }	// 最低電圧値を返す

  void setsubcntl ( double ) ;		// subcntl セット
  void addtosubcntl ( double ) ;	// subcntl セット
  double getsubcntl () { return subcntl ; }	// subcntl ゲット

  void cccl () ;	// Cc, Cl の計算

  // 方向別電流: 饋電線番号，電流値が引数
  // 該当するノードが発見できないと……とりあえず warning を出す
  // 起点側: branch では終点側
  void directional_curr_start ( int , double , double ) ;

  // 方向別電流: 饋電線番号，電流値が引数
  // 該当するノードが発見できないと……とりあえず warning を出す
  // 終点側: branch では起点側
  void directional_curr_end ( int , double , double ) ;

  // ファイルリード: 旧形式
  int readfile ( FILE * fl , char * fls )
  { return subc . readfile ( fl , fls ) ; }

  // ファイルリード: 新形式
  int readfile_xml ( const TiXmlNode * tn_in ) ;
} ;

#endif /* ! ___ELECCHAR_HH */
