o
    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Zd dlZd dl	m
  mZ d dlmZ d dlmZmZ dZdZdZdZdd	d
ddddZg d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/d0d1Zd2d3 Zd4d5 Zd6d7 Zd@d9d:Zd;d< ZdAd=d>ZdBd@dAZdCdCdDZdDdFdGZ dHdI Z!dJdK Z"dLdM Z#dEdOdPZ$dQdR Z%dSdT Z&dUdV Z'dWdX Z(dYdZ Z)d[d\ Z*d]d^ Z+d_d` Z,dadb Z-dFdcddZ.dedf Z/dAdgdhZ0didj Z1dkdl Z2dmdn Z3dodp Z4dqdr Z5d@dsdtZ6dudv Z7dAdwdxZ8dGdydzZ9d{d| Z:d}d~ Z;dd Z<dd Z=dd Z>dd Z?dHddZ@dd ZAdd ZBdd ZCdd ZDdAddZEdAddZFdAddZGdAddZHdAddZIdd ZJdGddZKdGddZLdAddZMdd ZNdIddZOdAddZPdAddZQdd ZRdd ZSdd ZTdd ZUdJddZVdAddZWdd ZXdd ZYdd ZZdd Z[dJddZ\dJddĄZ]ddƄ Z^ddȄ Z_dKddʄZ`dKdd̄Zadd΄ ZbddЄ Zcdd҄ ZdddԄ Zeddք ZfdLdd؄ZgdJddڄZhdBdd܄Ziddބ ZjdMddZkdd Zldd Zmdd Zndd Zodd ZpdAddZqdd Zrdd Zsdd ZtdNddZudAddZvdd Zwdd Zxdd Zydd Zzdd  Z{dOddZ|dd Z}dAddZ~dd	 ZdJd
dZdAddZdPddZdd Zdd ZdJddZdd ZdMddZdJddZdJddZdd Zd d! Zd"d# Zd$d% ZdJd&d'ZdJd(d)Zd*d+ Zd,d- ZdFd.d/Zd0d1 Zd2d3 Zd4d5 Zd6d7 Zd8d9 Zd:d; ZdFd<d=Zd>d? ZdS (Q      N)deepcopy)datetime	timedelta   출근   퇴근
   ztransit_db.json)u4   서울교통공사_노선별 지하철역 정보.csvu+   서울시 지하철 노선별 역정보.csvz+pJAzwA1O0a1Om/kUegbS/vqK8jD+ProL+Ph2RhIl7VwZ7142474d556b696d383570414f6a52Z@b416f73a5840954c79b8b4e34005cb18df555284583a3a2bff7c304b1449b980Z476c4342646b696d38387045694a65z'AIzaSyC7f5hegysRFSXHxwurFwLl-BUf0RuYTPoZ 4213a733f9c3b7e3b8824674aebff659)odsaysubway	busArriveZbusStopLocationgoogleDirectionskakao)   1호선   2호선   3호선   4호선   5호선   6호선   7호선   8호선   9호선   경의중앙   수인분당   경춘   공항철도	   신분당   우이신설   서해   신림u   김포골드Z1001r   Z1002r   Z1003r   Z1004r   Z1005r   Z1006r   Z1007r   Z1008r   Z1009r   Z1063r   Z1065r   Z1067r   Z1075r   Z1077r   Z1092r   Z1093r   Z1094r   c                   C   s   t tS N)r   DEFAULT_API_KEYS r!   r!   &/home/kim/smarthome/commute_backend.pydefault_api_keysI   s   r#   c                 C   s8   t  }t| tr|D ]}t| |}|r|||< q
|S r   )r#   
isinstancedict_normalize_labelget)valuemergedkey	candidater!   r!   r"   merge_api_keysM   s   
r,   c                  C   s   t  } d| _t j| _| S NF)sslcreate_default_contextcheck_hostname	CERT_NONEverify_mode)ctxr!   r!   r"   _ssl_ctxW   s   r4   Fc                 C   s~   t jj| |p	ddid}d|i}|rt |d< t jj|fi |}| jddd}W d    n1 s5w   Y  t|S 	N
User-AgentMozilla/5.0)headerstimeoutcontextutf-8replace)errors)	urllibrequestRequestr4   urlopenreaddecodejsonloads)urlr9   r8   use_sslreqkwargsresprawr!   r!   r"   _request_json^   s   

rL   c                   C   s   t   S r   )r   now	isoformatr!   r!   r!   r"   _now_isoh      rO   c              	   C   s&   zt | W S  ttfy   | Y S w r   )float	TypeError
ValueErrorr(   defaultr!   r!   r"   _parse_floatl   s
   
rV    c                 C   s   t | p| S r   )strstriprT   r!   r!   r"   r&   s      r&   busc                 C   s   | dkrdS |S )Nr
   r!   rT   r!   r!   r"   _normalize_transport_typew   rZ   r\   pointc                 C   s*   t | t|t||d}|r||d< |S )N)labellatlngtypemeta)r&   rV   )r^   r_   r`   
point_typerb   r]   r!   r!   r"   _point{   s   rd   c                 C   s.   t | tot| dd uot| dd uS )Nr_   r`   )r$   r%   rV   r'   )r]   r!   r!   r"   _valid_point   s   .re   c                   C   s   dd d d d d g d d d d dS )Nidle)journey_phasestart_triggered_atboarding_confirmed_atlast_known_positionlast_known_position_updated_atnearest_segment_reflive_candidate_tripslive_boardable_triplive_vehicle_markerlive_position_markerlive_train_positionr!   r!   r!   r!   r"   default_runtime_state   s   rr   c                   C   s6   ddddd d d d g ddd d d d d ddd t  dS )Nr[   rW   manual)origin_modefrom_address	from_stopto_stop
to_addressshared_routes)rt   ru   from_stationvia_station
to_stationrx   )transport_typedisplay_start_namedisplay_end_namer[   r
   )config	last_planruntime_state)rr   r!   r!   r!   r"   default_mode_bucket   s*   	r      c                 C   s(   d|  t |d|  t t ddS )Npreset-u
   프리셋 r   )idr^   modes)r&   r   )indexr^   r!   r!   r"   default_preset   s   r   c                   C   s   dddddt  tdgdS )N   zpreset-1r   ZdarkTr   )versionactivePresetId
activeModethemeshowOnDashboardapiKeyspresets)r#   r   r!   r!   r!   r"   default_commute_state   s   r   c                 C   s   | dkrdS dS )Nr   r   r!   r(   r!   r!   r"   _normalize_mode_name   rZ   r   c                 C   s8   t | trdd |  D S t | trdd | D S | S )Nc                 S   s   i | ]	\}}|t |qS r!   _clean_object).0kvr!   r!   r"   
<dictcomp>       z!_clean_object.<locals>.<dictcomp>c                 S   s   g | ]}t |qS r!   r   )r   r   r!   r!   r"   
<listcomp>       z!_clean_object.<locals>.<listcomp>)r$   r%   itemslistr   r!   r!   r"   r      s
   

r   c                 C   s  t | pi }t }d|d< |dp|d |d< |dd|d< t|d|d< g }t }t|dp5g dd	D ]\}}t |pBi }t|d
d| }||v rZ| d| }|| t||d}||d
< t|d|d |d< |dp}i }	t	D ]}
t |	|
pi }t
 }t|dtrt|d d|d d |d d< t|d dd|d d< t|d dd|d d< |d d |d dpi  |d d |d dpi  |d ds|d d ds|d d drd|d d< |dr|d|d< |dpi }t }|| ||d< ||d |
< q|| t|tkr= nq9|sE|d }||d< t|d|d d
 }|dd |D vre|d d
 }||d< t|d|d< t|S )Nr   r   r   r   Tr   r   r   startr   r   -r^   r   r   r}   r~   rW   r   r[   r
   rz   r|   r   r   r   r   c                 S   s   h | ]}|d  qS )r   r!   )r   pr!   r!   r"   	<setcomp>  r   z*normalize_commute_state.<locals>.<setcomp>r   )r   r   r'   r,   set	enumerater&   addr   
MODE_NAMESr   r$   r%   r\   updaterr   appendlenPRESET_LIMITr   r   )staterootZdefault_rootr   Zseen_idsidxpreset	preset_id
normalizedr   	mode_nameZ
raw_bucketbucketruntimeZmerged_runtimeZactive_presetr!   r!   r"   normalize_commute_state   sv    

  (

r   c                 C   sf  t | tst S t | dtr| d drt| d S | dr&t| S t | dtr3| dn| }|dr>t|S t }|dpI|d |d< |dd|d< t|d|d< t|d|d< |d	plg }|rg |d< t|d t d
dD ]\}}t	||d}|dpi }|dpi }|dpi }	t
D ]}
|d |
 }tdd |	|
g D d }tdd |	|
g D d }|r|d d }d|d d< t||
|d|dd|d< t|d|d|dd|d|dd |d!< t||
d d d|d"< t|d#pg |d$< |r|d d% }|s-d%|d d< t||
|d|dd|d< t|d&|d'|d(d)d*|d+i|d,< |d-p^g }|rmt|d. d d d)|d/< t|d0d d d)|d1< t||
d d d|d"< q|d | q~ttt|d2d.pd.d.t|d d
 }|d | d* |d3< t|S )4NcommuteConfigr   r   r   TZcommuteModer   r   membersr   r   r^   departarriveroutesr   c                 s   "    | ]}| d dkr|V  qdS )ra   r[   Nr'   r   rr!   r!   r"   	<genexpr>0       z)migrate_legacy_payload.<locals>.<genexpr>c                 s   r   )ra   r
   Nr   r   r!   r!   r"   r   1  r   r   r[   r}   ZfromYZfromXaddressru   ZbusStopNameZbusStopYZbusStopXbus_stopZ	busStopId)r   arsIdrv   rx   Z	busRoutesry   r
   stationNameZstationYZstationXsubway_stationr   	stationIdrz   Z	waypointsr   r{   ZdestStationr|   ZactiveMemberr   )r$   r%   r   r'   r   r   r,   r   r   r   r   nextrd   r   r   minmaxintr   )payloadZlegacyr   r   r   memberr   r   r   r   r   r   Z	bus_routeZsubway_routebus_cfg
subway_cfgZvia_listZactive_indexr!   r!   r"   migrate_legacy_payload  sz   


