o
    &_h                     @   s  d Z ddlZddlZddlmZ ddlmZmZ ddlm	Z	m
Z
mZ ddlmZ ddlZddlmZmZ ddlZddlZddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddl m!Z!m"Z"m#Z# ddl$m%Z% ddl&Z'eG dd dZ(eG dd dZ)eG dd dZ*eG dd dZ+eG dd dZ+G dd dZ,G dd dZ-G dd dZ.G dd  d Z/G d!d" d"Z0G d#d$ d$Z1d%d& Z2d'd( Z3e4d)kre3  dS dS )*zv
VIC License Checker
================================================================================================
    N)Path)	dataclassasdict)ListDictOptional)datetime)ThreadPoolExecutoras_completed	webdriverOptionsByKeysWebDriverWaitexpected_conditions)TimeoutExceptionWebDriverExceptionNoSuchElementException)fuzzc                   @   sr   e Zd ZU dZdZeed< dZeed< dZ	eed< dZ
eed	< d
Zeed< dZeed< dZeed< dZeed< dS )SimpleConfigzSimple configuration_https://www.lars.police.vic.gov.au/LARS/LARS.asp?File=/components/screens/psinfp03/psinfp03.aspwebsite_urlU   name_similarity_required   max_retry_attempts   request_timeout_secondsg333333?delay_between_requests   parallel_browsersF	test_modetest_record_limitN)__name__
__module____qualname____doc__r   str__annotations__r   intr!   r#   r$   floatr&   r'   boolr(    r2   r2   /var/www/html/scrapers/vic.pyr   #   s   
 r   c                   @   sT   e Zd ZU dZeed< eed< eed< eed< dZeed< dd	 Zd
e	fddZ
dS )EmployeeRecordz)Holds one employee's information from CSVpayroll_numberemployee_namelicense_number
csv_expiryr   csv_row_numberc                 C   sD   t | j | _t | j | _t | j | _t | j | _dS )z)Remove extra spaces and clean up the dataN)r-   r5   stripr6   r7   r8   selfr2   r2   r3   
clean_dataL   s   zEmployeeRecord.clean_datareturnc                 C   s   t | jo| jS )z9Check if this record has the minimum required information)r1   r7   r6   r;   r2   r2   r3   has_required_dataS      z EmployeeRecord.has_required_dataN)r)   r*   r+   r,   r-   r.   r9   r/   r=   r1   r?   r2   r2   r2   r3   r4   C   s   
 r4   c                   @   s   e Zd ZU dZdZeed< dZeed< dZeed< dZ	eed< dZ
eed< dZeed	< d
Zeed< dZeed< dZeed< dZeed< defddZdS )SearchResultz.Holds the result of searching VIC LARS website	Not Found
found_namelicense_typelicense_expirylicense_activities
No Licensename_matchesexpiry_status error_messager   how_many_retriesg        search_time_secondsF
was_cachedr>   c                 C   s   | j dko| j S )z-Did we successfully find license information?rB   )rC   rK   r;   r2   r2   r3   is_successfulf   s   zSearchResult.is_successfulN)r)   r*   r+   r,   rC   r-   r.   rD   rE   rF   rH   rI   rK   rL   r/   rM   r0   rN   r1   rO   r2   r2   r2   r3   rA   X   s   
 rA   c                   @   b   e Zd ZU dZeed< eed< eed< eed< eed< eed< eed< eed	< eed
< eed< dS VICVerificationResultz'Data class for VIC verification resultsr5   r7   rolecall_name	lars_name
name_matchrolecall_expirylars_expiryrI   type
activitiesNr)   r*   r+   r,   r-   r.   r2   r2   r2   r3   rR   k      
 rR   c                   @   rP   rQ   rZ   r2   r2   r2   r3   rR   z   r[   c                   @   sN   e Zd ZdZdefddZdd Zdejfdd	Z	d
d Z
dd Zdd ZdS )OptimizedBrowserManagerz6Manages multiple Chrome browsers for reliable scrapingconfigc                 C   s*   || _ t | _g | _d| _t | _d S )NF)	r]   queueQueuebrowser_poolall_browserssetup_complete	threadingLocklock)r<   r]   r2   r2   r3   __init__   s
   
