a
    l{i;                     @   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 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TRAMZZETTRAINBUSMETROZFERRYu
   NÄRTRAFIK)r      g   i  i  i  i  i  i  i  i  i  i  d   i  i  i  i  i  c                   @   s:   e Zd Zeeeed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	|sRt 
| t|rft|rtd tj| ddd}t }||j t|}|| W d    n1 s0    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 r1   /var/www/html/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   r1   r1   r2   r$   >   s
    
z!GtfsArchiveFetcher.archive_existsc                 C   sT   t jt j| d}t|}t | tddk}|rFt	d n
t	d |S )Nr4      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_outdatedr1   r1   r2   r%   D   s    

z&GtfsArchiveFetcher.is_archive_outdatedN)__name__
__module____qualname__staticmethodstrr3   r$   r%   r1   r1   r1   r2   r   (   s   
r   c                   @   s   e Zd ZdAeeedddZdd Ze	 e
dd e	 e
d	d
 feeeedddZeedddZdd ZeeeedddZeeeedddZeeeedddZeeedddZdd Zd d! Zeeed"d#d$Zeed%d&d'Ze d(kre Zeej eej Z!e!ej e"d)Z#e!$e# e%e! e&j'd*d+Z(e(j)*  e(+d,Z,e(+d-Z-e,j.d.d/d0d1d2 e,j.d3d4d5d1d6 e,j.d7d8d9d1d6 e,j.d:d;d<d1d6 e(/ Z0ee0j1e0j2Z3e45e0j6d=Z7e8e7e3d1d>Z9e9d?Z:e;e: d@S )B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...rD   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)selfrB   rC   rD   r1   r1   r2   __init__S   s    



zTimeTableQueryEngine.__init__c                    s    fdd j  D S )Nc                    s"   g | ]}|d  dkr  |qS )Zlocation_type1)_gtfs_stop_to_api_stop.0stoprN   r1   r2   
<listcomp>e   s   z=TimeTableQueryEngine.list_queryable_stops.<locals>.<listcomp>)rI   Zget_all_stopsrU   r1   rU   r2   list_queryable_stopsd   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 )Nr6   r7   c                 S   s   | d S )Ndeparture_secondsr1   )itemr1   r1   r2   <lambda>v       zBTimeTableQueryEngine.create_departures_timetable.<locals>.<lambda>)key)r   _get_queried_stop_ids_get_stop_times_for_stops_filter_stop_times_windowsort_compile_results)rN   r\   r]   r^   Zquery_stop_ids
stop_timesZstop_times_in_windowr1   r1   r2   create_departures_timetableh   s    

z0TimeTableQueryEngine.create_departures_timetable)query_idr   c                 C   sR   t d | j|}|d r.| j|d }|d gdd | j|d D  S )NzGetting related stopsZparent_stationstop_idc                 S   s   g | ]}|d  qS )rl   r1   rR   r1   r1   r2   rV      rb   z>TimeTableQueryEngine._get_queried_stop_ids.<locals>.<listcomp>)r&   rJ   rI   get_stopZget_all_quays_in_stop_place)rN   rk   rT   r1   r1   r2   rd   z   s    
z*TimeTableQueryEngine._get_queried_stop_idsc                 C   s   t d | j|S )NzGetting stop times for stops)r&   rJ   rK   Zget_stop_times_for_stops)rN   Zstop_idsr1   r1   r2   re      s    
z.TimeTableQueryEngine._get_stop_times_for_stops)ri   r]   r^   r   c                 C   s   t d |jd |jd  |j }|jd |jd  |j }g }|D ]f}|d }| |||sbqF| j|d }	|	d }
||kr| }n| }| j	
|
|rF|| qF|S )NzFiltering stop times  <   r_   trip_id
service_id)r&   rJ   hourminutesecond_is_time_in_windowrM   get_tripdaterH   Zis_servicedappend)rN   ri   r]   r^   Zwindow_start_secsZwindow_end_secsZfiltered_stop_times	stop_timeZsecs_since_midnighttriprq   Zservice_dater1   r1   r2   rf      s     