$$.r   c                 C   s   t | pi dS )Nr   )r,   r'   )r   r!   r!   r"   get_api_keysV  s   r   c                 C   s   t j| dtS )NZtransit_data)ospathjoinTRANSIT_DB_FILE
script_dirr!   r!   r"   _transit_db_pathZ  rZ   r   c                 C   s   t | }dd d di i i i i i i i i i d}tj|rpzIt|ddd}t|}W d    n1 s4w   Y  t|trc|	 D ]\}}||vsSt|| t
|sYt|||< qBd|d d< |W S W |S  tyo   Y |S w |S )	Nr   )r   	last_synclast_manual_update)metadataaddress_searchaddress_geocodebus_stop_searchsubway_station_searchroute_searchZcommon_routessubway_station_catalogsubway_station_catalog_metasubway_runtime_station_catalogsubway_timetabler   r;   encodingr   r   )r   r   r   existsopenrD   loadr$   r%   r   ra   r   	Exception)r   db_pathZ
default_dbfrK   r*   r(   r!   r!   r"   load_transit_db^  s@   

r   c                 C   sd   t | }tjtj|dd t|ddd}tj||ddd W d    d S 1 s+w   Y  d S )	NT)exist_okwr;   r   Fr   )ensure_asciiindent)r   r   makedirsr   dirnamer   rD   dump)r   dbr   r   r!   r!   r"   save_transit_db|  s
   "r   c                 C   s<   t | }t |d d< |r|d d |d d< t| | |S )Nr   r   r   )r   rO   r   )r   rs   r   r!   r!   r"   touch_transit_db  s   
r   c                 C   s   t |  S r   )r&   lower)textr!   r!   r"   
_cache_key  rP   r   c                 C   s   | pt  }|dS )Nz%Y-%m-%d)r   rM   strftimedttargetr!   r!   r"   _today_cache_key  s   
r   c                 C   s8   t | dd}td|}|rt|d dS |S )N rW   u   0*([1-9])호선r      호선)r&   r<   researchr   group)r(   r   matchr!   r!   r"   _normalize_line_key_text  s
   r  c                 C   s"   t |  }dd td|D S )Nc                 S   s    g | ]}|  rt|n|qS r!   )isdigitr   )r   tokenr!   r!   r"   r          z-_natural_station_sort_key.<locals>.<listcomp>z(\d+))r&   upperr  splitr(   r   r!   r!   r"   _natural_station_sort_key  s   r  c                 C   sD   t t| dd}|dd}|drt|S t||ddS )Nu	   수도권rW   r   r  0)r  r&   r<   endswith_extract_subway_line_keyr  r!   r!   r"   _normalize_line_key_from_csv  s
   
r  c                 C   s   g }t D ])}|tj| | |tjtj| | |tjtjdd| qt }g }|D ]}||vrE|| || q5|S )N~Z	Downloads)	SUBWAY_STATION_INFO_FILENAMESr   r   r   r   r   
expanduserr   r   )r   pathsnameseenZorderedr   r!   r!   r"   $_candidate_subway_station_info_paths  s    

r  c                 C   sR  t | D ]}tj|sqdD ]}zt|d|dd}tt|}W d    n1 s,w   Y  |ri }|D ]8}t|	d}t
|	d}t
|	d}	|rT|rT|	sUq7||g }
|
t
|	d|t
|	d	|	d
 q7| D ]\}}i }|D ]
}||d | q|t| dd d||< qt|W     S W q ty   Y qw qi S )N)cp949zeuc-krz	utf-8-sigr   rW   )r   newliner  u   전철역명u   외부코드u   전철역코드u   전철명명(영문)station_codestation_labelstation_label_enexternal_coder  c                 S      t | dS Nr  r  r'   itemr!   r!   r"   <lambda>      z7_load_subway_station_catalog_from_csv.<locals>.<lambda>r*   )r  r   r   r   r   r   csvZ
DictReaderr  r'   r&   
setdefaultr   r   sortedvaluesr   )r   r   r   handlerowscatalogrowline_keyr  r  line_bucketr   dedupedr$  r!   r!   r"   %_load_subway_station_catalog_from_csv  sH   r3  c                 C   sx   t jj| |p	ddid}d|i}|rt |d< t jj|fi |}| jdddW  d    S 1 s5w   Y  d S r5   )r>   r?   r@   r4   rA   rB   rC   )rF   r9   r8   rG   rH   rI   rJ   r!   r!   r"   _request_text  s   
$r4  c              	   C   s,  i }| pg D ]i}dd |pi   D }tt|dt|dt|d}t|dp2|d}t|dp>|d	}t|d
pJ|d}|rT|rT|sU|sUq||g ||t|dpg|d|pk|d q|  D ]\}}i }	|D ]
}
|	|
d |
 q|t|	 dd d||< qt|S )Nc                 S      i | ]\}}t | |qS r!   rX   r
  r   r*   r(   r!   r!   r"   r         z:_normalize_subway_station_catalog_rows.<locals>.<dictcomp>ZLINE_NUMZLINEZLINE_NMZ
STATION_NMZSTATN_NMZFR_CODEZEXTERNAL_CODEZ
STATION_CDZSTATN_CDZSTATION_NM_ENGZSTATN_NM_ENGr  r  c                 S   r   r!  r"  r#  r!   r!   r"   r%     r&  z8_normalize_subway_station_catalog_rows.<locals>.<lambda>r'  )	r   r  r  r'   r&   r)  r   r*  r+  )r-  r.  r/  r+  r0  r  r  r  r   r2  r$  r!   r!   r"   &_normalize_subway_station_catalog_rows  s4   r9  c                 C   s   t j| ptd }d| d}d| d}zt|dd}|dp#i }t|dp+g }|r4|d	fW S W n	 ty>   Y nw z/t|dd}t	
|}g }	|d
D ]}
|	dd |
D  qRt|	}|rj|dfW S W i dfS  tyz   Y i dfS w )Nr
    http://openapi.seoul.go.kr:8088/z'/json/SearchSTNBySubwayLineInfo/1/1000/z&/xml/SearchSTNBySubwayLineInfo/1/1000/   r9   ZSearchSTNBySubwayLineInfor/  zapi-jsonz.//rowc                 S   s   i | ]}|j |jqS r!   )tagr   )r   childr!   r!   r"   r         z9_load_subway_station_catalog_from_api.<locals>.<dictcomp>zapi-xmlrW   )r>   parsequoter    rL   r'   r9  r   r4  ETZ
fromstringfindallr   )api_keysZ
subway_keyZjson_urlZxml_urldataservicer.  Zraw_xmlr   r-  r/  r!   r!   r"   %_load_subway_station_catalog_from_api  s8   


rG  c                 C   s   t | }|dp
i }|dpi }|r |s |dt kr |S |rBt|d\}}|rB||d< t t |p6dd|d< t| | |S |rH|sH|S t| }|rc||d< t t dd|d< t| | |S |rg|S |S )Nr   r   daterD  Zapi)rH  
updated_atsourcer(  )r   r'   r   rG  rO   r   r3  )r   rD  force_refreshr   cachedrb   r.  rK  r!   r!   r"   get_subway_station_catalog  s:   



rN  c                 C   s0   t | }t|t|pg }|r|S t| |S r   )rN  r   r'   r  _runtime_line_station_sequence)r   r0  r.  
line_itemsr!   r!   r"   _line_station_sequence@  s
   
rQ  c                    s2  t | }|dp
i t|pi }t|dpi sg S t }dd  D   fdd D }g }t }|pB|D ]9}|}	|	r||	|vr||	v r||	|	 |
|	 t|	pbi dpgd}
|
ro|
|v rpn|
}	|	r||	|vr||	v sQqC|D ]}||vr|
| qd	d fd
d|D D S )Nr   stationsc                 S   s(   h | ]}| d rt| d pdqS )next_station_idrW   r'   rX   r   r$  r!   r!   r"   r   O     ( z1_runtime_line_station_sequence.<locals>.<setcomp>c                    s8   g | ]\}}| d rt| d vs| vr|qS )prev_station_idrT  )r   
station_idr$  Zreferenced_prevrR  r!   r"   r   P  s    z2_runtime_line_station_sequence.<locals>.<listcomp>rS  rW   c                 S   sV   g | ]'}| d r| dpd| d pd| dpd| dp&| dp&ddqS )r  r  rW   r  r  r  r   rU  r!   r!   r"   r   b  s    c                 3   s    | ]
}  |p
i V  qd S r   r   )r   rX  )rR  r!   r"   r   i  s    z1_runtime_line_station_sequence.<locals>.<genexpr>)r   r'   r  r   r   keysr+  r   r   r   r   rX   )r   r0  r   r   ZidsZ	start_idsZordered_idsvisitedZstart_idZ
current_idZnext_idrX  r!   rY  r"   rO  H  s<   


rO  c                 C   s,  |sd S t | }|di }d}|D ]x}t|d|d}t|d}|r*|s+q||i d d}|d |i }	|t|dt|d	t|d
t|dt|dt|dt|d|d	}
|
 D ]\}}|r|	||kr||	|< d}qo|rt |d< q|rt| | d S d S )Nr   F	subway_idr0  rX  )rR  rJ  rR  r  r  r  r  rW  rS  )	rX  r  r  r  r  rW  rS  r\  r0  TrJ  )r   r)  r  r'   r&   r   rO   r   )r   r-  r   r.  changedr/  r0  rX  r1  Zstation_bucketZupdatesr*   r(   r!   r!   r"   "_cache_subway_runtime_station_rowsn  sB   
r^  c                 C   st   t |}|sd S t| |}t|D ]\}}t |d|kr"|  S qt|D ]\}}t|d|r7|  S q'd S )Nr  )_normalized_namerQ  r   r'   _name_matches)r   r0  r  r   r   r   r$  r!   r!   r"   _station_index_on_line  s   
ra  c                 C   s   t |}|sdS t| |}|D ]}t |d|kr(|dp%|dp%d  S q|D ]}t|d|rC|dp@|dp@d  S q+dS )NrW   r  r  r  )r_  rQ  r'   r`  )r   r0  r  r   r   r$  r!   r!   r"   _resolve_station_external_code  s   
rb  c                 C   sn   t |d|d|d}t| ||d}t| ||d}|d u s-|d u s-||kr/d S ||kr5dS dS )Nr0  
line_labelroute_labelboard_labelalight_labelr   )r  r'   ra  )r   segmentr0  board_indexZalight_indexr!   r!   r"   _subway_direction_sign  s   rj     c           
      C   s   t |d|d|d}t| |}t| ||d}t| |}|r,|d u s,|d u r.g S |dk rAtt|| d |d d}ntt||d  |d }g }|D ]}	|	dk s^|	t|kr_qR|||	 dpid	|	|kd
 qRdd |D S )Nr0  rc  rd  re  r   r   rg  r  rW   r^   boardc                 S   s   g | ]	}| d r|qS )r^   r   )r   stationr!   r!   r"   r     r   z-_static_approach_stations.<locals>.<listcomp>)	r  r'   rQ  ra  rj  r   ranger   r   )