z OptimizedBrowserManager.__init__c                 C   s   | j rdS | jI | j r	 W d   dS td| jj d t| jjD ]}|  }| j| | j	
| td|d  d q%d| _ td W d   dS 1 sTw   Y  dS )	z.Create Chrome browsers for parallel processingNzSetting up z Chrome browsers...z   Browser r%   z readyTz+All browsers ready for parallel processing!)rb   re   printr]   r&   range_create_chrome_browserra   appendr`   put)r<   ibrowserr2   r2   r3   setup_browsers   s   
"z&OptimizedBrowserManager.setup_browsersr>   c                 C   s   t  }|d |d |d |d |d |d |d |d |d	 |d
 |d |d |d |d |d |d tj|dS )z/Create one Chrome browser with optimal settings
--headless--no-sandbox--disable-dev-shm-usagez--disable-gpuz--disable-extensionsz--disable-loggingz--disable-web-securityz--window-size=1280,720z%--disable-background-timer-throttlingz --disable-renderer-backgroundingz(--disable-backgrounding-occluded-windowsz!--disable-ipc-flooding-protectionz--disable-features=TranslateUIz--disable-default-appsz--no-first-runz--memory-pressure-offoptions)r   add_argumentr   Chrome)r<   chrome_optionsr2   r2   r3   ri      s$   















z.OptimizedBrowserManager._create_chrome_browserc                 C   s.   | j s|   | j }t|| jj}||fS )z)Get a browser from the pool (thread-safe))rb   rn   r`   getr   r]   r#   )r<   rm   wait_helperr2   r2   r3   get_browser   s
   
z#OptimizedBrowserManager.get_browserc                 C   s   | j | dS )z Return browser to pool when doneN)r`   rk   )r<   rm   r2   r2   r3   return_browser   r@   z&OptimizedBrowserManager.return_browserc                 C   sN   d}| j D ]}z|  W q   |d7 }Y q|dkr%td| d dS dS )z$Close all browsers when program endsr   r%   z	WARNING: z" browsers failed to close properlyN)ra   quitrg   )r<   failed_cleanupsrm   r2   r2   r3   cleanup_all_browsers   s   
z,OptimizedBrowserManager.cleanup_all_browsersN)r)   r*   r+   r,   r   rf   rn   r   ru   ri   ry   rz   r}   r2   r2   r2   r3   r\      s    
r\   c                   @   s   e Zd ZdZdedefddZdedefdd	Zdedefd
dZ	dededefddZ
dededefddZdedefddZdedefddZdejdededefddZdS )SeleniumLicenseSearcherz(Searches VIC LARS website using Seleniumr]   browser_managerc                 C   s&   || _ || _i | _t | _i | _d S N)r]   r   search_cacherc   rd   
cache_lock
name_cache)r<   r]   r   r2   r2   r3   rf      s
   

z SeleniumLicenseSearcher.__init__namer>   c                 C   s~   |sdS || j v r| j | S | |}|   }t|dkr2|d  dd|dd  }n|  }|| j |< |S )zEConvert name to standard format for comparison with enhanced cleaningrJ   r    ,  N)r   _clean_name_for_matchingr:   uppersplitlenjoin)r<   r   cleaned_nameparts
normalizedr2   r2   r3   normalize_employee_name   s   


