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

#include <cstdio>
#include <cstdlib>
#include <cmath>

#include "train.hh"
#include "StrPrintf.hh"

#define INVLIM 1e-5

//#define DEBUG
//#define PRATEBUG

#define DELAY_ALLOWED 	3	// Ec_auto 惰行中に許される遅れ[sec]
			// 惰行中のエネルギー返却によるベタ遅れ防止のため


// Station_pass, Pass_pass 時の nxx 入れ換え
bool
train :: nm_nxxps
()
{
  // data check
  if ( nxx -> nextnxx () -> nxxptn () != Pass_pass
       && nxx -> nextnxx () -> nxxptn () != Pass_station )
  {
    l_ofs << "Error: nextsta_pattern data not correct" << endl ;
    cerr  << "Error: nextsta_pattern data not correct" << endl ;
    exit ( 13 ) ;
  }

  if ( pos * direc () >= nxx -> parrive () * direc () - DINVLIM )
  {
    // 次の次駅データに移行するしかない
    double tde = tdept - taudx ;	// 次駅データ出発時遅れ時分の決定
    taudx = t_sim - nxx -> tarrive ( true ) - tde ;
    l_ofs 
      << StrPrintf ( "car %i: pos = %.3f, direc %d(%d-%d), delay %.2f sec." ,
                     carno , pos , direc () , nxx -> dptnum () ,
                     nxx -> dpttbl () , taudx ) << endl ;
    cerr
      << StrPrintf ( "car %i: pos = %.3f, direc %d(%d-%d), delay %.2f sec." ,
                     carno , pos , direc () , nxx -> dptnum () ,
                     nxx -> dpttbl () , taudx ) << endl ;
    nxx -> setpf ( taudx , pfirst ) ;		// 遅れを通信
    if ( fabs ( taudx ) > ontprec_delay_set )
    {
      // 遅れが大きいなら…
      if ( g_sw_freerun_cycle && ( ! nxx -> get_ontprec () )
           && n_inc_nfree != n_simcycle )
      {
        // フリーラン中で ontprec 未セットならば nfree 増
        ++ nfree ;
        l_ofs << StrPrintf ( "nfree increased to %d" , nfree ) << endl ;
        cerr  << StrPrintf ( "nfree increased to %d" , nfree ) << endl ;

        // nfree 増を1サイクル2度行わない
        n_inc_nfree = n_simcycle ;
      }
      nxx -> set_ontprec () ;			// ontprec をセット
    }

    tdept = t_sim ;	// 停車時分は存在しない
    prate = ptime / nxx -> tarrive ( true ) ;		// 力行率
    nxx -> prate ( prate ) ;				// 力行率通信
#ifdef PRATEBUG
    cerr << StrPrintf ( "prate = %.7f" , prate ) << endl ;
#endif
    addlen () ;					// 総走行距離校正
    stpos = pos = nxx -> nextnxx () -> pstart () ;	// 列車位置校正
    setNextstaPointer ( nxx -> nextnxx () ) ;
    pgrad = nxx -> dpgrad ( pos ) ;			// 次駅データ入換
    ptime = 0.0 ;					// 力行時間更新
    if ( g_sw_station_object_valid )
    {
      if ( g_sw_disttrain_ended )
      {
        // to_station データを from_station に置換え
        stnobj_now -> from_station_generate ( this ) ;
        stnobj_now -> this_train_will_depart ( this ) ;	// 通過も可
      }
      stnobj_now = nxx -> stnobj () ;
      if ( g_sw_disttrain_ended )
      {
        // disttrain が終了した後のみ行う
        // to_station を新しい station_obj に通信,
#ifdef DEBUG
        cerr << "communicate with the new station_obj" << endl ;
#endif
        stnobj_comm () ;	// 時隔計算を新たに行う
      }
    }	// 入れ換え

    double ontx = ontimesub ( pos , pgrad , vel , t_sim ) ;

    double x_tard = 0.0 ;	// 到着遅れ時分の期待値
    if ( g_sw_station_object_valid && g_sw_disttrain_ended )
    {
      // 信号系有効時のみチェック
      // **** nxx->tarr_delay ( this ) : 信号系無効時は zero なのだが
      x_tard = nxx -> tarr_delay ( this ) ;	// これが通常の話
      if ( g_sw_stop_between_oriented && sw_x_btws )
      {
        // 駅間停止指向で駅間停止位置を過ぎていない場合
        x_tard = 0.0 ;	// 遅れなしとしてパターンを生成
      }
    }

    if ( ontx - tdept + taudx < nxx -> tarrive ( pfirst ) + x_tard )
    {
      // ブレーキ状態への転向条件
      stat = Brake ;
      brakev = - 1.0 ;	// 負の目標速度：ontime Brake 条件
      rnotchold = rnotch = - 1.0 ;
      iamcoast = true ;			// 惰行領域を設定
      iamconst = false ;
    }
    else
    {
      // 力行状態への転向条件
      iamcoast = false ;				// 力行領域を設定
      iamconst = true ;
      cpsw = false ;					// cpsw リセット
      if ( vel >= nxx -> vlimit ( pgrad ) 
           && nxx -> vlimit ( pgrad ) >= INVLIM
           /* && tresist ( vel , pgrad ) < 0 */ )
      {
        // 速度制限にかかる→定速走行へ転向
        stat = Const_vel ;
      }
      else
      {
        // 力行状態へ転向
        stat = Power ;
        rnotchold = rnotch = 1.0 ;
      }
    }
    return true ;
  }
  else
  {
    return false ;
  }
}