r   rh  window_sizer0  rP  ri  direction_signZindexesrR  r   r!   r!   r"   _static_approach_stations  s&   

rr  c                 C   s   t | |pi t|S r   )r   r'   r   )r   sectionr*   r!   r!   r"   _get_cached_section     rt  c                 C   s   t || |i t|< d S r   )r   r)  r   )r   rs  r*   r(   r!   r!   r"   _put_cached_section  ru  rv  c                 C   s   |  dpi }|  dpi }|  dp(| dp(|  dp(| dp(|  dp(d| dp=|  dp=| dp=|  dp=dt|  dpL| dpL| dt|  dp\| dp\| dd	S )
NZroad_addressr   Z
place_nameZaddress_nameZroad_address_namerW   yx)r^   r   r_   r`   )r'   rV   )docZroadr   r!   r!   r"   _normalize_address_item  s   4*  rz  c                 C   sj   g }t  }| D ]+}t|d t|d |d|df}||v r(q|| || q|S )Nr^   r   r_   r`   )r   r&   r'   r   r   r   )r   r2  r  r$  r*   r!   r!   r"   _dedupe_address_items  s   
r{  c                 C   s  t | }t|d|}|d ur|S d|ptd  dd}g }dtj|}dtj|}zt|d|d	}	|d
d |		dg D  W n	 t
yP   Y nw zt|d|d	}
|dd |
	dg D  W n	 t
yq   Y nw dd t|D }t|d|| t| | |S )Nr   zKakaoAK r   r7   )Authorizationr6   zChttps://dapi.kakao.com/v2/local/search/address.json?query={}&size=8zChttps://dapi.kakao.com/v2/local/search/keyword.json?query={}&size=8   )r9   r8   c                 s       | ]}t |V  qd S r   rz  r   ry  r!   r!   r"   r         z#search_addresses.<locals>.<genexpr>Z	documentsc                 s   r~  r   r  r  r!   r!   r"   r     r  c                 S   s   g | ]}t |r|qS r!   )re   rU  r!   r!   r"   r     s    z$search_addresses.<locals>.<listcomp>)r   rt  r    formatr>   r@  rA  rL   extendr'   r   r{  rv  r   )r   queryrD  r   rM  r8   r   Zaddress_urlZkeyword_urlZaddress_dataZkeyword_datar!   r!   r"   search_addresses  s<   

  
r  c                 C   sZ   t | }t|d|}|d ur|S t| ||d}|r|d nd }t|d|| t| | |S )Nr   rI  r   )r   rt  r  rv  r   )r   r  rD  r   rM  r   bestr!   r!   r"   geocode_address  s   
r  c           	      C   s   t | }t|d|}|d ur|S dtj| dtj|ptd  }t|ddd}g }|dp3i d	p8g D ]0}||d
pCd|dpN|dpNd|dpY|dpYdt	|dt	|dd q9t
|d|| t| | |S )Nr   7https://api.odsay.com/v1/api/searchStation?stationName=z&stationClass=1&apiKey=r	   r}  Tr9   rG   resultrn  r   rW   	stationIDlocalStationIDZarsIDrw  rx  )r  r   r   r_   r`   r   rt  r>   r@  rA  r    rL   r'   r   rV   rv  r   	r   r  rD  r   rM  rF   rE  r   rn  r!   r!   r"   search_bus_stops  s0   
	
r  c           	   
   C   s   t | }t|d|}|d ur|S dtj| dtj|ptd  }t|ddd}g }|dp3i d	p8g D ]+}||d
pCd|dpN|dpNdt	|dt	|d|dp`dd q9t
|d|| t| | |S )Nr   r  z&stationClass=2&apiKey=r	   r}  Tr  r  rn  r   rW   r  r  rw  rx  ZlaneName)r  r   r_   r`   	lineNamesr  r  r!   r!   r"   search_subway_stations9  s0   
	
r  c                 C   s0   | pt  }| dkrdS | dkrdS dS )N   2   31)r   rM   weekdayr   r!   r!   r"   _seoul_week_tagU  s   r  c                 C   s   dd | pi   D }t|dp|dp|dt|dp%|dt|dp5|d	p5|d
t|dpE|dpE|dt|dpP|dt|dp`|dp`|dt|dpp|dpp|dt|dt|dd	S )Nc                 S   r5  r!   r6  r7  r!   r!   r"   r   _  r8  z,_normalize_timetable_row.<locals>.<dictcomp>ZTRAIN_NOZTRNNOZBTRAINNOZ
ARRIVETIMEZ
ARRIV_TIMEZLEFTTIMEZDEPTTIMEZDEPARTURETIMEZ
EXPRESS_YNZ	EXPRESSYNZDIRECTATZLAST_TRAIN_YNZLASTTRAIN_YNZDESTSTATIONCDZDESTSTATION_CODEZDESTSTATIONZSUBWAYSNAMEZDESTINATIONZDESTSTATIONNMZ	INOUT_TAGZWEEK_TAG)	train_noarrival_timeZdeparture_timeZ
express_ynZlast_train_ynZdest_station_codeZdest_station_name	inout_tagweek_tag)r   r&   r'   )r/  r+  r!   r!   r"   _normalize_timetable_row^  s        r  c              	   C   sl  t |}t| ||}|sg S t| }t| d| dt  }|dp%i |}	|sIt|	trI|	dt krIt|	dtrIt	|	dpGg S t
 }
g }dD ]K}dtj|pYtd  dtj| d	|
 d	| }z&t|d
d}|dpyi }|dpg D ]}t|}|d r|| qW qP ty   Y qPw t ||||t d|di |< t| | t	|S )N|r   rH  r-  )r  r  r:  r
   z*/json/SearchSTNTimeTableByIDService/1/500//r   r<  ZSearchSTNTimeTableByIDServicer/  r  )rH  r  r0  r  r-  rJ  )r  rb  r   r   r   r'   r$   r%   r   r   r  r>   r@  rA  r    rL   r  r   r   rO   r)  r   )r   r  r0  rD  rL  Zresolved_line_keyr  r   Z	cache_keyZcached_entryr  r-  r  rF   rE  rF  r/  r   r!   r!   r"   get_subway_timetable_cachedm  sb   


r  c                 C   sL   t | ||d}t| }|dpi }t|pi |dpd|dp#ddS )N)rD  rL  r   rK  rW   rJ  )subway_station_catalog_linessubway_station_catalog_sourceZ!subway_station_catalog_updated_at)rN  r   r'   r   )r   rD  rL  r.  r   rb   r!   r!   r"   refresh_long_term_transit_cache  s   
r  c           	      C   s   t | }t|d|}|d ur|S dtj| dtj|ptd  }t|ddd}g }|dp3i d	p8g D ]}||d
pCd|dpN|dpNd|dpTdd q9t	|d|| t
| | |S )Nr   z.https://api.odsay.com/v1/api/searchLane?busNo=&apiKey=r	   r}  Tr  r  lanebusNorW   busIDlaneIDra   )
busRouteNm
busRouteIdra   )r   rt  r>   r@  rA  r    rL   r'   r   rv  r   )	r   r  rD  r   rM  rF   rE  r   r  r!   r!   r"   search_bus_routes  s,   

r  c           
      C   s   d}t | }t |}t ||  }t || }t |d d t |t | t |d d   }	|d t t |	t d|	  S )Ni6a r   r   )mathradianssincosatan2sqrt)
Zlat1Zlng1Zlat2Zlng2ZradiusZp1Zp2d1Zd2ar!   r!   r"   _haversine_m  s   

8$r  K   c                 C   s   t dtt| pd| S )Nr   r   )r   r   r  ceil)
distance_mZ	speed_mpmr!   r!   r"   _minutes_from_distance  ru  r  c           
      C   s  t | rt |stdt| d | d |d |d }|dkr)tt|dd dS d| d  d| d  d	|d  d|d  d
tj|pDtd  
}zYt	|dd}|
dpWg }|r|d 
dpci gd }t|
dpmi 
dprd}t|
dp{i 
dpd}	||dkrtdtt|	d nd|d 
di 
ddW S W n	 ty   Y nw tt||dkrdd dS t|d dS )Nu5   도보 경로를 계산할 좌표가 부족합니다.r_   r`      r   r  duration_minutesZpolylinez<https://maps.googleapis.com/maps/api/directions/json?origin=,z&destination=z&mode=walking&key=r   r;  r<  r   Zlegsdistancer(   Zdurationr   <   Zoverview_polylinepoints)re   rS   r  r   roundr>   r@  rA  r    rL   r'   r   r  r  r   r  )
origindestinationrD  Zdirect_distancerF   rE  r   Zlegr  Z
duration_sr!   r!   r"   fetch_walking_directions  sN   "	

r  c           
      C   s  t | rt |s|dkrdS dS zNd| d  d| d  d|d  d	|d  d
tj|p,td  
}t|ddd}|dp?i dpEi gd }t|dpOi dpTd}|dkr]|W S W n	 tyg   Y nw |dkrndnd}t	| d | d |d |d }	t
dt|	|S )Nr[         4https://api.odsay.com/v1/api/searchPubTransPathT?SX=r`   &SY=r_   &EX=&EY=r  r	   r   Tr  r  r   r   info	totalTime   i&     )re   r>   r@  rA  r    rL   r'   r   r   r  r   r  )
board_pointalight_pointr}   rD  rF   rE  r   
total_timeZspeedr  r!   r!   r"   _estimate_ride_eta_minutes  s6   r  c                 C   s    t | tr| S | d u rg S | gS r   )r$   r   r   r!   r!   r"   _as_list  s
   