"
z/SeleniumLicenseSearcher.normalize_employee_namec                 C   s   |sdS t | }d| }|  }g }|D ] }t|dkr*t|dkr*q|dr6t|dkr6q|| qg }|D ]}d|v rQ|d}|| q@|| q@dd |D }|red|S |S )	z>Clean name by removing common variations and formatting issuesrJ   r   r%   .   -c                 S   s   g | ]}|  r|qS r2   )r:   ).0wordr2   r2   r3   
<listcomp>*  s    zDSeleniumLicenseSearcher._clean_name_for_matching.<locals>.<listcomp>)	r-   r:   r   r   r   r   endswithrj   extend)r<   r   cleanedwordsfiltered_wordsr   processed_wordshyphen_partsr2   r2   r3   r     s(   
z0SeleniumLicenseSearcher._clean_name_for_matchingcsv_namewebsite_namec           	      C   s   |dkrdS |r
|sdS |  |}|  |}| |}| |}||kr&dS | | kr0dS t||t| | t| | t| | g}t|}|| j	j
kr^dS d|ddS )z<Compare names with enhanced cleaning and return match statusrB   zNo MatchYesNo (.1fz%))r   r   r   r   token_set_ratiotoken_sort_ratiopartial_ratioratiomaxr]   r   )	r<   r   r   cleaned_csvcleaned_websitenorm_csvnorm_websitesimilarity_methods
similarityr2   r2   r3   check_name_similarity/  s*   




z-SeleniumLicenseSearcher.check_name_similarityr8   
web_expiryc              
   C   s   |r|r|dkr
