// 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_cons.cc --- class train functions on nextmotion: nm_constv
// -----
// ChangeLog:
// 2009. 11. 27
//  Added AMANO_B comments. Headers fixed to new ISO C++ standards.
// -----

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

#include "train.hh"

#define INVLIM 1e-5

//#define DEBUG
using std :: cerr ;
using std :: endl ;



// 定速走行中の次状態計算
void
train :: nm_constv
( double tracff )
{

  enableMechanicalPowerCalculation () ;
  nposc () ;
  disableMechanicalPowerCalculation () ;
#ifdef DEBUG
  cerr << "nm_constv: car " << car_number () << ": nposc ended" << endl ;
  l_ofs << "nm_constv: car " << car_number () << ": nposc ended" << endl ;
#endif

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

#ifdef DEBUG
  cerr << "nm_constv: car " << car_number () << ": sw_x_btws check end"
       << endl ;
  l_ofs << "nm_constv: car " << car_number () << ": sw_x_btws check end"
        << endl ;
#endif

  if ( nxx -> nxxptn () == Pass_pass
       || nxx -> nxxptn () == Station_pass )
  {
    // 次駅通過の場合 bklen の条件より先でよい
    if ( nm_nxxps () )
    {
      return ;		// 次駅データ入れ換えた！
    }
  }

#ifdef DEBUG
  cerr << "nm_constv: car " << car_number () << ": station pass check end"
       << endl ;
  l_ofs << "nm_constv: car " << car_number () << ": station pass check end"
        << endl ;
#endif

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

#ifdef DEBUG
  cerr << "nm_constv: car " << car_number () << ": bklen check end"
       << endl ;
  l_ofs << "nm_constv: car " << car_number () << ": bklen check end"
        << endl ;
#endif

  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 ;
    }
  }

#ifdef DEBUG
  cerr << "nm_constv: car " << car_number () << ": signal stop check end"
       << endl ;
  l_ofs << "nm_constv: car " << car_number () << ": signal stop check end"
        << endl ;
#endif

  if ( vlimitbrake () )
  {
    // 前方制限 brake を判定
    return ;
  }
  
#ifdef DEBUG
  cerr << "nm_constv: car " << car_number () << ": vlimit check end"
       << endl ;
  l_ofs << "nm_constv: car " << car_number () << ": vlimit check end"
        << endl ;
#endif

  if ( nm_stnobj_brake () )
  {
    // 信号系切替りによるブレーキ
    return ;
  }
  
#ifdef DEBUG
  cerr << "nm_constv: car " << car_number () << ": signal brake check end"
       << endl ;
  l_ofs << "nm_constv: car " << car_number () << ": signal brake check end"
        << endl ;
#endif

  if ( nm_stnobj_power () )
  {
    // 信号系切替りによる力行
    return ;
  }

#ifdef DEBUG
  cerr << "nm_constv: car " << car_number () << ": signal accel check end"
       << endl ;
  l_ofs << "nm_constv: car " << car_number () << ": signal accel check end"
        << endl ;
#endif

  if ( iamcoast )
  {
    // 惰行領域にある
    if ( tresist ( vel , pgrad ) >= 0
         || ( vel < nxx -> vlimit ( pgrad )
              || nxx -> vlimit ( pgrad ) < INVLIM ) )
    {
      // 走行抵抗が正、または速度制限にかからない
      iamconst = false ;
      iamcoast = true ;		// 惰行領域へ
      stat = Coast ;
      rnotchold = rnotch = 0.0 ;
      return ;
    }
    else
    {
      stat = Const_vel ;
      return ;
    }
  }
  else
  {
    // 力行領域にある
    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 )
    {
      // 定時ノッチオフ運転の条件
      iamconst = false ;
      iamcoast = true ;		// 惰行領域へ
      if ( tresist ( vel , pgrad ) > 0
           || ( vel < nxx -> vlimit ( pgrad )
                || nxx -> vlimit ( pgrad ) < INVLIM ) )
      {
        stat = Coast ;
        rnotchold = rnotch = 0.0 ;
        return ;
      }
      else
      {
        stat = Const_vel ;
        return ;
      }
    }
  }

  if ( vel < nxx -> vlimit ( pgrad ) && iamconst )
  {
    stat = Power ;
    ontprec = nxx -> get_ontprec () ;
    iamcoast = false ;
    rnotchold = rnotch = 1.0 ;
  }
}