r  c                 C   s&   t |  }dD ]}||d}q|S )N)	r      역	   정류장u   (중)u   (지하)()r   _rW   )r&   r   r<   )r(   r   r  r!   r!   r"   r_    s   r_  c                 C   s,   t | }t |}t|o|o||v p||v S r   )r_  bool)leftrightr  br!   r!   r"   r`    s   r`  c                 C   s6   | pi  d}|dkrdS |dkrdS |dv rdS dS )	Nra   r   r  r   r  )r  r  r   gps   도보구간u   지점r   )r]   rc   r!   r!   r"   _point_kind  s   r  c                 C   s`   t | sd S t| dpi }|r|| t| d| d| d|p+| dp+d|p.d S )Nrb   r^   r_   r`   ra   r]   )re   r   r'   r   rd   )r]   rc   rb   Zmerged_metar!   r!   r"   _clone_point#  s   
r  c                 C   s|   t | rt |s
g S d| d  d| d  d|d  d|d  dtj|p%td  
}t|d	d
d}|dp8i dp=g S )Nr  r`   r  r_   r  r  r  r	   r   Tr  r  r   )re   r>   r@  rA  r    rL   r'   )r  r  rD  rF   rE  r!   r!   r"   _fetch_path_result2  s    r  c              
   C   s   |dkrdnd}g }| pi  dpi  dpg }|D ]4}| dp'| dp'd}t|| d	| d
|| dp<| d| ddd}t|rN|| q|S )Nr[   r   r   ZpassStopListrR  r   r  rW   rw  rx  r  r   r   Zodsay_pass_stop)r   station_indexrK  )r'   rd   re   r   )subpathr}   rc   r  rR  rn  r^   r]   r!   r!   r"   _extract_subpath_points?  s&   
r  c                 C   sD   t | pi | d| pi | d| pi | d|ddiS )NZNameYXrK  Zodsay_subpath_endpoint)rd   r'   )r  prefixfallback_typer!   r!   r"   _subpath_endpoint_pointU  s   r  c              	   C   s  d dd t| D }t| d}t| dd}t| dd}|r3t||d}t||tdt|d	 }nd
d t|dt|dfD }d|pNt| pIi 	ddt
|| pSi 	dt| p[i 	dp`d||rh|d n|pki 	dppd|rv|d n|pyi 	dp~ddS )Nr   c                 s   (    | ]}t |d p|dV  qdS r  r  Nr&   r'   r   r  r!   r!   r"   r   `     & z0_build_subway_subpath_segment.<locals>.<genexpr>r
   r   r   endr   r   c                 S      g | ]}|r|qS r!   r!   r   r]   r!   r!   r"   r   h  r   z1_build_subway_subpath_segment.<locals>.<listcomp>r  	   지하철sectionTimer^   rW   rg  )kindrd  r0  r  r  start_label	end_label)r   _lane_itemsr  r  _ensure_named_endpointr   r   r  r&   r'   r  r   )r  rd  r  start_point	end_pointr!   r!   r"   _build_subway_subpath_segment_  s    
r  c                 C   s   |pg D ]Q}|s	qt ||dpd}|sq| rP| d }|d|dko/|d|dk}t|d|d}|s?|rP|di t|dpLi  q| | q| S )Nra   r]   rg  r_   r`   r^   rb   )r  r'   r`  r)  r   r   r   )Ztarget_points
new_pointsr]   clonedprev
same_coord	same_namer!   r!   r"   _append_unique_pointst  s   ( r   c                    sh  d }t | ||dD ]}t|d}dd |D }|sq	d}|d }	|d }
t|	d| dr5|d	7 }t|
d
|drD|d	7 } rd}|D ]0}t|d}t fdd|D r`|d7 }t|d dsvt|d
 drz|d7 }qJ|t|dd 7 }tdd |D }|||d}|d u s|d |d ks|d |d kr|d |d k r|}q	|S )NrI  subPathc                 S   &   g | ]}t |d pddkr|qS trafficTyper   r   r   r'   r   r  r!   r!   r"   r        & z'_select_subway_path.<locals>.<listcomp>r   rg  	startNamer^   r}  endNamer
   c                 3   &    | ]}t |d  d V  qdS r^   Nr`  r'   r  	via_pointr!   r"   r        $ z&_select_subway_path.<locals>.<genexpr>r   r   rk  c                 s   s8    | ]}t |d pddv rt |dpdV  qdS )r  r   )r   r  r  Nr  r  r!   r!   r"   r     s   6 )scoresubpathsr  r  r  )r  r  r'   r`  r  anyr   sum)r  r  r  rD  r  r   r  subway_subpathsr  first_subwayZlast_subwayZvia_hitsr  pass_pointsr  r+   r!   r  r"   _select_subway_path  s@   
,8r  c           $   	   C   s  t | |||d}|s t| dt|dg}g dd |D dddS g }|dp(g D ]$}t|d	p2d}|d
krA|d|d q)|dkrM|d|d q)i }	t|D ]\}
}|d dkrft|d |	|
< qTt|	 }|r|	|d  }|	|d  }t	|dpg | d|d< t	|dpg |t
dt|dpg d
 |d< |dsg r|dp| gd dn| d|d< |dsg r|dp|gd dn|d|d< g }d}g }g }t|D ]\}
}|d dkrt|	|
pi }|sqg }d }d }|dpg D ]}t||dpd}|sq	|re|d }|d|dko6|d|dk}t|d|d}|sH|re|t| |dpVi d}|d u ra|}|}q	t||di d< || |t| |d u r|dpi d}|dpi d}q	||d< ||d< ||d< || |t|dpd7 }|dr||d qd }d }t|
d
 ddD ]}||	v r|	| } nqt|
d
 t|D ]}||	v r|	| } nq|r|sq|dr|dpg d nd } |dr |dpg d nd }!ddd d}"t| rht|!rhz	t| |!|d }"W n, tyg   t|dpKi d!pQdt|dpZi d"p`dd d}"Y nw d| pmi dpy|dpyd|!p}i dp|dpdt|"dp|dpi d"pdt|"d#p|dpi d!pdd$}#||# |t|#dpd7 }q|||d%d&d' |D dS )(Nr  rD  r   c                 S   r  r!   r!   r  r!   r!   r"   r     r   z)_build_subway_journey.<locals>.<listcomp>r   rW   )journey_segmentsr  section_time
lane_labelr  r  r   r
   )r  r  r  walkr  r  rg  r  r^   r  r  ra   r_   r`   rb   global_indexstart_index	end_indexr  rd  r  rI  r  r  r  r  
from_labelto_labelr  r  z / c                 s       | ]}|r|V  qd S r   r!   r   r^   r!   r!   r"   r     r  z(_build_subway_journey.<locals>.<genexpr>)r  r  r'   r   r   r   r  r*  rZ  r  r   r   r   r`  r)  ro  re   r  r   r   )$r  r  r  rD  
path_matchfallback_pointsZraw_segmentsr  traffic_typeZbuilt_subwayr   entryZsubway_indexesfirst_segmentZlast_segmentr  Ztotal_minuteslane_labelsZcombined_pointsrh  segment_pointsr  r  r]   r  r  r  r  Zreused_indexZprev_subwaynext_subwayZcandidate_idx
from_pointto_pointZ	walk_infoZwalk_segmentr!   r!   r"   _build_subway_journey  s   266*





$$
  **
r/  c                 C   s   t |s| S t||d}| s|gS tdt|t| d }t| | d|drb|dp7| | d| | d< |d| | d< |d| | d< | | di t	|dp]i  | S |dkrk|g|  S | |g S )Nra   r   r   r^   r_   r`   rb   )
re   r  r'   r   r   r   r`  r)  r   r   )r  Ztarget_pointZ
index_hintZtarget_cloneZcompare_indexr!   r!   r"   r    s    $

r  c                 C   s   dd t | pi dD S )Nc                 S   s   g | ]	}t |tr|qS r!   )r$   r%   r  r!   r!   r"   r   2  r   z_lane_items.<locals>.<listcomp>r  )r  r'   )r  r!   r!   r"   r  1  ru  r  c                    s  |dkrdnd}d }t  |dD ]}	t|	dD ]}
t|
dp#d|kr(qdd	d
 t|
D }dd t|
D }t|
|}d}t|
ddrS|d7 }t|
d drb|d7 }|rl||v rl|d7 }|rxt||v rx|d7 }rt	fdd
|D r|d7 }|rt	fdd
|D r|d7 }t	 fdd
|D r|d7 }|t|
dpd|
||d}|d u r|}q|d |d kr|}qqq|S )Nr[   r   r   rI  r  r  r   r   c                 s   r  r  r  r  r!   r!   r"   r   <  r  z*_select_transit_subpath.<locals>.<genexpr>c                 S   sP   h | ]$}| d s| ds| drt| d p$| dp$| dp$dqS r  r  r  rW   rT  r  r!   r!   r"   r   =  s    $z*_select_transit_subpath.<locals>.<setcomp>r  r^   rk  r	  r}  r   c                 3        | ]}t |d  V  qdS r  r  r  	via_labelr!   r"   r   L      r  c                 3   r
  r  r  r  r  r!   r"   r   O  r  c                 3   r
  r  r  r  r  r!   r"   r   Q  r  r  )r  r  r  
lane_namesr  r  )
r  r  r'   r   r   r  r  r`  rX   r  )r  r  r}   
route_nameroute_idr3  rD  target_trafficr  r   r  r7  lane_idsr  r  r+   	best_timer!   r  r  r3  r"   _select_transit_subpath5  sT   
+r>  c                    s  |dkrdnd|dkrdhnhd }t  |dD ]}fddt|d	D }	fd
d|	D }
|
s8qddd |
D }dd |
D }g }|
D ]
}|t|| qMd}t|
d ddrk|d7 }t|
d d dr||d7 }|r||v r|d7 }|rt||v r|d7 }rtfdd|D r|d7 }|rtfdd|D r|d7 }t fdd|D r|d7 }|t	dd |	D ||	||d}|d u r|}q|d |d kr|}q|d |d kr|d dkr|d pd }|d |k r|}q|S )!Nr[   r   r   r
   r  rI  c                    s&   g | ]}t |d pd v r|qS r  r   r  r  )relevant_trafficr!   r"   r   l  r  z(_select_transit_path.<locals>.<listcomp>r  c                    &   g | ]}t |d pd kr|qS r?  r  r  r:  r!   r"   r   m  r  r   c                 s   sJ    | ] }t |D ]}|d s|drt|d p|dV  qqdS r  )r  r'   r&   r   r  r  r!   r!   r"   r   p  s    z'_select_transit_path.<locals>.<genexpr>c                 S   s^   h | ]+}t |D ]$}|d s|ds|drt|d p*|dp*|dp*dqqS r0  )r  r'   rX   rC  r!   r!   r"   r   v  s    $z'_select_transit_path.<locals>.<setcomp>r   r  r^   rk  rg  r	  r}  r   c                 3   r1  r  r  r  r2  r!   r"   r     r4  r  c                 3   r
  r  r  r  r5  r!   r"   r     r  c                 3   r
  r  r  r  r6  r!   r"   r     r  c                 s   s"    | ]}t |d pdV  qdS r  r   Nr  r  r!   r!   r"   r     r   )r  r  r   r  r7  r  r  r  i?B )