dS z9t |d}t |d}|t  k }| | k}|r,|s,W dS |r3|r3W dS |s:|s:W dS |sA|rAW dS W dS  ty` } zd	t|d
d  W  Y d
}~S d
}~ww )z<Calculate expiry status comparison between CSV and web datesrB   rG   z%d/%m/%YActiveExpiredzActive - Date WrongzExpired - Date WrongUnknownError: Nr"   )r   strptimetodaydate	Exceptionr-   )r<   r8   r   csv_dateweb_date
is_expireddates_matcher2   r2   r3   calculate_expiry_statusW  s(   "z/SeleniumLicenseSearcher.calculate_expiry_statusemployeec                 C   s   |j | jv r#| j|j  }| |j|j|_| |j|j|_	d|_
|S | |}| rF| j || j|j < W d   |S 1 sAw   Y  |S )z0Search for one employee's license using SeleniumTN)r7   r   r   r6   rC   rH   r   r8   rE   rI   rN   _search_with_retriesrO   r   )r<   r   cached_resultresultr2   r2   r3   search_single_licenser  s$   

z-SeleniumLicenseSearcher.search_single_licensec           
      C   s8  |j  st S d}t| jjD ]{}zR| j \}}zAt }| 	|||}t | }|
 rT| |j|j|_| |j|j|_||_||_|W | j| W   S W | j| n| j| w W q ty }	 zt|	}|| jjd k rtd|d   W Y d}	~	qd}	~	ww td| jj d| | jjdS )z(Try searching multiple times if it failsrJ   r%         ?NzFailed after z attempts: )rK   rL   )r7   r:   rA   rh   r]   r!   r   ry   time_do_selenium_searchrO   r   r6   rC   rH   r   r8   rE   rI   rL   rM   rz   r   r-   sleep)
r<   r   
last_errorattemptrm   rx   
start_timer   search_timer   r2   r2   r3   r     sB   
 z,SeleniumLicenseSearcher._search_with_retriesrm   rx   c              
   C   s  z~| | jj |ttjdf}|  |	|j
  |	tj |ttjdf td |tjdtjd}t|dkr{|d tjd}t|dkr{t|d j p_d	|d j pgd	|d
 j pod	|d j pwd	dW S t W S  ty   td|j
  ty } z	tdt| d}~w ty } z	tdt| d}~w ty } z	tdt| d}~ww )z3Actually search the VIC LARS website using SeleniumSearchAuthNbidResultsTabler%   trr    td   r   rB   r      )rC   rD   rE   rF   zWebsite timeout for license: zPage element not found: NzWebDriver error: zSelenium search error: )rw   r]   r   untilECpresence_of_element_locatedr   IDclear	send_keysr7   r:   r   RETURNr   r   find_elementfind_elementsTAG_NAMEr   rA   textr   r   r   r-   r   )r<   rm   rx   r   search_input	rows_htmlcellsr   r2   r2   r3   r     sB   
z+SeleniumLicenseSearcher._do_selenium_searchN)r)   r*   r+   r,   r   r\   rf   r-   r   r   r   r   r4   rA   r   r   r   ru   r   r   r2   r2   r2   r3   r~      s    )()r~   c                   @   s.   e Zd ZdZedededee fddZ	dS )SimpleCSVHandlerz"Reads employee data from CSV files	file_pathr]   r>   c              
      s  zt j| tdd  jj jdd _g d} fdd|D }|r5tdd	| d
t j dg } 	 D ]9\}}t
|d |d |d |d |d d}|  | rt|| |jrtt||jkrttd|j d  nq;|s{tdg }t }	d}
|D ]}|j|	vr|	|j || q|
d7 }
q|
dkrtd|
 d |W S  ty } z
tdt|   d}~ww )z Load employee data from CSV fileF)dtype	na_filteru   ﻿rJ   )Payroll NumberEmployee NameLicense NumberExpiry/Update  Datec                    s   g | ]	}| j vr|qS r2   )columns)r   coldfr2   r3   r     s    z7SimpleCSVHandler.load_employee_data.<locals>.<listcomp>z"
ERROR: Missing required columns: r   z

Your CSV file MUST have these exact column names:
- Payroll Number
- Employee Name
- License Number
- Expiry/Update  Date

Current columns in your file: z
                r   r   r   r   r    r5   r6   r7   r8   r9   z!TEST MODE: Processing only first  recordsz2ERROR: No valid employee records found in CSV filer   r%   zNOTE: Removed z duplicate license numberszERROR reading CSV file: N)pdread_csvr-   r   r:   replace
ValueErrorr   listiterrowsr4   r=   r?   rj   r'   r   r(   rg   setr7   addr   )r   r]   required_columnsmissing_columns	employeesindexrowr   unique_employeesseen_licensesduplicates_removedr   r2   r   r3   load_employee_data  sZ   	



z#SimpleCSVHandler.load_employee_dataN)
r)   r*   r+   r,   staticmethodr-   r   r   r4   r   r2   r2   r2   r3   r          r   c                   @   st   e Zd ZdZdefddZdd Zdedefd	d
Z	dde
dedefddZde
defddZde
defddZdS )SimpleProgressTrackerz1Shows nice progress bar and processing statisticstotal_employeesc                 C   s<   || _ d| _d| _d| _d| _t | _d| _t	 | _
d S )Nr   )r  	completed
successfulfailedcachedr   r   last_updaterc   rd   re   )r<   r  r2   r2   r3   rf   8  s   
zSimpleProgressTracker.__init__c              
   C   sd   t dd  t d| j d t d  t ddddd	dd
dddddd 	 t d  dS )zShow the processing header
U=====================================================================================z!VIC LICENSE CHECKER - PROCESSING z
 EMPLOYEESProgress<15r   Employee<25LicenseStatus<12SpeedzU-------------------------------------------------------------------------------------N)rg   r  r;   r2   r2   r3   show_headerB  s
   
,z!SimpleProgressTracker.show_headerr   r   c                 C   sl  | j - |  jd7  _|jr|  jd7  _n| r"|  jd7  _n|  jd7  _W d   n1 s3w   Y  t }|| j dk rEdS || _| j| j	 d }| 
|}t|| j d}| j| d }t|jdkrt|jdd d	 n|j}t|jd
kr|jdd d	 n|j}	|jrd}
n	| rd}
nd}
td| d|dd|	dd|
dd|ddddd dS )zUpdate progress displayr%   Nr   d   g{Gz?<         z..      CachedSuccessFailedr   r  r
  r  .0fz/minrJ   T)endflush)re   r  rN   r  rO   r  r  r   r  r  _make_progress_barr   r   r   r6   r7   rg   )r<   r   r   current_timepercentprogress_barelapsedspeeddisplay_namedisplay_licensestatusr2   r2   r3   update_progressJ  sN   
.
z%SimpleProgressTracker.update_progressr"   r!  widthr>   c                 C   s8   t || d }d| d||   }d| d|ddS )zCreate ASCII progress barr  Xr   [z] z5.1f%r/   )r<   r!  r)  filledbarr2   r2   r3   r  v  s   z(SimpleProgressTracker._make_progress_barelapsed_timeexcel_file_pathc                 C   s   t dd  t d t d  t d| j  t d| j  t d| j  t d| j  t d| jt| jd	 d
 dd t d| |  t d| j| d dd t d|  t d  dS )zShow final processing summaryz

r  zPROCESSING COMPLETED!zTotal employees processed: zSuccessful searches: zFailed searches: zCached results: zSuccess rate: r%   r  r   r,  zTotal time: zProcessing speed: r  z employees/minutezExcel report saved: N)rg   r  r  r  r  r   _format_time)r<   r0  r1  r2   r2   r3   show_final_summary|  s   
$z(SimpleProgressTracker.show_final_summarysecondsc                 C   sp   |dk r
|ddS |dk r"t |d }t |d }| d| dS t |d }t |d d }| d| dS )	z"Convert seconds to readable formatr  r  z secondsi  zm szh mr-  )r<   r4  minutessecshoursr2   r2   r3   r2    s   z"SimpleProgressTracker._format_timeN)r"   )r)   r*   r+   r,   r/   rf   r  r4   rA   r(  r0   r-   r  r3  r2  r2   r2   r2   r3   r   5  s    
,r   c                   @   s.   e Zd ZdZedee dedefddZdS )SimpleExcelGeneratorz'Creates Excel reports with color codingresultsoriginal_file_pathr>   c                 C   s  zAt |}t d}|j|j d| d }g }| D ]W}|dd}|dd}|dd}	|dd}
|d	kpl|d
kpl|dkpl|dpl|d	kpl|dkpl|	d	kpl|	dkpl|
d
kpl|
dkpl|
dpld|
v pld|
v }|rt|| q|sdddt	|  dddddddd
}|g}|j|j d| d }t
|}t
j|dd}t	|dksdt|d d dvrd!nd"}|j|d#|d$ |j}|j| }|d%d&d'dd(d)d%d*}t|jD ]5\}}|d||| tt	t||js|| tj	  nd}tt|d+ d,d-}|||| q|dd. |ddt	|t	|jd  |dd W d/   n	1 s9w   Y  t|W S  tyY } z
td0t|   d/}~ww )1zDCreate Excel report - EXCEPTIONS ONLY (problems that need attention)z%Y%m%d_%H%M%S_Exceptions_z.xlsx
Name MatchrJ   	LARS NameTypeExpiry StatusrB   rG   Errorr   r   zError:z
Date Wrongr   zN/Az"ALL RECORDS PROCESSED SUCCESSFULLYr   zNo exceptionsz	All foundzAll dates matchz	All validz
All active)
r   r   Rolecall Namer?  r>  r@  Rolecall ExpiryLARS ExpiryrA  
Activities_VIC_ALL_SUCCESS_
xlsxwriter)enginer%   zALL RECORDSr   rC  
ExceptionszProcessing SummaryF)r   
sheet_nameTz#8C1E31whitecentervcenter)boldbg_color
font_colorborderalignvalign	text_wrapr      2   r"   NzERROR creating Excel report: )r   r   nowstrftimeparentstemrw   
startswithrj   r   r   	DataFrameExcelWriterr-   to_excelbooksheets
add_format	enumerater   writer   emptyastypemin
set_columnset_row
autofilterfreeze_panesr   rg   )r;  r<  original_path	timestamp
excel_pathexception_resultsr   rU   rT   rD   rI   is_exceptionsummary_resultr   writerrK  workbook	worksheetheader_colorcol_numheader
max_length	col_widthr   r2   r2   r3   create_excel_report  s   	





 
)z(SimpleExcelGenerator.create_excel_reportN)	r)   r*   r+   r,   r   r   r   r-   rz  r2   r2   r2   r3   r:    r   r:  c                   @   s   e Zd ZdZdd Zdd Zdd Zdefd	d
Zde	de
fddZdee dee fddZdedefddZdee dee fddZdee dee fddZdS )SeleniumVICLicenseCheckerz0Main application class - using reliable Seleniumc                 C   s   t  | _t| j| _d | _d S r   )r   r]   r\   r   progress_trackerr;   r2   r2   r3   rf     s   
z"SeleniumVICLicenseChecker.__init__c              
   C   s4  zz?|    |  }t|| j}| t|s%td W W | j	  dS | 
|}t||}t | jj }| j|| W n; tyM   td Y n7 ty{ } z#tdt|  td td td td td	 W Y d}~nd}~ww W | j	  dS W | j	  dS W | j	  dS | j	  w )
z0Main function - this is where everything happenszProcess cancelled by userNz*

Process stopped by user (Ctrl+C pressed)z
ERROR: z
TROUBLESHOOTING TIPS:z1. Make sure your CSV file has the exact column names: 'Payroll Number', 'Employee Name', 'License Number', 'Expiry/Update  Date'z)2. Check that Chrome browser is installedz)3. Make sure you have internet connectionz<4. Try running as administrator if you get permission errors)_show_welcome_get_csv_file_from_userr   r   r]   _ask_user_to_continuer   rg   r   r}   _process_all_employeesr:  rz  r   r|  r   r3  KeyboardInterruptr   r-   )r<   csv_file_pathr   r;  rn  r0  r   r2   r2   r3   run  s>   

zSeleniumVICLicenseChecker.runc                 C   s   t d dS )zShow welcome messagez!VIC License Checker - Starting...N)rg   r;   r2   r2   r3   r}  =  s   z'SeleniumVICLicenseChecker._show_welcomer>   c                 C   s   t tjdkrtjd  d}td|  ntd td td td td td	 d}|s<td
t| sItd| tdt|j	  |S )zGet CSV file path from userr%   z"'zUsing file from command line: z
Please provide your CSV file:z   You can either:z   1. Type the full file pathz-   2. Drag and drop the file into this windowz"   3. Copy and paste the file pathz
Enter CSV file path: zNo file path providedzFile not found: zFile found: )
r   sysargvr:   rg   inputr   r   existsr   )r<   r   r2   r2   r3   r~  A  s   z1SeleniumVICLicenseChecker._get_csv_file_from_useremployee_countc                 C   s~   | j jrtdt|| j j d dS td| d td| j j d 	 td  }|dv r4dS |d	v r:d
S td q&)z.Ask user if they want to process the employeesz
TEST MODE: Will process z
 employeesTz
Ready to process z	Will use z parallel Chrome browsersz"
Continue with processing? (Y/N): )yyes)nnoFz&Please enter 'y' for yes or 'n' for no)	r]   r'   rg   rg  r(   r&   r  r:   lower)r<   r  responser2   r2   r3   r  \  s   z/SeleniumVICLicenseChecker._ask_user_to_continuer   c                    sd  t t|| _t| j| jg }t| jjd  fdd|D }t|D ]y}|| }z0|	 }|j
|j|j|j|j|j|j|j|j|jd
}|| | j|| t| jj W q& ty } z7td|j dt|  |j
|j|jdd|jddddd
}	||	 tt|d}
| j||
 W Y d	}~q&d	}~ww W d	   |S 1 sw   Y  |S )
zAProcess all employees with minimal output unless there are issuesmax_workersc                       i | ]
}  j||qS r2   submitr   r   r   executorsearcherr2   r3   
<dictcomp>}      zDSeleniumVICLicenseChecker._process_all_employees.<locals>.<dictcomp>
r   r   rC  r?  r>  rD  rE  rA  r@  rF  zERROR processing z: rB  )rK   N)r   r   r|  r~   r]   r   r	   r&   r
   r   r5   r7   r6   rC   rH   r8   rE   rI   rD   rF   rj   r(  r   r   r$   r   rg   r-   rA   )r<   r   all_resultsfuture_to_employeefuturer   search_resultresult_dictr   error_resulterror_search_resultr2   r  r3   r  o  s`   


