o
    kiB                     @   s  d dl Z d dlZd dlZd dlZd dlZd dlZd dlmZmZ d dlmZ d dl	Z	d dl
Z
d dlmZmZmZmZmZ d dlmZ i d dddd	d
dd
dddddddddddddddddddddd
ddddddddZG dd dZG d d! d!ZdS )"    N)datetime	timedelta)BytesIO)GtfsStopsCacheGtfsRoutesCacheGtfsTripsCacheGtfsStopTimesCacheGtfsCalendarDatesCache)RealtimeDataFetcherTRAM   ZZETg   TRAINm   i  BUSi  i  i  i  i  i  i  i  i  d   i  METROi  ZFERRYu
   NÄRTRAFIK)i  i  i  c                   @   s>   e Zd ZedededefddZedd Zedd	 Zd
S )GtfsArchiveFetcherurl	directoryreturnc                 C   s   t jtj| jdd }td| t jt  ||}t j	|s)t 
| t|r3t|rdtd tj| ddd}t }||j t|}|| W d    |S 1 s_w   Y  |S )Nr   z
FILENAME: zUpdating GTFS archiveTF)allow_redirectsverify)ospathbasenameurllib3util	parse_urlprintjoingetcwdexistsmakedirsr   archive_existsis_archive_outdatedlogginginforequestsgetr   writecontentzipfileZipFile
extractall)r   r   filenameZdirectory_pathrZzipdataZzip_ref r2   \C:\Users\computer\Desktop\notes\tskylt4.0\server\20260128 - new GTFS loader\GtfsTimeTable.pyfetch_and_extract+   s$   




z$GtfsArchiveFetcher.fetch_and_extractc                 C   s.   t j| ot j| ot jt j| dS )Nfeed_info.txt)r   r   r#   isdirr!   )r   r2   r2   r3   r%   ?   s
   
z!GtfsArchiveFetcher.archive_existsc                 C   sV   t jt j| d}t|}t | tddk}|r$t	d |S t	d |S )Nr5      daysz GTFS archive is older than 1 dayz#GTFS archive is less than 1 day old)
r   r   getmtimer!   r   fromtimestampnowr   r'   r(   )r   Zmodification_time_epochZcreation_timeZis_outdatedr2   r2   r3   r&   E   s   


z&GtfsArchiveFetcher.is_archive_outdatedN)__name__
__module____qualname__staticmethodstrr4   r%   r&   r2   r2   r2   r3   r   )   s    
r   c                	   @   s.  e Zd ZdIdededefddZdd Ze	 e
d	d
 e	 e
dd fdedededefddZdedefddZdd ZdedededefddZdedededefddZdedededefd d!Zded"edefd#d$Zd%d& Zd'd( Z	 d)ed*edefd+d,Zd-edefd.d/Ze d0kre Zeej eej Z!e!ej e"d1Z#e!$e# e%e! e&j'd2d3Z(e(j)*  e(+d4Z,e(+d5Z-e,j.d6d7d8d9d: e,j.d;d<d=d9d> e,j.d?d@dAd9d> e,j.dBdCdDd9d> e(/ Z0ee0j1e0j2Z3e45e0j6dEZ7e8e7e3d9dFZ9e9dGZ:e;e: dHS dHS )JTimeTableQueryEngineF	gtfs_rootrealtime_fetcherreduce_memory_usagec                 C   s   t d |rt d || _|| _t| j| _t| j| _t 	d t
| j|d| _t 	d t| j| _t| j| _t d d S )Nz!Initializing TimeTableQueryEnginezkReduced memory usage is enabled. This will reduce memory usage by up to 90%, at the cost of slower queries.z7Initializing stop times cache, this can take a while...rE   zInitialized stop times cachez Initialized TimeTableQueryEngine)r'   r(   warning_realtime_fetcherZ
_gtfs_rootr	   _calendar_dates_cacher   _stops_cachedebugr   _stop_times_cacher   _routes_cacher   _trips_cache)selfrC   rD   rE   r2   r2   r3   __init__T   s   