r  r  r'   r   r  r  r`  rX   r  r  )r  r  r}   r8  r9  r3  rD  r  r   r  transit_subpathsr7  r;  r  r  r  r+   r<  r!   )r  r  r@  r:  r3  r"   _select_transit_pathg  sh   
 rF  c                 C   sP   | pi  dpi }t| dpd}|dkr|S tdd t| p i  dD S )Nr  r  r   c                 s   &    | ]}t |pi d pdV  qdS rD  r  r  r!   r!   r"   r     r  z#_path_total_time.<locals>.<genexpr>r  )r'   r   r  r  )r   r  r  r!   r!   r"   _path_total_time  s
    rH  c                 C   s&   dd t | D }ddd |D S )Nc                 S   8   g | ]}| d s| drt| d p| dqS r  r  r'   r&   r  r!   r!   r"   r         z'_subpath_lane_label.<locals>.<listcomp>r   c                 s   r#  r   r!   r$  r!   r!   r"   r     r  z&_subpath_lane_label.<locals>.<genexpr>r  r   )r  r*  r!   r!   r"   _subpath_lane_label  s   rN  c                 C   sD   t | D ]}t|d|d|d}|r|  S qtt| S )NZ
subwayCodeZsubwayIDr  )r  r  r'   rN  )r  r  r0  r!   r!   r"   _subpath_line_key  s   rO  c           
      C   s   t | pg }t|}t|pg D ]V\}}t||d}|sq|ra|d }|d|dko8|d|dk}t|d|d}	|sH|	ra|di |dpTi  |dkr`t|d }q|| q|||rrt|d fS d fS )	Nra   rg  r_   r`   r^   rb   r   r   )	r   r   r   r  r'   r`  r)  r   r   )
Zexisting_pointsr  r)   r  r   r]   r+   r  r  r  r!   r!   r"   !_merge_unique_points_with_indexes  s"   (rP  c                 C   s   | pi  |pd}|r/d|  krt|k r/n nt|| ||  d}|r-|r-||d< |S t| p3i  dp8ddkr>dnd}|rIt|d d |S d S )	NrW   r   ra   r^   r  r   r   r]   )r'   r   r  r   rd   )r  Zkey_namer&  Zfallback_indexr^   r]   rc   r!   r!   r"   #_subpath_endpoint_point_from_points  s    "rQ  c                    sp  d }t  |dD ]}t|d}dd |D }|sq	d}t|d p$i ddr1|d7 }t|d	 p7i d
 drD|d7 }g }	|D ]E}
t|
d}|	| t|
}|r^|d7 }tfdd|D rm|d7 }t fdd|D r||d7 }rtfdd|D r|d7 }qH|||t|d}|d u s|d |d ks|d |d kr|d |d k r|}q	|S )NrI  r  c                 S   r  r  r  r  r!   r!   r"   r     r  z/_select_subway_journey_path.<locals>.<listcomp>r   r  r^   r}  rg  r	  r
   r   c                 3   r
  r  r  r  r5  r!   r"   r     r  z._select_subway_journey_path.<locals>.<genexpr>r   c                 3   r
  r  r  r  r6  r!   r"   r     r  c                 3   r1  r  r  r  r2  r!   r"   r     r4  r  )r   r  r  r  r  r  )	r  r  r'   r`  r  r  rN  r  rH  )r  r  r3  rD  r  r   r  r  r  Z
all_pointsr  r  r  r+   r!   r=  r"   _select_subway_journey_path  sF   

 rR  c                  C   s  t | ||r|pi dnd|d}|sd S g }g }d }|dp!g }	dd t|	D }
|
s/d S |
d }|
d }t|	D ]s\}}t|d	pGd}|d
krt|d}||krX| nt|d|d}||kre|nt|d|tdt|d
 }|r{t||dn|}|rt||tdt|d
 n|}t	||\}}}t
|pd}|d|t||pi dp|dp|r|d dnd|pi dp|dp|r|d dndt|dpdt|dp|dpd|||d
 |d }q;|dkr|rd }|	|d
 d  D ]}t|p	i d	pdd
kr|} nq|sq;t|d}|dr3|dp0g d nd }t|d|d}t|dpDd}t|dpT|dpTd}|dkrt|rt|rz t|||d}t|dpx|pxd}t|dpd}W n
 ty   Y nw |dp|dpd}|d|dpd|||d q;|sd S tdd |D d }|t| |||r|pi dnddtdd |D |pi dpd|pi d pdd!S )"Nr^   rW   )r3  rD  r  c                 S   s.   g | ]\}}t |p
i d pddkr|qS r  r  )r   r   r  r!   r!   r"   r     s   . z._build_subway_journey_meta.<locals>.<listcomp>r   rg  r  r   r
   r  r	  r  r  r  ZsectionDistance)
r  rc  r0  re  rf  r  r  r  Zglobal_start_indexZglobal_end_indexr  r  rI  r  r  rf  r  r   c                 s   r   r  r
   Nr   r   rh  r!   r!   r"   r   R  r   z-_build_subway_journey_meta.<locals>.<genexpr>r2  c                 s   rG  )r  r   Nr  rT  r!   r!   r"   r   [  r  rc  r0  )r  r  r  r  primary_line_key)rR  r'   r   r   r  rQ  r   r   r  rP  rN  r   rO  re   r  r   r   _compose_segment_pointsr  ) r  r  destination_pointr  rD  selectedr  Zmerged_transit_pointsZprevious_subwayr  Zsubway_indicesZfirst_subway_indexZlast_subway_indexr   r  r'  r+  Z
start_hintZend_hintr  r  rc  r,  Znext_subpathZnext_pointsr-  r.  Zwalk_durationZwalk_distanceZwalkingr"  r  r!   r!   r"   _build_subway_journey_meta  s   
(",,
 
$ rY  c                 C   s  g }t | r|t| d g }t|pg D ]@\}}t||dp"dd|i}|s*qd}	|dkr3d}	n
|t|d kr=d	}	|rIt|d
|rId}	|	|di d< || q|| t |rh|t|d g }
|D ]T}|
r|
d }|d|dko|d|dk}t|d
|d
}|s|r|ddv r|ddvr||
d< n|di }|	|dpi  ql|
| ql|
S )Nr  ra   r]   Zsegment_indexpassr   rm  r   Zalightr^   Zviarb   roler  rg  r_   r`   )r  r  )
re   r   r  r   r'   r   r`  r)  r  r   )origin_pointtransit_pointsrW  r3  r  Znormalized_transitr   r]   r  r[  r2  r  r  r  Z	prev_metar!   r!   r"   rV  a  sD   
(
rV  c                 C   s0   dd t | D }|rd|S |dkrdS dS )Nc                 S   rI  rJ  rK  r  r!   r!   r"   r     rL  z(_subpath_route_label.<locals>.<listcomp>r   r[      버스r  rM  )r  r}   labelsr!   r!   r"   _subpath_route_label  s   
r`  c	                    sF  t ||||||r|pi dnd|d}	|	sCt| ||||||||d	}
g |
dp*g |
dp0d|
dp@|p@|d	kr?d
dS ddS |d	krIdnd |	dpQg } fdd|D }t|}d}g }g }d}|D ]}t|dpsd}|dkr|dkr|dp|r|d dn|d}|dpd}|d|||t|dpdtt|dpdd |d7 }qi| krqi|d7 }t||p|p|d	krd
nd}|dkrt|nd}t	||}|dkrt
||d}||krt
||tdt|d }g }t|D ](\}}t||d||||d}|sq || |t||d q |r3|d dn|dp=|d}|rH|d dn|dpR|d}|||||||t|dpcd|d |d7 }qi|t| d d |D ||r|pi dndd!|	dpd|	d"p|p|d	krd
dS ddS )#Nr^   rW   r8  r9  r3  rD  )r  r8  r9  rD  r  r  r   r  r[   r^  r  )sectionsr  r  r  r   r   r  c                    rA  r?  r  r  rB  r!   r"   r     r  z+_build_transit_sections.<locals>.<listcomp>r  r  r
   r  rg  rf  r	  r  r  r  )ra   section_indexr!  r"  r  r  ra   )rc  Zsection_point_indexr0  Zsection_route_label)ra   rc  rd  r0  re  rf  r  r  c                 S   r  r!   r!   r  r!   r!   r"   r     r   r2  r7  )rF  r'   _segment_pointsr   r   r   rQ   r`  r  r  r  r   r   r  rV  )r\  r  r  rW  r}   r  r8  r9  rD  r%  fallbackZrelevant_subpathsrE  Ztransit_totalZtransit_seenrb  Zall_transit_pointsrc  r  r'  r!  r"  rd  r0  r  Zannotated_pointsZpoint_indexr]   	annotatedre  rf  r!   rB  r"   _build_transit_sections  s   	
&



**
.rg  c                    s    sdS t  fdddD rdS dd l}|d }|d }|r*t|dnd}|r5t|dnd}|s;|rA|d	 | S d
 v sId v rKdS dS )N'  c                 3       | ]}| v V  qd S r   r!   )r   wordmsgr!   r"   r     r  z._bus_arrival_msg_to_seconds.<locals>.<genexpr>)u   운행종료u   운행중단u   막차u   출발대기r   u   (\d+)분u   (\d+)초r   r  u   곧u   즉시   )r  r  r  r   r  )rl  r  Zminute_matchZsecond_matchminutessecondsr!   rk  r"   _bus_arrival_msg_to_seconds  s   rp  c                 C   sN   |  dpi }t| dpd}|r#|dkr%t| dp!d| dd S d S )NZ	msgHeaderZheaderCdrW   r  Z	headerMsgu,   버스 도착정보 조회 실패 (headerCd=r  )r'   rX   rS   )rE  headerZheader_coder!   r!   r"   _raise_bus_api_error
  s
   rr  c           	      C   s   g }| D ]c}| dp| dp| dpd}| dp"| dp"d}tddd	D ]=\}}| |p3d}t|}|d
