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

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

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

//#define DEBUG

int arrivalcomp
( const void* p, const void* q ) {
    to_station* a = ( to_station* ) p;
    to_station* b = ( to_station* ) q;
    if ( a->tarrive > b->tarrive ) {
        return 1;
    } else if ( a->tarrive < b->tarrive ) {
        return -1;
    } else {
        return 0;
    }
}

// 時隔の計算
void station_obj::headway_cal
() {
    //*****************************************************************
    // g_sw_station_object_valid および g_sw_disttrain_ended が true の
    // ときにのみ呼ぶこと
    //*****************************************************************
    register int i;

    // もっとも遅くなる時刻の計算
    double f_d_a, f_a_a, f_d_d, f_d_p, f_a_p, f_p_a, f_p_d, f_p_p;
    double f_res;

#ifdef DEBUG
    cerr << "headway_cal: " ;
#endif

    switch ( stnobjtype ) {
    case Vanishing:
#ifdef DEBUG
      cerr << "Vanishing:" << endl ;
#endif
        for ( i = 0; i < number(); i++ ) {
            data[ i ].tarr_delay = 0.0;		// ポインタ・エラーに注意
        }
        break;
    case Doubletrack_no_cross:
#ifdef DEBUG
      cerr << "Doubletrack_no_cross:" << endl ;
#endif

        // 列車の通過・待避関係の制約
#ifdef DEBUG
      cerr << "From_station trains" << endl ;
#endif
        for ( i = 0; i < nvoie; i++ ) {
            if ( ! train_departure[ i ].is_at_station ) {
#ifdef DEBUG
              cerr << StrPrintf ( "Track %d: no train" , i ) << endl ;
#endif
                continue;	// 在線してなければ考える必要なし
            }
            if ( train_departure[ i ].notrw > 0 ) {
                // 列車待ち数 1以上: とにかく発車禁止
                // *** 列車待ち数は同一値をとらないよう別に保証 ***
                train_departure[ i ].do_not_depart = true;
                train_departure[ i ].tdept_delay = 0.0;
                if ( t_sim > train_departure[ i ].tdept ) {
                    train_departure[ i ].tdept_delay
                        = t_sim - train_departure[ i ].tdept;
                }
#ifdef DEBUG
                cerr << StrPrintf ( "Track %d: prohibit departure" , i )
                     << endl ;
#endif
                continue;
            }
            // 関係を見る
            train_departure[ i ].do_not_depart = false;
            train_departure[ i ].tdept_delay = 0.0;
#ifdef DEBUG
            cerr << StrPrintf ( "Track %d: deciding departure time" , i )
                 << endl ;
#endif
            for ( register int j = 0; j < nvoie; j++ ) {
                if ( i == j ) continue;
                if ( train_departure[ j ].is_at_station ) {
#ifdef DEBUG
                  cerr << StrPrintf ( "Track %d: train waiting" , j ) << endl ;
#endif
                continue;	// 在線してなければ考える必要なし
            }
                if ( train_departure[ j ].is_pass ) {
                    // 通過--発車時隔が問題
                    f_p_d
                        = pass_depart[ 0 ]( j, i )
                        + train_departure[ j ].tdept
                        + train_departure[ j ].tdept_delay;
                    f_res = f_p_d
                        - train_departure[ i ].tdept;
#ifdef DEBUG
                    cerr << StrPrintf ( "Track %d: pass_depart" , j ) << endl ;
#endif
                } else {
                    // 発車--発車時隔が問題
                    f_d_d
                        = depart_depart[ 0 ]( j, i )
                        + train_departure[ j ].tdept
                        + train_departure[ j ].tdept_delay;
                    f_res = f_d_d
                        - train_departure[ i ].tdept;
#ifdef DEBUG
                    cerr << StrPrintf ( "Track %d: depart_depart" , j )
                         << endl ;
#endif
                }

#ifdef DEBUG
            cerr << StrPrintf ( "f_res: %7.2f" , f_res ) << endl ;
#endif

                if ( train_departure[ i ].tdept_delay < f_res ) {
                    train_departure[ i ].tdept_delay = f_res;
                }
            }
        }

        // アプローチする列車の発着・通過関係の制約
        for ( i = 0; i < number(); i++ ) {
            int nvoie_j = data[ i ].voie;
            int nvoie_i;
            data[ i ].tarr_delay = 0.0;	// まずはゼロから
            if ( i == 0 ) {	// 最初のデータに対しては先頭から
#ifdef DEBUG
              cerr << "First train in to_station" << endl ;
#endif
                for ( nvoie_i = 0; nvoie_i < nvoie; nvoie_i++ ) {
                    // nvoie_i: 先行列車の番線
                    // nvoie_j: 当該列車の番線
                    if ( nvoie_i == nvoie_j ) {
                        // 同一番線着発
                        if ( ( ! train_departure[ nvoie_i ].is_pass )
                             && ( ! data[ i ].is_pass ) ) {
                            // 発車--到着時隔が問題
                            f_d_a
                                = depart_arrival[ 0 ]( nvoie_i, nvoie_j )
                                + train_departure[ nvoie_i ].tdept
                                + train_departure[ nvoie_i ].tdept_delay;
                            f_res = f_d_a
                                - data[ i ].tarrive;
#ifdef DEBUG
                            cerr << "depart_arrival" << endl ;
#endif
                        } else if
                            ( train_departure[ nvoie_i ].is_pass
                              && ( ! data[ i ].is_pass ) ) {
                            // 通過--到着時隔が問題
                            f_p_a
                                = pass_arrival[ 0 ]( nvoie_i, nvoie_j )
                                + train_departure[ nvoie_i ].tdept
                                + train_departure[ nvoie_i ].tdept_delay;
                            f_res = f_p_a
                                - data[ i ].tarrive;
#ifdef DEBUG
                            cerr << "pass_arrival" << endl ;
#endif
                        } else if
                            ( ( ! train_departure[ nvoie_i ].is_pass )
                              && data[ i ].is_pass ) {
                            // 発車--通過時隔が問題
                            f_d_p
                                = depart_pass[ 0 ]( nvoie_i, nvoie_j )
                                + train_departure[ nvoie_i ].tdept
                                + train_departure[ nvoie_i ].tdept_delay;
                            f_res = f_d_p
                                - data[ i ].tarrive;
#ifdef DEBUG
                            cerr << "depart_pass" << endl ;
#endif
                        } else {
                            // 通過--通過時隔が問題
                            f_p_p
                                = pass_pass[ 0 ]( nvoie_i, nvoie_j )
                                + train_departure[ nvoie_i ].tdept
                                + train_departure[ nvoie_i ].tdept_delay;
                            f_res = f_p_p
                                - data[ i ].tarrive;
#ifdef DEBUG
                            cerr << "pass_pass" << endl ;
#endif
                        }
                    } else {
                        // 異番線着発
                        if ( ( ! train_departure[ nvoie_i ].is_pass )
                             && ( ! data[ i ].is_pass ) ) {
                            // 到着--到着時隔が問題
                            f_a_a
                                = arrival_arrival[ 0 ]( nvoie_i, nvoie_j )
                                + train_departure[ nvoie_i ].tarrive;
                            f_res = f_a_a
                                - data[ i ].tarrive;
#ifdef DEBUG
                            cerr << "arrival_arrival" << endl ;
#endif
                        } else if
                            ( train_departure[ nvoie_i ].is_pass
                              && ( ! data[ i ].is_pass ) ) {
                            // 通過--到着時隔が問題
                            f_p_a
                                = pass_arrival[ 0 ]( nvoie_i, nvoie_j )
                                + train_departure[ nvoie_i ].tdept
                                + train_departure[ nvoie_i ].tdept_delay;
                            f_res = f_p_a
                                - data[ i ].tarrive;
#ifdef DEBUG
                            cerr << "pass_arrival" << endl ;
#endif
                        } else if
                            ( ( ! train_departure[ nvoie_i ].is_pass )
                              && data[ i ].is_pass ) {
                            // 到着--通過時隔が問題
                            f_a_p
                                = arrival_pass[ 0 ]( nvoie_i, nvoie_j )
                                + train_departure[ nvoie_i ].tarrive;
                            f_res = f_a_p
                                - data[ i ].tarrive;
#ifdef DEBUG
                            cerr << "arrival_pass" << endl ;
#endif
                        } else {
                            // 通過--通過時隔が問題
                            f_p_p
                                = pass_pass[ 0 ]( nvoie_i, nvoie_j )
                                + train_departure[ nvoie_i ].tdept
                                + train_departure[ nvoie_i ].tdept_delay;
                            f_res = f_p_p
                                - data[ i ].tarrive;
#ifdef DEBUG
                            cerr << "pass_pass" << endl ;
#endif
                        }
                    }
//                     if ( f_res < 0.0 ) f_res = 0.0;
#ifdef DEBUG
                    cerr << StrPrintf ( "f_res: %7.2f" , f_res ) << endl ;
#endif
                    if ( data[ i ].tarr_delay < f_res ) {
                        data[ i ].tarr_delay = f_res;
                    }
                }
            } else {	// i > 0
                // 2番目以降の列車は前の列車に対するもので検討
                // voie_i: 先行列車の番線
                // voie_j: 当該列車の番線
#ifdef DEBUG
              cerr << "Successive train in to_station" << endl ;
#endif
                nvoie_i = data[ i - 1 ].voie;
//                 nvoie_j = data[ i ].voie;
                if ( nvoie_i == nvoie_j ) {
                    // 同一番線着発
                    if ( ( ! data[ i - 1 ].is_pass )
                         && ( ! data[ i ].is_pass ) ) {
                        // 発車--到着時隔が問題
                        f_d_a
                            = depart_arrival[ 0 ]( nvoie_i, nvoie_j )
                            + data[ i - 1 ].tarrive
                            + data[ i - 1 ].tarr_delay
                            + data[ i - 1 ].tstop;
                        f_res = f_d_a
                            - data[ i ].tarrive;
#ifdef DEBUG
                        cerr << "departure-arrival" << endl
                             << StrPrintf ( "f_res: %7.2f" , f_res ) << endl ;
#endif
                    } else if
                        ( data[ i - 1 ].is_pass
                          && ( ! data[ i ].is_pass ) ) {
                        // 通過--到着時隔が問題
                        f_p_a
                            = pass_arrival[ 0 ]( nvoie_i, nvoie_j )
                            + data[ i - 1 ].tarrive
                            + data[ i - 1 ].tarr_delay;
                        f_res = f_p_a
                            - data[ i ].tarrive;
                    } else if
                        ( ( ! data[ i - 1 ].is_pass )
                          && data[ i ].is_pass ) {
                        // 発車--通過時隔が問題
                        f_d_p
                            = depart_pass[ 0 ]( nvoie_i, nvoie_j )
                            + data[ i - 1 ].tarrive
                            + data[ i - 1 ].tarr_delay
                            + data[ i - 1 ].tstop;
                        f_res = f_d_p
                            - data[ i ].tarrive;
                    } else {
                        // 通過--通過時隔が問題
                        f_p_p
                            = pass_pass[ 0 ]( nvoie_i, nvoie_j )
                            + data[ i - 1 ].tarrive
                            + data[ i - 1 ].tarr_delay;
                        f_res = f_p_p
                            - data[ i ].tarrive;
                    }
                } else {
                    // 異番線着発
                    if ( ( ! data[ i - 1 ].is_pass )
                         && ( ! data[ i ].is_pass ) ) {
                        // 到着--到着時隔が問題
                        f_a_a
                            = arrival_arrival[ 0 ]( nvoie_i, nvoie_j )
                            + data[ i - 1 ].tarrive
                            + data[ i - 1 ].tarr_delay;
                        f_res = f_a_a
                            - data[ i ].tarrive;
                    } else if
                        ( data[ i - 1 ].is_pass
                          && ( ! data[ i ].is_pass ) ) {
                        // 通過--到着時隔が問題
                        f_p_a
                            = pass_arrival[ 0 ]( nvoie_i, nvoie_j )
                            + data[ i - 1 ].tarrive
                            + data[ i - 1 ].tarr_delay;
                        f_res = f_p_a
                            - data[ i ].tarrive;
                    } else if
                        ( ( ! data[ i - 1 ].is_pass )
                          && data[ i ].is_pass ) {
                        // 到着--通過時隔が問題
                        f_a_p
                            = arrival_pass[ 0 ]( nvoie_i, nvoie_j )
                            + data[ i - 1 ].tarrive
                            + data[ i - 1 ].tarr_delay;
                        f_res = f_a_p
                            - data[ i ].tarrive;
                    } else {
                        // 通過--通過時隔が問題
                        f_p_p
                            = pass_pass[ 0 ]( nvoie_i, nvoie_j )
                            + data[ i - 1 ].tarrive
                            + data[ i - 1 ].tarr_delay;
                        f_res = f_p_p
                            - data[ i ].tarrive;
                    }
                }
//                 if ( f_res < 0.0 ) f_res = 0.0;
                if ( data[ i ].tarr_delay < f_res ) {
                    data[ i ].tarr_delay = f_res;
                }
            }
        }

        break;
    }	// switch 文の終わり
}

// 時隔の計算・初期化時
void station_obj::headway_cal_init
() {
    // 停車中の列車に対して notrw をつける
    // 矛盾なしと仮定し、発車予定時刻の速い順につける
    for ( register int i = 0; i < nvoie; i++ ) {
        int xnotrw = 0;
        for ( register int j = 0; j < nvoie; j++ ) {
            if ( i == j )
                continue;
            if ( train_departure[ j ].tdept <
                 train_departure[ i ].tdept ) {
                xnotrw++;
            }
        }
        train_departure[ i ].notrw = xnotrw;
    }

    // to_station 配列中の列車をソート
    // 矛盾なしと仮定し、到着予定時刻の速い順に
    if ( number() != 0 ) {
        qsort( data, number(), sizeof( to_station ), arrivalcomp );
    }

    // 時隔計算
    headway_cal();
}