>>z0SeleniumVICLicenseChecker._process_all_employeesr   c                 C   s   g }|j r
|d |jdkr|d|jdd |jdkr(|d|j  |jr5|d|j  n|d |rAd	|S d
S )z-Create informative notes for the Excel reportz!Cached result (duplicate license)r   zSearch time: z.2fr5  z	Retries: r   zSelenium scrapingz | zProcessed successfully)rN   rj   rM   rL   rK   r   )r<   r   notesr2   r2   r3   _create_notes_for_result  s   



z2SeleniumVICLicenseChecker._create_notes_for_resultrecords_datac                      zg }|D ],}t |dd |dd |dd |dd dd}|  || q|s7g W S g }t }t| j| jt	| jj
dn  fd	d
|D }t|D ]W}|| }z)| }	|j|j|j|	j|	j|j|	j|	j|	j|	jd
}
||
 t| jj W qZ ty } z|j|j|jdd|jddddd
}|| W Y d}~qZd}~ww W d   n1 sw   Y  | j  t | }tdt| d|dd |W S  ty } ztd|  | j   d}~ww )BProcess list of records and return results as list of dictionariesr   rJ   r   r   r   r   r   r  c                    r  r2   r  r  r  r2   r3   r    r  =SeleniumVICLicenseChecker.process_records.<locals>.<dictcomp>r  rB  NCompleted processing  records in r   r5  Error processing records: r4   rw   r:   r=   rj   r   r~   r]   r   r	   r&   r
   r   r5   r7   r6   rC   rH   r8   rE   rI   rD   rF   r   r$   r   r}   rg   r   r<   r  recordsrecord_datar   output_rowsr   r  r  r  r  r   r  