kr=q)||||||| dpO| dpOd| d| pb| dpb| dpbdd q)q|jdd d |S )NZrtNmZbusRouteAbrvr  rW   r  ZrouteId)Zarrmsg1Zarrmsg2r   r   rh  dirZ
adirectionZ	stationNmZstNmZstaNm)r8  r9  eta_secondseta_textZvehicle_order	directionr  c                 S      | d S Nrt  r!   rx  r!   r!   r"   r%  &      z._normalize_bus_arrival_items.<locals>.<lambda>r'  )r'   r   rp  r   sort)	r   tripsr$  r8  r9  Zorderr*   ru  rt  r!   r!   r"   _normalize_bus_arrival_items  s,   "&r}  c                 C      |  dpi  dp|  d}|sg S dtjj|d dd dtjjt|dd d}t|d	d
}t| t| dp=i  dpBg S )Nrb   r   zDhttp://ws.bus.go.kr/api/rest/stationinfo/getStationByUid?ServiceKey=r   rW   safez&arsId=&resultType=jsonr}  r<  msgBodyitemListr'   r>   r@  rA  rX   rL   rr  r}  )stoprD  Zars_idrF   rE  r!   r!   r"   _fetch_bus_arrivals_by_ars*     r  c                 C   r~  )Nrb   r   zChttp://ws.bus.go.kr/api/rest/arrive/getLowArrInfoByStId?ServiceKey=r   rW   r  z&stId=r  r}  r<  r  r  r  )r  rD  rX  rF   rE  r!   r!   r"   !_fetch_bus_arrivals_by_station_id8  r  r  c                 C   s   |pt }| dp
i dp| d}| dpi dp!| d}|s(|s(g S g }ttfD ])}z|| |}|r=|W   S W q. tyW } z|t| W Y d }~q.d }~ww |r`t|d g S )Nrb   r   r   r   )r    r'   r  r  r   r   rX   rS   )r  rD  Zhas_arsZhas_station_idr=   Zfetcherr|  excr!   r!   r"   fetch_bus_arrivalsF  s&   

r  c                 C   s   t | dpd}|dkr|S t| dpd}t| dpd}d|v s)|dkr+dS d	|v s3|d
kr5dS d|v r;dS d|v rAdS d|v sI|dkrKdS dS )NZbarvlDtr   arvlMsg2rW   arvlCdu   진입r  rm     도착r  -   u   전역출발Z   u   전역진입r  u   출발r     )r   r'   rX   )r$  rt  messagecoder!   r!   r"   _subway_eta_secondsY  s    r  c                 C   s$   t | }|dkr
dS |dkrdS |S )Nr  u   상행r  u   하행)r&   r  r!   r!   r"   _normalize_subway_updn_linel  s   r  c                  G   sd   | D ]-}t |}|sqt|}|r|  S |dd}tD ]}|dd|v r.|    S qqdS )Nr   rW   )r  SUBWAY_ID_TO_KEYr'   r<   SUBWAY_LINE_KEYS)r+  rK   r   Zmappedr   r*   r!   r!   r"   r  u  s   
r  c                    s(  | sg S dt j|ptd  dt j|  }t|dd}|dp$g }g }g }g }	dd ||fD }
|D ]=d	fd
ddD  t}|dkrNq6i ddpVdd|ddpadddpidddpqdddp~dp~ddtdpdddpddt	d d!t
d d"td#pd$pdd%v pd&tdpdv d'td(d)dd*t
d(d+t
d,d-t
d.d/t
d0d1t
d2t
d3t
d#t
d4d5kt
d6t
d7dpddp#ddp*ddp1dd8	}||d* |d' |d+ d9pMd9pM| |d- |d/ d|d+ d: || |
rot fd;d|
D rt|	| q6|rttjtjt| |	p|}|jd<d= d> |S )?N(http://swopenapi.seoul.go.kr/api/subway/r
   z"/json/realtimeStationArrival/0/20/r}  r<  ZrealtimeArrivalListc                 S   r  r!   r!   )r   r(   r!   r!   r"   r     r   z)fetch_subway_arrivals.<locals>.<listcomp>r   c                 3   s"    | ]}t  |pd V  qdS rW   NrX   r'   )r   r*   r#  r!   r"   r     r   z(fetch_subway_arrivals.<locals>.<genexpr>)trainLineNmbstatnNmr  arvlMsg3r   r8  r  rW   rt  ru  r  r  r  r  r  r  btrainNotrainNoZarrival_coder  received_atrecptnDt	updn_lineupdnLineupdn_line_code
is_expressZbtrainSttusdirectAt)r  7   급행r0  subwayIdsubwayNmr\  rX  statnIdrW  ZstatnFidrS  ZstatnTidZdest_station_idZbstatnIdZordkeyZlstcarAtr  Z
subwayListZ	statnList)	Zord_keyZ
train_typeZis_last_trainZsubway_listZstation_listZraw_train_line_nameZraw_arrival_messageZraw_station_messageZraw_destinationstatnNm)r\  r0  rX  r  rW  rS  r  r  c                 3   ri  r   r!   )r   keyword)haystackr!   r"   r     r  c                 S   rw  rx  r!   ry  r!   r!   r"   r%    rz  z'fetch_subway_arrivals.<locals>.<lambda>r'  )r>   r@  rA  r    rL   r'   r   r  rX   r  r&   r  r   r  r^  r   r   r   abspath__file__r{  )Zstation_nameZvia_nameZ	dest_namerD  rF   rE  r   runtime_station_rowsZ	all_tripsZfiltered_tripsfiltersrt  tripr|  r!   )r  r$  r"   fetch_subway_arrivals  s   

	
6 


r  c           
      C   sR  t | } | sg S dtj|ptd  dtj|  }t|dd}|dp(g }g }g }|D ]h}t |d|d| }t|d	}	||d
pQ|dpQd|dpWd|	|t	|dp`d|dpgdt
|dt|d|dpyd|dpdd
 |t|d||	|dpdd q/|rttjtjt| |S )Nr  r
   z/json/realtimePosition/0/60/r}  r<  ZrealtimePositionListr  r  r  r  r  rW   r  Z
trainSttusr  r  r  )
r  r  rX  r0  status_codeZstatus_textr  r  Z	direct_atr  )r\  r0  rX  r  )r  r>   r@  rA  r    rL   r'   r&   r   rX   r  r^  r   r   r   r  r  )
Z	line_namerD  rF   rE  r   	positionsr  r$  Znormalized_line_keyrX  r!   r!   r"   fetch_subway_positions  sN   
r  c                 C   s   t | trit| dpi }| drd|vr| d|d< | dr.d|vr.| d|d< | dr>d|vr>| d|d< | drNd|vrN| d|d< t| dpX| d| d| d	| d
pf||S d S )Nrb   r   r   r  lineNamer^   r  r_   r`   ra   )r$   r%   r   r'   rd   )r(   r  rb   r!   r!   r"   _point_from_config  s   
6r  c                 C   sX   | dkrt |rtd|d |d dS t |r|S t |r(td|d |d dS td)Nr  u   GPS 현재위치 사용r_   r`   u/   출발지 좌표를 확인할 수 없습니다.)re   rd   rS   )rt   Zmanual_pointcurrent_positionr!   r!   r"   _choose_origin_point  s   r  c                    s@   |s| S dd |D dd |D   fdd| D }|p| S )Nc                 S       h | ]}| d r| d qS )r  r   rU  r!   r!   r"   r     r	  z$_filter_bus_trips.<locals>.<setcomp>c                 S   r  )r  r   rU  r!   r!   r"   r     r	  c                    s,   g | ]}| d v s| d v r|qS )r8  r9  r   r   r  Z	route_idsZroute_namesr!   r"   r     s   , z%_filter_bus_trips.<locals>.<listcomp>r!   )r|  ry   filteredr!   r  r"   _filter_bus_trips  s   r  c                 C   s.   | sd S | D ]}|d |kr|  S q| d S Nrt  r   r!   )
candidatesready_secondsr  r!   r!   r"   _pick_boardable_trip  s   r  c           	      C   sz   g }d}d}t | p
g D ],\}}t|}t|dpdt|p dk}||d< ||d< || |r8|s8|}d}q||fS )Nr   Frt  Zcandidate_index
selectableT)r   r   r   r'   r   )	r  r  rf  selected_indexfoundr   r  Zannotated_tripr  r!   r!   r"   _annotate_candidate_trips#  s   
r  r}  c                 C   sj   | sg dfS t t|pdt|pdd }t| d | }|s#g dfS |t dtt|p+dt|d fS )Nr   r   )r   r   r   r   r   )r  r  minimum_sizeZ
keep_countZkeptr!   r!   r"   _retain_candidate_window3  s   $r  c                    s<  |sdS t  d}t  d} dpg }t fddt|D d}t }|dkrG||d	 d  D ]}	t |	d
}
|
rF||
 q6|rN|| d}|D ]7}t |dp^|d}||krh|d8 }||v rq|d8 }n|d7 }|r|dr|d7 }|dr|d7 }qR|tt|d dpddd 8 }|S )Nire  rf  r  c                 3   s.    | ]\}}t |d  dr|V  qdS )r^   re  Nr  )r   r   r]   rh  r!   r"   r   C     , z._subway_segment_group_score.<locals>.<genexpr>rg  r   r   r^   position_station_labelr  r  r;  rk  r  r   r   rt  i  g      ^@)r_  r'   r   r   r   r   r   r   )rh  r|  rv  preferred_expressre  rf  r  ri  Zdownstream_labelsr]   r   r  r  r  r!   r  r"   _subway_segment_group_score=  s<   



$r  c                    s  t | pg }|s
g S t|d|d|d  r( fdd|D }|r(|}|r rt| |d}t||}g }|D ]<}t| |dpL|d}	|	d u sZ|d u sZ|d u r`|| q>|d	k rm|	|krm|| |d	krz|	|krz|| q>|r|}d
t|dp|dpdv }
i }|D ]}t|dpd }||g | qt	|dkr|S d }d }|
 D ]\}}|jdd d t||||
}|d u s||kr|}|}q||p|}|jdd d |S )Nr0  rc  rd  c                    s*   g | ]}t |d |d kr|qS )r0  r8  )r  r'   r  r0  r!   r"   r   c  s   * z9_filter_subway_candidates_for_segment.<locals>.<listcomp>re  r  r  r   r  rW   r  r   c                 S      t | dpdS r  r  r#  r!   r!   r"   r%        z7_filter_subway_candidates_for_segment.<locals>.<lambda>r'  c                 S   r  r  r  r#  r!   r!   r"   r%    r  )r   r  r'   ra  rj  r   rX   rY   r)  r   r   r{  r  )r  rh  r   r|  Z	same_lineri  rq  Zdirectionalr  r  r  groupsrv  Zbest_directionZ
best_scoreZgrouped_tripsr  r  r!   r  r"   %_filter_subway_candidates_for_segment]  sV   



 r  c                 C   s   |sd S t |dpd}t|d}t |dpd}t|dp$d}t| p*g D ]\}}|rAt |dp9d|krA|  S q,t| pFg D ]5\}}|oVt|d|k}|oct |dp`d|k}	tt|dpld| dk}