z.TimeTableQueryEngine._filter_stop_times_window)seconds_since_midnightwindow_start_since_midnightwindow_end_since_midnightr   c                 C   s@   |dkr|d8 }||kr0||  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 r1   rN   r{   r|   r}   r1   r1   r2   ru      s    z'TimeTableQueryEngine._is_time_in_windowc                 C   s\   ||  ko|k n  pZ||  ko4|  ko4dkn  pZ||  k oV|  koVdk S   S )Nr   i_ r1   r~   r1   r1   r2   Z__is_time_in_window   s
      z(TimeTableQueryEngine.__is_time_in_window)ri   searched_stop_idsr   c                    s  t d t }z|D ]z}t|  j|d } j|d } |d } j	
|d |d } j	|d }	 j	|d }
|d dkrzH|d } j|}|d d } j|}|d	p|d
|d< W n. ty } zt| W Y d }~n
d }~0 0 zt|d t|d  }W n   d}Y n0 |d |d  |d ||tt|d  |d |d ||	|
|d}||vr|| qW n8 ty } ztd td| W Y d }~n
d }~0 0  fdd|D |dS )NzCompiling resultsrp   Zroute_idrl   Zstop_sequenceZstop_headsign zstop_name:fr	stop_nameZpickup_typeZdrop_off_typeZdeparture_timeZ
route_typeZroute_long_nameZroute_short_name)	directionZscheduled_departure_timerealtime_departure_timerT   typeZ
route_longroute_shortdelayposition	occupancydrop_sumz$Entries error ##################### zERROR: c                    s   g | ]}  |qS r1   )_gtfs_stop_id_to_api_stop)rS   rl   rU   r1   r2   rV     rb   z9TimeTableQueryEngine._compile_results.<locals>.<listcomp>)stops
departures)r&   rJ   listr   rM   rv   rL   Z	get_router   rG   Zget_delay_for_trip_stopZget_position_for_tripZget_occupancy_for_triprK   Zget_stop_times_for_triprI   rm   r)   	Exceptionint_add_secondsROUTE_TYPE_NAMESrx   )rN   ri   r   entriesry   rz   routerT   r   r   r   rp   Z
trip_stopsZfinal_stop_idZ
final_stoper   totalr1   rU   r2   rh      sT    



.	 z%TimeTableQueryEngine._compile_resultsc                 C   s   |  | j|S )N)rQ   rI   rm   )rN   rl   r1   r1   r2   r     s    z.TimeTableQueryEngine._gtfs_stop_id_to_api_stopc                 C   s,   d|d< |d |d |d |d |d dS )N0Zplatform_coderl   r   Zstop_latZstop_lon)idnameplatformZlatitudeZ	longituder1   )rN   rT   r1   r1   r2   rQ     s    z+TimeTableQueryEngine._gtfs_stop_to_api_stop)timesecondsr   c                 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)rN   r   r   Ztime_secondsdtr1   r1   r2   r   /  s     z!TimeTableQueryEngine._add_seconds)time_strr   c                 C   s0   | d\}}}t|d t|d  t| S )N:rn   ro   )splitr   )rN   r   hmsr1   r1   r2   r   5  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/rE   Z9021012080000000N)F)<r<   r=   r>   r@   r
   boolrO   rW   r   r;   r   objectrj   r   rd   re   rf   r   ru   Z(_TimeTableQueryEngine__is_time_in_windowrh   r   rQ   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   r3   r   	gtfs_pathrA   query_engineresultr   r1   r1   r1   r2   rA   Q   s|   
! 
B








rA   )r   r   r&   r   r   r,   r   ior   r(   r   ZGtfsCacheHelpersr   r   r   r   r	   r
   r   r   rA   r1   r1   r1   r2   <module>   sB   )