total_timer2   r  r3   process_records     

4
z)SeleniumVICLicenseChecker.process_recordsc                    r  )r  r   rJ   r   r   r   r   r   r  c                    r  r2   r  r  r  r2   r3   r  E  r  r  r  rB  Nr  r  r   r5  r  r  r  r2   r  r3   r  )  r  N)r)   r*   r+   r,   rf   r  r}  r-   r~  r/   r1   r  r   r4   r   r  rA   r  r  r2   r2   r2   r3   r{    s    (K[r{  c               
   C   sD  zqddl m}  ddlm} ddlm} ddlm} ddlm	} ddl
m} | }|d |d	 |d
 | j|d}||d}z*|d |||jdf}	|	ratd W |  W dS td W |  W dS |  w  ty }
 z$tdt|
  td td td td td W Y d }
~
dS d }
~
ww )Nr   r   r   r   r   r   r   ro   rp   rq   rr   r  r   r   z Selenium connection test PASSED!Tz7Search input field not found - website may have changedFz!Selenium connection test failed: zCommon fixes:z 1. Install Google Chrome browserz"2. Update Chrome to latest version3. Run as administratorz4. Check internet connection)seleniumr   !selenium.webdriver.chrome.optionsr   selenium.webdriver.common.byr   selenium.webdriver.common.keysr   selenium.webdriver.support.uir   selenium.webdriver.supportr   rt   ru   rw   r   r   r   rg   r{   r   r-   )r   r   r   r   r   r   rv   driverwaitr   r   r2   r2   r3   test_selenium_connection  sJ   