|r}|	r}|
r}|  S qHd S )Nr  rW   r  r8  rt  r   r  )rX   r'   r_  r   r   abs)r  Zpreferred_tripZpreferred_trainZpreferred_stationZpreferred_routeZpreferred_etar   r  Zsame_stationZ
same_routeZ	close_etar!   r!   r"   _find_candidate_trip_index  s$   r  c           
         s  t | d| d| d}|st|pg S t|tr|ni }||vr<z
t||d||< W n ty;   g ||< Y nw ||pBg }g }t|pIg D ]<}t|dpTd t fdd|D d }	|	r|	d	pjd|d
< |	dpsd|d< |	dr|	d|d< |	| qK|S )Nr0  rc  rd  rI  r  rW   c                 3   s.    | ]} rt |d pd kr|V  qdS r  rW   Nr  rU  r  r!   r"   r     r  z4_merge_subway_position_candidates.<locals>.<genexpr>r  r  r  Zposition_status_coder  )
r  r'   r   r$   r%   r  r   rX   r   r   )
rh  r  rD  position_cacher0  cacher  r)   r  matched_positionr!   r  r"   !_merge_subway_position_candidates  s,   
r  c                 C   s   t | d}t| d| d| d}|r%|r%t|| dd}|r%|S i }t|p+g dd d	d
D ]*}t |dp>|d}|rGt||rHq2t|}	|	|vrT|||	< t|dkr\ nq2dd tt	|
 D }
|
|podd	d |
S )Nre  r0  rc  rd  rk  )rp  c                 S   r  r  r  r#  r!   r!   r"   r%    r  z4_approach_stations_from_candidates.<locals>.<lambda>T)r*   reverser  r  r  c                 S   s   g | ]}|d dqS )Frl  r!   r$  r!   r!   r"   r     r?  z6_approach_stations_from_candidates.<locals>.<listcomp>u	   탑승역rl  )r&   r'   r  rr  r*  r`  r_  r   reversedr   r+  r   )rh  r  r   re  r0  Zstatic_stationsZstations_by_keyr  r^   r*   rR  r!   r!   r"   "_approach_stations_from_candidates  s(   r  c              	   C   s~  t |rd|ini }tjtjt}g }t|pd}d}	i }
tt| p%g D ]\}}|t	|d }|
 |d< |
 |d< |ddkrkt|d	pNdd
 }|t	|| d }|
 |d< ||7 }|| q(|}zt|dpudd|dp|d|d}W n ty   g }Y nw t||dpd|dp|dp|d|d t||||
d}t|||d}t||\}}t||d< t|||d|d< |	st||}|d ur|}t||dd\}}||d< ||d< |r|| nd }|r'|t|dpd }|t	|d 
 |d< |t|d	pdd
  }|t	|d 
 |d< |}n|t|d	p0dd
 7 }d}	|| q(|S )Nsnapshot_created_atr   Fro  Zexpected_departure_timeZexpected_arrival_timer  r
   r  r  re  rW   rf  rI  r0  rc  rd  )rD  r  r   Zapproach_tripsZapproach_stationsr  )r  candidate_tripsselected_trip_indexrt  T)_plan_time_baser   r   r   r  r  r   r   r   r   rN   r'   r   r  r   r  r  r  r  r  r  r  )r  rD  r  initial_ready_secondspreferred_first_tripZ	base_timer   ZattachedZcumulative_ready_secondsZfirst_subway_seenr  r   rh  Zsegment_startZduration_secondsZsegment_endr  r|  r  r  Zforced_indexselected_tripZdepart_secondsZarrival_secondsr!   r!   r"   !_attach_subway_segment_candidates  s^   
(4
r  c                 C   s<   |  d}|rzt|W S  ty   Y t S w t S )Nr  )r'   r   fromisoformatr   rM   )plansnapshotr!   r!   r"   r    s   
r  c                 C   s   |  ddkr	| S tdd |  dpg D d }|r!| ds#g s#| S t| dp*g | d< tdtt| dp8dt| d d	 }t| d | }t| d
| d
|  dpZi  d| d|  dpgi  d}|rr||d
< || d< || d< | S )Nr}   r
   c                 s   r   rS  r   rT  r!   r!   r"   r   		  r   z2_sync_primary_subway_candidates.<locals>.<genexpr>r  r  r   r  r   r0  summarysubway_line_keyrc  rd  boardable_trip)r'   r   r   r   r   r   r   r  )r  r)  r  r  r0  r!   r!   r"   _sync_primary_subway_candidates	  s(   *r  c           
   
   C   s  t | dpg }|s| S |d u rt| dpd}tdtt|t|d }t || }t| }|tt|dp;dd }|tt| dpId| dpOd d	 }|d
pn| dp`i dpn| ddkrmdnd}d}	| ddkrt|d| dpi d|| dpi dpi d| dpi dpi d| dpi dpi d| dpi dpi d}	|	r|	|d< || d< || d< |	 | d< |	 | d< | ddkrd||dpd|dpdd| d < nd||dpd|d!pd|	d"| d < |t
| d t
| d d#| d< |	r$|	| d d< | ddkr^| d$r^t| d$p:g || d%t| d&pGdd' |d(| d$< t| } t | dp\|}| S ))Nr  r  r   r   rt  r  ride_eta_minuteswalk_after_alight_minutesrn  r8  r  rd  r}   r[   r^  r  rW   r
   r0  r  r  rb   r  r  r  r  
board_timer  ru  rv  ra   r^   ru  rv  vehicle_markerr  ra   r^   ru  r  r0  rd  board_time_hhmmarrival_time_hhmmr  r  walk_to_board_minutesr  rD  r  r  r  )r   r'   r   r   r   r   r  r   r  rN   _format_hhmmr  r  )
r  r  rD  r  r  Z	time_baser  r  rd  r  r!   r!   r"   _apply_selected_trip	  sr   *4	




r  c                 C   s0   | sdS z	t | dW S  ty   Y dS w )Nz--:--z%H:%M)r   r  r   r   )Z	iso_valuer!   r!   r"   r  ]	  s   r  c	              	   C   s   t ||||||r|pi dnd|d}	g }
d}|pd}|	rF|	dp$g }
t|
|d}
t|
|tdt|
d }
|	dp>d}|	dpE|}|
sXt||d	t||d	g}
t| d
d |
D ||rj|pfi dndd||dS )Nr^   rW   ra  r   r  r   r  r7  ra   c                 S   r  r!   r!   r  r!   r!   r"   r   |	  r   z#_segment_points.<locals>.<listcomp>r2  )r  r  r  )r>  r'   r  r   r   r  rV  )r\  r  r  rW  r}   r  r8  r9  rD  r%  r]  r  r  r!   r!   r"   rd  f	  s0   	 *rd  c              
   C   s  t | dd}t | dd}t | dd}t | dd}t|r(t|s*d S t| d||}t|r9|n|}	t|||d}
t|	r]|d	 |	d	 ksV|d
 |	d
 kr]t||	|dnddd d}tt||d| dpog }|swtdt||
d d \}}t	||\}}t
|| }t||||	d|dpd|dpd|d}|dpt||d|d}t }|tt|d d }|tt||d  d }|dp|dpd}i dddt d|d|d |d!|	d"|
d d#|
d$ d%|d&|d d'|d$ d(| d)| d*|d+|d,|d-|d.p g d||d/p*d|d0p1dd1|t| t| d2t||pGi d3pP|d4|pTi d5pZd|d4|
d |
d$ d6d7S )8Nru   r   rv   r   rw   rx   rt   rI  r_   r`   r   r  ry   u9   버스 실시간 도착정보를 찾을 수 없습니다.r  r  r[   r8  rW   r9  )r8  r9  rD  r  rt  r  r  r  r^  r}   r  r\  r  r  rW  r  walk_to_board_distance_mr  r  r  walk_after_alight_distance_mr  r  r  r  r  r+  r  ru  rv  r  r  source_labelr^   preset_labelenabledr!  Zfrom_card_labelr"  r  r  )r  r  transfer_walk)r  r'   re   r  r  r  r  rS   r  r  r   rd  r  r   rM   r   r   rO   rN   r  r  )r   r  rD  transfer_contextru   rv   rw   rx   r\  rW  walk_to_boardwalk_after_alightr  r  r  	boardablesegment_metaride_etanow_dtr  r  rd  r!   r!   r"   _build_bus_plan	  s    

	


r  c                 C   s  t | dd}t | dd}| drt | ddnd }t | dd}t | dd}t|r7t|s9d S t| d||}	t|rH|n|}
t|	||d	}t|
rl|d
 |
d
 kse|d |
d krlt||
|d	nddd d}t|d|r~|dnd|d|d	}|stdt||d d \}}t||\}}t	|| }t
|||
||d}|st|	|||
d||dpd|d}|dpt||d|d	}t }| }|tt|d d }|tt||d  d }|dp|dpd}t|d|d|d|dpi d |dpi d!|dp"i d |dp,i d!|}|r9||d< t|d"pAg |||d d |d#}i d$dd%|d&|	d'|d(|d)|
d*|d d+|d, d-|d.|d d/|d, d0| d1| d2|d3|d4|d5|d6pg |d||d7pd|d8pd|d9|t| t| |d:t||pi d;p|	d|pi d<pd|d|d |d, d=d>}t|S )?Nru   r   rz   r   r{   r|   rx   rt   rI  r_   r`   r   r  r^   rW   u<   지하철 실시간 도착정보를 찾을 수 없습니다.r  r  r  r
   r8  )r  r8  rD  r  rt  r  r  r  r  rU  r0  rb   r  r  r  r  r}   r  r\  r  r  rW  r  r  r  r  r  r  r  r  r  r  r  r+  r  ru  r  r  )rd  r  r  r  r  r   r  )r  r  r  r  )r  r'   re   r  r  r  rS   r  r  r   rY  rd  r  r   rM   rN   r   r   r  r  r  r  r  )r   r  rD  r  ru   rz   r{   r|   rx   r\  rW  r  r  r  r  r  r  r  r	  r
  r  r  r  rd  r  r  r  r!   r!   r"   _build_subway_plan	  s    
*


	


)r  c                 C   sB   |  dpg D ]}| d|kr|  S q|  dptdgd S )Nr   r   r   r   )r'   r   )r   r   r   r!   r!   r"   _get_preset7
  s
   r  c                 C   s6   t | dpg D ]\}}|d|kr|  S q	dS )Nr   r   r   )r   r'   )r   r   r   r   r!   r!   r"   _get_preset_index>
  s
   r  c                 C   s
  t | |}|dkrd S | dpg }|d t|k r ||d  nd }|s&d S |dp,i |p1i }|dp8i }|dp?i }d }	|d|d|d	|d
fD ]}
t|
r`t|
}	 nqT|	sed S |	dpqt|dd}|dt|dd| |	|dS )Nr   r   r   r   r   r   rj   rW  r  r  r^   u   이전 카드r   u   카드 )r   r   source_pointr  )r  r'   r   re   r   r&   )r   r   r   r   r   Zprev_presetZprev_bucketZ	prev_planZprev_runtimer  r+   r  r!   r!   r"   _get_previous_card_contextE
  s8   
 r  c                 C   s   t | |}|d t| S )Nr   )r  r   )r   r   r   r   r!   r!   r"   _get_mode_buckete
  s   
