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

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

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

#define INVLIM 1e-5

//#define DEBUG
//#define TIMEPRINT

// 力行中の次位置演算
void
train :: nm_power
( double tracff )
{

  // ----
  // NOTE: 2010. 1. 20 -- emrn no longer used.
  // ----
  // tracff *= emrn ;	// added 04 Jun 92
  //                    // 発振防止アルゴリズムのため

#ifdef DEBUG
  cerr << StrPrintf ( "nm_power, tracff = %.1f" , tracff ) << endl ;
#endif
  iamcoast = false ;
  iamconst = true ;
  enableMechanicalPowerCalculation () ;
  npos ( tracff ) ;
  disableMechanicalPowerCalculation () ;

  // ----
  // Accumulating acceleration time.
  // 力行時間の積算.
  // ----
  ptime += deltah ;

#ifdef DEBUG
  cerr << "npos ended\n";
#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 << "if station_object_valid ---- sw_x_btws check ended" << endl ;
#endif
  }

  double bkl_drx = bklen () * direc () ;

#ifdef DEBUG
  cerr << "first bklen() ended" << endl ;
#endif

  if ( bkl_drx >= nxx -> parrive () * direc () )
  {
    // オフブレーキの条件（駅間停止指向）

    stat = Brake ;
    brakev = nxx -> varrive () ;
    sw_btws = false ;		// 駅間停止のためのブレーキではない
    sw_x_btws = false ;		// 駅間停止位置を過ぎたと認定
    rnotchold = rnotch = - 1.0 ;
#ifdef DEBUG
    cerr << "first off-brake." << endl ;
#endif
    return ;			// off-brake
  }

  if ( g_sw_station_object_valid && g_sw_disttrain_ended )
  {
    // 信号系有効時のみチェック
    bkl_drx = bklen ( 0.0 ) * direc () ;

#ifdef DEBUG
    cerr << "second bklen( 0.0 ) ended." << endl ;
#endif

    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
#ifdef DEBUG
      cerr << StrPrintf ( "Off-brake at power mode, pos = %.3f" , pos )
           << endl ;
#endif
      rnotchold = rnotch = - 1.0 ;

#ifdef DEBUG
      cerr << "between-stop braking." << endl ;
#endif
      return ;
    }
  }

  if ( vlimitbrake () )
  {
    // 前方速度制限により brake
#ifdef DEBUG
    cerr << "velocity limit braking." << endl ;
#endif
    return ;
  }

  // 到着予想時刻
  double ontx = ontimesub ( pos , pgrad , vel , t_sim ) ;

#ifdef DEBUG
  cerr << "ontimesub ended." << endl ;
#endif

  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 )
  {
    // 駅間走行時分一定の条件による状態遷移
    // *** Coast または Const_vel へ
#ifdef DEBUG
    cerr << StrPrintf
      ( "car %i: ontx, tarrivex = %.2f %.2f" ,
        carno , ontx , nxx -> tarrive ( pfirst ) + x_tard + tdept - taudx )
         << endl ;
#endif
#ifdef TIMEPRINT
    cerr << "power" << endl ;
#endif
    iamconst = false ;
    iamcoast = true ;	// 力行状態終了
    ++ pfirst ;

    // 駅間走行時分一定の条件による状態遷移・つづき
    // **** 遷移先の状態を決定
    sw_btws = false ;	// 駅間停止のためのブレーキではない
    if ( tresist ( vel, pgrad ) > 0
         || ( vel < nxx -> vlimit ( pgrad )
              || nxx -> vlimit ( pgrad ) < INVLIM ) )
    {
      // 制限速度にかからないケース
      //  -> Coast 状態へ遷移
      // **** 速度が制限速度より低い
      // **** 速度が制限速度以上だが惰行時速度が落ちる
      stat = Coast ;
      rnotchold = rnotch = 0.0 ;
#ifdef DEBUG
      cerr << StrPrintf ( "Power -> coast, vlimit = %.1f km/h" ,
                          nxx -> vlimit ( pgrad ) ) << endl ;
#endif
      return ;					// ontime 運転条件
    }
    else
    {
      // 制限速度にひっかかるケース
      //  -> Const_vel 状態へ遷移
      // **** 速度が制限速度以上で惰行時速度が落ちない
      stat = Const_vel ;
#ifdef DEBUG
      cerr << StrPrintf
        ( "Power -> Const, vlimit, vel = %.1f, %.1f km/h" ,
          nxx -> vlimit ( pgrad ) , vel ) << endl ;
#endif
      return ;
    }
  }

  if ( nm_stnobj_brake () )
  {
    // 信号現示変化によるブレーキをかけるべきケース
    return ;
  }

  if ( vel >= nxx -> vlimit ( pgrad )
       && nxx -> vlimit ( pgrad ) >= INVLIM )
  {
    // 制限速度にひっかかる -> 力行状態を終了しないまま定速走行へ
    //  -> Const_vel 状態へ遷移
    // **** 速度が制限速度以上で惰行時速度が落ちない
    // **** 力行状態のまま
    iamcoast = false ;
    iamconst = true ;
    stat = Const_vel ;
#ifdef DEBUG
    cerr << StrPrintf ( "Power -> Const, vlimit, vel = %.1f, %.1f km/h" ,
                        nxx -> vlimit ( pgrad ) , vel ) << endl ;
#endif
  }
  return ;
}