zTimeTableQueryEngine.__init__c                    s    fdd j  D S )Nc                    s"   g | ]}|d  dv r  |qS )Zlocation_type)01)_gtfs_stop_to_api_stop.0stoprO   r2   r3   
<listcomp>k   s
    z=TimeTableQueryEngine.list_queryable_stops.<locals>.<listcomp>)rJ   Zget_all_stopsrW   r2   rW   r3   list_queryable_stopsj   s   
z)TimeTableQueryEngine.list_queryable_stops
   )minutes   )hoursquery_stop_idwindow_start
window_endr   c                 C   s`   ||k sJ || t ddk sJ | |}| |}| |||}|jdd d | ||S )Nr7   r8   c                 S   s   | d S )Ndeparture_secondsr2   )itemr2   r2   r3   <lambda>   s    zBTimeTableQueryEngine.create_departures_timetable.<locals>.<lambda>)key)r   _get_queried_stop_ids_get_stop_times_for_stops_filter_stop_times_windowsort_compile_results)rO   r^   r_   r`   Zquery_stop_ids
stop_timesZstop_times_in_windowr2   r2   r3   create_departures_timetableq   s   

z0TimeTableQueryEngine.create_departures_timetablequery_idc              
   C   s   t d | j|}|d r1z
| j|d }W n ty0 } ztd| W Y d }~nd }~ww |d gdd | j|d D  S )NzGetting related stopsZparent_stationz_get_queried_stops-error: stop_idc                 S   s   g | ]}|d  qS )rm   r2   rT   r2   r2   r3   rX      s    z>TimeTableQueryEngine._get_queried_stop_ids.<locals>.<listcomp>)r'   rK   rJ   get_stop	Exceptionr    Zget_all_quays_in_stop_place)rO   rl   rV   er2   r2   r3   re      s   
z*TimeTableQueryEngine._get_queried_stop_idsc              	      s   t d t d|  |D ]1  | jjv }t d  d|  |s@ fdd| jj D }t d  d|d d	   qt d
t| j  | j|S )NzGetting stop times for stopszRequested stop_ids: zStop ID z exists in _stops_by_id: c                    s    g | ]} |v s| v r|qS r2   r2   )rU   kZsidr2   r3   rX      s     zBTimeTableQueryEngine._get_stop_times_for_stops.<locals>.<listcomp>zSimilar keys for z: rZ   zStopTimesCache attributes: )r'   rK   rJ   Z_stops_by_idkeysdirrL   Zget_stop_times_for_stops)rO   Zstop_idsr#   closer2   rr   r3   rf      s   
z.TimeTableQueryEngine._get_stop_times_for_stopsrj   c                 C   s   t d |jd |jd  |j }|jd |jd  |j }g }|D ]3}|d }| |||s1q#| j|d }	|	d }
||krF| }n| }| j	
|
|rV|| q#|S )NzFiltering stop times  <   ra   trip_id
service_id)r'   rK   hourminutesecond_is_time_in_windowrN   get_tripdaterI   Zis_servicedappend)rO   rj   r_   r`   Zwindow_start_secsZwindow_end_secsZfiltered_stop_times	stop_timeZsecs_since_midnighttripry   Zservice_dater2   r2   r3   rg      s"   


z.TimeTableQueryEngine._filter_stop_times_windowseconds_since_midnightwindow_start_since_midnightwindow_end_since_midnightc                 C   s@   |dkr|d8 }||kr||  ko|k S   S ||kp||k S )u   
        Robust midnight-safe window check.
        Handles:
        - windows that do NOT cross midnight
        - windows that DO cross midnight (e.g. 23:00 → 01:00)
        - GTFS times > 24:00 (e.g. 25:10:00)
        iQ r2   rO   r   r   r   r2   r2   r3   r}      s   z'TimeTableQueryEngine._is_time_in_windowc                 C   s\   ||  ko	|k n  p-||  ko|  kodkn  p-||  k o+|  ko+dk S   S )Nr   i_ r2   r   r2   r2   r3   Z__is_time_in_window   s    z(TimeTableQueryEngine.__is_time_in_windowsearched_stop_idsc                    s  t d t }z|D ]}td|  j|d } j|d } |d } j	