r  c               
   C   s   t tjdkrtjd  } | dv rt  dS ztd td t s+td td t }|  W dS  tyB   td Y dS  t	yy } z,td	t
|  td
 td td td td td td W Y d}~dS d}~ww )zMain entry pointr%   )z--testz-ttestNzStarting VIC License Checker...z3
Testing Selenium connection to VIC LARS website...z4Connection issues detected, but continuing anyway...zKIf all searches fail, the website may have changed or Chrome needs updatingz%
Selenium application stopped by userz
FATAL ERROR: z
SELENIUM TROUBLESHOOTING:z,1. Check your CSV file has the right columnsz'2. Install/update Google Chrome browserr  z!4. Check your internet connectionz85. Try reducing parallel_browsers to 1 if getting errorsz16. Run with --test to check Selenium connectivity)r   r  r  r  r  rg   r{  r  r  r   r-   )argappr   r2   r2   r3   main  s4   r  __main__)5r,   jsonr   pathlibr   dataclassesr   r   typingr   r   r   r   r  concurrent.futuresr	   r
   rc   r^   r  r   r  r   r  r   r  r   r  r   r  r   r   selenium.common.exceptionsr   r   r   	rapidfuzzr   pandasr   r   r4   rA   rR   r\   r~   r   r   r:  r{  r  r  r)   r2   r2   r2   r3   <module>   sZ    X  Ohp  ~4*
