// 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.)
// trn_coas.cc --- class train functions on nextmotion: nm_coast
// $Id: trn_coas.cc,v 2.4 1994/12/27 12:03:47 rt Exp $

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

#include "train.hh"

#define INVLIM 1e-5

//#define DEBUG

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

// 惰行時の次位置演算
void
train :: nm_coast
( double tracff )
{

  // tracff *= emrn ;
  enableMechanicalPowerCalculation () ;
  npos ( tracff ) ;	// 次位置演算
  disableMechanicalPowerCalculation () ;

  if ( g_sw_station_object_valid && g_sw_disttrain_ended )
  {
    if ( pos * direc ()
         >= nxx -> parrive () * direc () - nxx -> out_of_station () )
    {
      sw_x_btws = false ;	// 駅間停止位置を過ぎたと認定
    }
  }

  if ( nxx -> nxxptn () == Pass_pass
       || nxx -> nxxptn () == Station_pass )
  {
    // 次駅通過の場合
    if ( nm_nxxps () )
    {
      // 次駅データ入換えた！
      return ;
    }
  }

  if ( bklen () * direc () >= nxx -> parrive () * direc () )
  {
    // オフブレーキの条件
    stat = Brake ;
    brakev = nxx -> varrive () ;
    rnotchold = rnotch = - 1.0 ;
    return ;
  }

  if ( g_sw_station_object_valid && g_sw_disttrain_ended )
  {
    // 信号系有効時のみチェック

    double bkl_drx = bklen ( 0.0 ) * direc () ;

    if ( bkl_drx >= nxx -> parrive () * direc () - nxx -> out_of_station ()
         // && g_sw_stop_between_oriented -> 実はいらない
         && nxx -> stnobj () -> voie_occupied ( this ) )
    {
      // オフブレーキの条件: out_of_station の位置までに停止
      // **** 駅間停止指向の場合かつ駅番線未開通かつ
      // **** out_of_station の位置までに速度0にならない場合
      stat = Brake ;
      brakev = 0.0 ;	// 目標速度: 停止
      sw_btws = true ;	// 駅間停止のためのブレーキなので true
      sw_x_btws = false ;	// 駅間停止位置を過ぎたと認定
      rnotchold = rnotch = - 1.0 ;
      return ;
    }
  }

  if ( vlimitbrake () )
  {
    // 前方制限 brake を判定
    return ;
  }
  
  if ( nm_stnobj_brake () )
  {
    // 信号系切替りによるブレーキ
#ifdef DEBUG
    cerr << "car " << cs_number () << " stnobj_brake" << endl ;
#endif
    return ;
  }

  if ( nm_stnobj_power () )
  {
    // 信号系切替りによる力行
#ifdef DEBUG
    cerr << "car " << cs_number () << " stnobj_power" << endl ;
#endif
    return ;
  }

  if ( cpsww )
  {
    // 走行時分合せのための力行/回生
    cpsw = true ;
  }
  
  if ( cpsw && rnotch < INVLIM )
  {
    // (Ec_auto mode)
    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 )
    {
      l_ofs << "car " << carno << ": REGENERATE" << endl ;
      // 回生のみ状態への転向条件
      stat = Regenerate ;
      rnotchold = rnotch = - 1.0 ;
      iamcoast = false ;			// 回生のみ領域を設定
      iamconst = false ;
    }
    else if ( ontx - tdept + taudx > nxx -> tarrive( pfirst )
              + x_tard + DELAY_ALLOWED )
    {
      	// ベタ遅れ判定
      iamcoast = false ;				// 力行領域を設定
      iamconst = true ;
      cpsw = false ;				// cpsw リセット
      if ( vel >= nxx -> vlimit ( pgrad ) && nxx -> vlimit ( pgrad ) >= INVLIM
           && tresist ( vel , pgrad ) < 0 )
      {
        // 速度制限にかかる→定速走行へ転向
        stat = Const_vel ;
        return ;
      }
      stat = Power ;				// 力行状態へ転向
      rnotchold = rnotch = 1.0 ;
      ontprec = nxx -> get_ontprec () ;
      return ;
    }
  }

  if ( vel >= nxx -> vlimit ( pgrad ) && nxx -> vlimit ( pgrad ) >= INVLIM
       && tresist ( vel , pgrad ) < 0 )
  {
    // 下り勾配による速度上昇→速度制限にかかった
    stat = Const_vel ;	// 定速走行へ転向
    iamcoast = true ;	// 惰行領域を設定
    iamconst = false ;
    return ;
  }

  if ( cpsw )
  {
    cpsw = false ;
  }
}