|d |d } j	|d }	 j	|d }
|d dkrz$|d } j|}|d	 d } j|}|d
pj|d|d< W n ty } ztd| W Y d }~nd }~ww zt|d t|d  }W n   d}Y |d |d  |d ||tt|d  |d |d ||	|
|d}||vr|| qW n ty } ztd td| W Y d }~nd }~ww z fdd|D |dW S  ty	 } zt| W Y d }~d S d }~ww )NzCompiling resultszFOR stop_time in stop_times: rx   Zroute_idrm   Zstop_sequenceZstop_headsign zstop_name:fr	stop_namez_compile_results-error: Zpickup_typeZdrop_off_typeZdeparture_timeZ
route_typeZroute_long_nameZroute_short_name)	directionZscheduled_departure_timerealtime_departure_timerV   typeZ
route_longroute_shortdelayposition	occupancydrop_sumz$Entries error ##################### zERROR: c                    s   g | ]}  |qS r2   )_gtfs_stop_id_to_api_stop)rU   rm   rW   r2   r3   rX   2  s    z9TimeTableQueryEngine._compile_results.<locals>.<listcomp>)stops
departures)r'   rK   listr    rN   r~   rM   Z	get_router   rH   Zget_delay_for_trip_stopZget_position_for_tripZget_occupancy_for_triprL   Zget_stop_times_for_triprJ   rn   r*   ro   int_add_secondsROUTE_TYPE_NAMESr   )rO   rj   r   entriesr   r   routerV   r   r   r   rx   Z
trip_stopsZfinal_stop_idZ
final_stoprp   r   totalr2   rW   r3   ri      sh   



$ 	6z%TimeTableQueryEngine._compile_resultsc                 C   s   |  | j|S )N)rS   rJ   rn   )rO   rm   r2   r2   r3   r   7  s   z.TimeTableQueryEngine._gtfs_stop_id_to_api_stopc                 C   s,   d|d< |d |d |d |d |d dS )NrQ   Zplatform_coderm   r   Zstop_latZstop_lon)idnameplatformZlatitudeZ	longituder2   )rO   rV   r2   r2   r3   rS   ;  s   z+TimeTableQueryEngine._gtfs_stop_to_api_stoptimesecondsc                 C   s8   |  || }tt tj t|d }|dS )N)r   z%H:%M:%S)get_seconds_since_midnightr   combinetodayminr   r   strftime)rO   r   r   Ztime_secondsdtr2   r2   r3   r   R  s    
z!TimeTableQueryEngine._add_secondstime_strc                 C   s0   | d\}}}t|d t|d  t| S )N:rv   rw   )splitr   )rO   r   hmsr2   r2   r3   r   X  s    z/TimeTableQueryEngine.get_seconds_since_midnight__main__z4%(asctime)s - %(name)s - %(levelname)s - %(message)szPCLI script to get a realtime timetable for a stop based on GTFS and GTFS-RT data)descriptionzrequired argumentszoptional argumentsz--gtfsgtfs_urlzPthe url to the gtfs zip file. Include an API key if the gtfs feed requires this.T)desthelprequiredz--trip-updateszZthe url to the tripupdates.pb file. Include an API key if the realtime feed requires this.trip_updates)r   r   r   z--vehicle-positionsz_the url to the vehiclepositions.pb file. Include an API key if the realtime feed requires this.vehicle_positionsz	--stop-idz,the id of the stop to create a timetable forzstop-idzgtfs/rF   Z9021012080000000N)F)<r=   r>   r?   rA   r
   boolrP   rY   r   r<   r   objectrk   r   re   rf   rg   r   r}   Z(_TimeTableQueryEngine__is_time_in_windowri   r   rS   r   r   r'   	getLoggerrootsetLevelWARNStreamHandlersysstdouthandler	Formatter	formattersetFormatter
addHandlerargparseArgumentParserparserZ_action_groupspopadd_argument_groupr   optionaladd_argument
parse_argsargsr   r   Zrealtime_data_fetcherr   r4   r   	gtfs_pathrB   query_engineresultr    r2   r2   r2   r3   rB   R   s    	
 


D








rB   )r   r   r'   r   r   r-   r   ior   r)   r   ZGtfsCacheHelpersr   r   r   r   r	   r
   r   r   rB   r2   r2   r2   r3   <module>   sj    	
)