r  c                 C   s<   t | }t||p|d}t|p|d}||d |fS )Nr   r   r   )r   r  r'   r   )r   r   r   r   resolved_presetresolved_moder!   r!   r"   resolve_active_selectionj
  s   r  c                 C   sV   t | ||\}}}t|||}||t|dpi t|dt|dp't dS )Nr   r   r   )presetIdmoder   r   r   )r  r  r   r'   rr   )r   r   r   r   r  r  r   r!   r!   r"   get_mode_snapshotq
  s   r  c                 C   s.   t | stdt| dt| ddS )Nu1   현재 위치 좌표(lat,lng)가 필요합니다.r_   r`   )r_   r`   )re   rS   rV   r'   )r  r!   r!   r"   validate_current_position}
  s
   r  c              
   C   s  t | ||\} }}t|}t| ||}t|d }t|dd}t| |}|dkr0t| ||nd }|dkrBd|d d< d|d d< t| }	g }
g }|dkr~zt	|dpVi ||	|d}|rc|

| W nI ty} } z|
t| W Y d }~n5d }~ww zt|dpi ||	|d}|r|

| W n ty } z|
t| W Y d }~nd }~ww |
st|r|d d	|
jd
d d |
d }t }d|d< t |d< ||d< ||d< || d< || d< || fS )Nr   r}   r[   r   r  rt   r
   )rD  r  u5   출발 가능한 계획을 만들지 못했습니다.c                 S   s   |  dpdS )Nr  rW   r   r#  r!   r!   r"   r%  
  r&  zbuild_plan.<locals>.<lambda>r'  startedrg   rh   r   r   r   r   )r  r  r  r   r\   r'   r  r  r   r  r   r   rX   r  rS   r{  rr   rO   )r   r   r   r  r   r   r}   Zpreset_indexr  rD  r  r=   Zbus_planr  Zsubway_planrX  r   r!   r!   r"   
build_plan
  sX   



r  c           	      C   s   t | ||\} }}t| ||}t|d}|std|dp"g }|s)tdt|}|dk s7|t|kr;td|| }|sJ|dsJtdt||t| d	}||d< || fS )
Nr   ?   먼저 출발을 눌러 실행계획을 생성해야 합니다.r  u/   선택 가능한 차량 후보가 없습니다.r   u!   잘못된 차량 선택입니다.r  u9   현재 기준으로 탑승할 수 없는 차량입니다.rI  )	r  r  r   r'   rS   r   r   r  r   )	r   r   r   
trip_indexforce_selectr   r   r  r  r!   r!   r"   select_candidate_trip
  s"   r  c              	   C   s  d}t ddtt| d  }|d | d  | }|d | d  | }|d | d  | }|d | d  | }|| }	|| }
|	|	 |
|
  }|dkrOd S t dtd||	 ||
   | }||	|  }||
|  }|tt||d| d ||  | d ||  d	S )
Ng    @g      ?g    -@r_   r`   r           r   )ratior  r_   r`   )r   r  r  r  r   r  hypot)r  r  r  Z	lat_scaleZ	lng_scalesxsyexeyZdxZdyZdenomtZproj_xZproj_yr!   r!   r"   _project_on_segment
  s&   "r'  c                 C   s,   ddh}|  d|v r| d|v rdS dS )Nr   r   ra   u   차량구간r  r   )r  r  Ztransit_typesr!   r!   r"   _segment_kind
  s   r(  c           
      C   s  t |rt| tr| sd S g }t| D ]8\}}t |sqt|d |d |d |d }||t||dp<d|d  t|d|d |d dd qt	t
| d D ]Y}| | }| |d  }t |rht |siqTt|||}|srqT|||d d	kr}dnd
 t|||dpd d|dpd |d |d |d |dpd|dpddd	 qT|sd S dd |D }	|	rt|	dd dS t|dd dS )Nr_   r`   r^   u   지점 r   r]   r   rc   r^   r  r_   r`   rK  r   g      ?r   u   시작u    → r  r  rW   rh  )	r   rc   r^   r  r_   r`   Zsegment_start_labelZsegment_end_labelrK  c                 S   s(   g | ]}|d  dkr|d dkr|qS )rK  r]   r  x   r!   rU  r!   r!   r"   r     rV  z(_project_to_segments.<locals>.<listcomp>c                 S   rw  Nr  r!   r#  r!   r!   r"   r%    rz  z&_project_to_segments.<locals>.<lambda>r'  c                 S   rw  r+  r!   r#  r!   r!   r"   r%    rz  )re   r$   r   r   r  r   r  r'   r  ro  r   r'  r(  r   )
r+  r  r  r   r]   r  r  r  Z
projectionZpoint_candidatesr!   r!   r"   _project_to_segments
  sV    r,  c                 C   s   |  dpg }|sd S t|  dpi  d|  dpi  d|  dp$i  d}|D ]}| ddkrG|rGt| d| d	|krG|  S q+|D ]}| ddkrW|  S qJd S )
Nr  r  r0  r  r  r  r  r
   rd  )r'   r  )r   r  Zpreferred_keyrh  r!   r!   r"   _subway_board_segment  s"   ,r-  c                 C   sx   t |}|sd S | dpg }t|D ]\}}t |d|kr$|  S qt|D ]\}}t|d|r9|  S q)d S )Nr  r^   )r_  r'   r   r`  )rh  r^   r   r  r   r]   r!   r!   r"   _segment_station_index$  s   r.  c                    s  |  dpi }t| dpd  sdS t| }|sdS t|| d}t fdd|D d }|s4dS t|| d}|d u rE|d d	fS | d
pKg | }| dpTi }| dt|| dpg| dpgdd| d| ddd}	|d uo{||k}
||	|
fS )Nr  r  rW   )NNFre  c                 3   s*    | ]}t |d pd kr|V  qdS r  r  rU  Zselected_trainr!   r"   r   ;  s   ( z-_subway_train_position_ref.<locals>.<genexpr>r  Fr  rb   r  r^   r  r_   r`   Ztrain_positionr)  )r'   rX   r-  r.  r   r  )r   live_positionsr  Zboard_segmentri  r  r  r]   Z
point_metaposition_refhas_passed_boardr!   r/  r"   _subway_train_position_ref2  s4   
	
r3  c                 C   s*  t | ||\} }}t|}t| ||}|d}t| }|s"tdt|dp*t }td|d|dd|d< t	 |d	< t
|d
pGg ||d< |ddkrzt|dpZi |d}	t|	|dpfi d|dpoi ddg}	g }
nx|dpi }|dpi }t|dpdd|dp|dpi dpd|d}	t|dpi dp|dpi dp|dpi d|d}
|drt|dpg ||dt|dpdd  |dd!|d< t|}||d< |	d d" |d#< |drt|dn|	r|	d nd |d$< d |d%< |	s|dr|d|d$ p)i d&p6|di d|d$ p<i d'pBd|d$ pHi d(pNd|d$ pTi dpZdt|d$ pai d|dpki d|d$ pti d&|dp~i dd)nd |d*< |d |d+< |rd,|d-< t	 |d.< nq|dd/krt||
\}}}|r ||d%< |d*d u rd0d/i|d*< |d1pd|d* d1< |d2pd|d* d2< |d3pd|d* d3< |r||d+< |d-d4kr |r d,|d-< t	 |d.< n|d-d5krd4|d-< ||d< || fS )6Nr   r  r   u   현재 위치r_   r`   r  rj   rk   r+  rl   r}   r[   r  rI  r  rd  r  r9  )r  r  r  r^   rW   r  r  r  r0  r  r  r  r   r  r  r}  rm   rn   rq   r8  ru  rv  )ra   r^   ru  rv  r  r0  ro   rp   Zboardedrg   ri   r
   ra   r  r  r  r  rf   )r  r  r  r'   r   rS   r   rr   rd   rO   r,  r  r  r  r  r  r   r  r  r3  )r   r   r   r  confirm_boardingr   r   rD  r   Zlive_candidatesr0  r  r  Zmatched_trainr1  r2  r!   r!   r"   refresh_liveP  s   

2 

0&
r5  c                 C   sb   t | ||\} }}t| ||}t }|drdnd|d< |dp#i d|d< ||d< || fS )Nr   r  rf   rg   r   rh   )r  r  rr   r'   )r   r   r   r   r   r!   r!   r"   reset_journey_state  s   r6  )r   NFr   )rW   )r[   )rW   NNr]   N)r   N)Fr-   )rk  )r  )NN)rW   rW   rW   Nr  )NrW   rW   N)rW   rW   N)r}  )NNr   N)rD   r  r   r.   r(  r  urllib.parser>   urllib.requestZxml.etree.ElementTreeZetreeZElementTreerB  copyr   r   r   r   r   r   r  r    r  r  r#   r,   r4   rL   rO   rV   r&   r\   rd   re   rr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r3  r4  r9  rG  rN  rQ  rO  r^  ra  rb  rj  rr  rt  rv  rz  r{  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r_  r`  r  r  r  r  r  r  r   r  r/  r  r  r>  rF  rH  rN  rO  rP  rQ  rR  rY  rV  r`  rg  rp  rr  r}  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  rd  r  r  r  r  r  r  r  r  r  r  r  r'  r(  r,  r-  r.  r3  r5  r6  r!   r!   r!   r"   <module>   sz   		


=?	$	"&"	 	,
"
"w2=	&[&f	I+
	
	
 ,2
@	Jk 	*0Q