
    iA                     .   d Z ddlmZ ddlmZmZ ddlmZmZ ddl	m
Z
 ddlmZ ddlmZmZ ddlmZ erdd	lmZ dd
lmZ ddlmZ d+dededefdZe G d d                      Zdddddedz  dedz  dedz  deedz  edz  f         fdZdddddedz  defdZdddddedz  dee         fdZ dddddefdZ!dddddefd Z"	 	 	 d,d"ed#         dddedz  d$ed%eded#         fd&Z#	 	 	 	 d-ddd%ed'ee         dz  d(ed)edz  deee$dz  f         fd*Z%dS ).a(  
Search operations - Sans-I/O business logic for calendar search.

This module contains pure functions that implement search logic
without performing any network I/O. Both sync (CalDAVSearcher.search)
and async (CalDAVSearcher.async_search) use these same functions.

Key functions:
- build_search_xml_query(): Build CalDAV REPORT XML query
- filter_search_results(): Client-side filtering of search results
- determine_search_strategy(): Analyze server features and return search plan
- _collation_to_caldav(): Map collation enum to CalDAV identifier
    )deepcopy)	dataclassfield)TYPE_CHECKINGAny)Timezone)	Collation)cdavdav)error)Searcher)CalendarObjectResource)
FeatureSetT	collationcase_sensitivereturnc                     | t           j        k    r|rdS dS | t           j        k    r|rdS dS | t           j        k    rdS dS )a  Map icalendar-searcher Collation enum to CalDAV collation identifier.

    CalDAV supports collation identifiers from RFC 4790. The default is "i;ascii-casemap"
    and servers must support at least "i;ascii-casemap" and "i;octet".

    :param collation: icalendar-searcher Collation enum value
    :param case_sensitive: Whether the collation should be case-sensitive
    :return: CalDAV collation identifier string
    i;octetzi;ascii-casemapzi;unicode-casemap)r	   SIMPLEUNICODELOCALE)r   r   s     W/root/projects/butler/venv/lib/python3.11/site-packages/caldav/operations/search_ops.py_collation_to_caldavr       se     I$$$ 	%9$$	i'	'	'  	'9&&	i&	&	& !  y    c                       e Zd ZU dZdZedz  ed<   dZedz  ed<   dZ	eed<    e
e          Zee         ed<   d	Zeed
<   d	Zeed<   d	Zeed<   dS )SearchStrategyzEncapsulates the search strategy decisions based on server capabilities.

    This dataclass holds all the decisions about how to execute a search,
    allowing the same logic to be shared between sync and async implementations.
    Npost_filterhacksTsplit_expanded)default_factoryremove_propertiesFremove_category_filterpending_todo_multi_searchretry_with_comptypes)__name__
__module____qualname____doc__r   bool__annotations__r   strr   r   setr!   r"   r#   r$    r   r   r   r   A   s            $K### E3:  ND #(%"<"<"<s3x<<< $)D((( ',t+++ "'$&&&&&r   r   searcherr   featuresr   comp_type_supportNcurrent_hackscurrent_post_filterc                 d   |}|}| j         s3t          | dd          s"t          | dd          st          | dd          r|dk    r
|s|durd}d}|]t          | dd          r| j        rC| j        s<d	| j        v s3d
| j        v s*|                    d          r|                    d          sd}||fS )zDetermine if post-filtering is needed based on searcher state and server features.

    Returns (post_filter, hacks) tuple with potentially updated values.

    This is a Sans-I/O function - it only examines data and makes decisions.
    todoFeventjournalbrokenno_comp_filterTN
categoriescategoryzsearch.text.case-sensitivezsearch.time-range.accurate)
comp_classgetattrinclude_completedexpand_property_filtersis_supported)r.   r/   r0   r1   r2   r   r   s          r   _determine_post_filter_neededrA   _   s    &KE
  x// x%00	
 xE22 )) *u$$  	65	)	) 2:2L ?  8555333$$%ABB 4$$%ABB 4 r   r   c                 Z    |                     d           od| j        v pd| j        v o|duS )zCheck if category filters should be removed from server query.

    Returns True if categories/category are in property filters but server
    doesn't support category search properly.
    zsearch.text.categoryr9   r:   F)r@   r?   )r.   r/   r   s      r   _should_remove_category_filterrC      sH     !!"8999 	%X77c:Ic;c	%u$r   c                      |                     d          s|du rg S t           dt                                 fd j        D             S )zGet list of properties with explicit 'contains' operator that server doesn't support.

    These properties should be removed from server query and applied client-side.
    zsearch.text.substringF_explicit_operatorsc                 >    g | ]}|v j         |         d k    |S )contains)_property_operator).0propexplicit_operatorsr.   s     r   
<listcomp>z5_get_explicit_contains_properties.<locals>.<listcomp>   sA       %%%(*Ed*Kz*Y*Y 	*Y*Y*Yr   )r@   r<   r,   rH   )r.   r/   r   rK   s   `  @r   !_get_explicit_contains_propertiesrM      sv     455 9M9M	 +@#%%HH    /   r   c                 t    |                     d          rdS t          | j        s| j        o| j                  S )zCheck if property filters should be removed due to combined search issues.

    Some servers don't handle combined time-range + property filters properly.
    search.combined-is-logical-andF)r@   r)   startendr?   r.   r/   s     r   ,_should_remove_property_filters_for_combinedrS      s?     =>> u/8<OX5OPPPr   c                     t          | dd          r	| j        du sdS |                    d          o?|                    d          o*|                    d           p|                    d          S )zCheck if we need multiple searches for pending todos.

    Returns True if searching for pending todos and server supports the
    necessary features for multi-search approach.
    r4   Fzsearch.textrO   z)search.recurrences.includes-implicit.todoz1search.recurrences.includes-implicit.todo.pending)r<   r=   r@   rR   s     r    _needs_pending_todo_multi_searchrU      s     Hfe,, 1Ku1T1Tu 	m,, 	
!!"BCC	
 %%&QRRR Z$$%XYYr   Fobjectsr   r   server_expandc                 x   |s|j         s|r|s| S g }| D ]$}|j         s|rD	 |                    ||           }n&# t          $ r d |j        j        D             }Y nw xY w|sOnd |j        j        D             }|j        }d |j        D             }	|	|_        |D ]}
t          |
t                    r|rT|                    d          }|j        }g |_        |	D ]}|                    |           |	                    |           n|}|                    |
           |s|	                    |           &|S )a  Apply client-side filtering and handle recurrence expansion/splitting.

    This is a Sans-I/O function - it only processes data without network I/O.

    :param objects: List of Event/Todo/Journal objects to filter
    :param searcher: The CalDAVSearcher with filter criteria
    :param post_filter: Whether to apply the searcher's filter logic.
        - True: Always apply filters (check_component)
        - False: Never apply filters, only handle splitting
        - None: Use default behavior (depends on searcher.expand and other flags)
    :param split_expanded: Whether to split recurrence sets into multiple
        separate CalendarObjectResource objects. If False, a recurrence set
        will be contained in a single object with multiple subcomponents.
    :param server_expand: Indicates that the server was supposed to expand
        recurrences. If True and split_expanded is True, splitting will be
        performed even without searcher.expand being set.
    :return: Filtered and/or split list of CalendarObjectResource objects
    )expand_onlyc                 <    g | ]}t          |t                    |S r-   
isinstancer   rI   xs     r   rL   z*_filter_search_results.<locals>.<listcomp>   s9       TUW_I`I`  r   c                 <    g | ]}t          |t                    |S r-   r[   r]   s     r   rL   z*_filter_search_results.<locals>.<listcomp>   s9       ZPQS[E\E\  r   c                 <    g | ]}t          |t                    |S r-   r[   r]   s     r   rL   z*_filter_search_results.<locals>.<listcomp>  s'    EEEQZ8-D-DEqEEEr   T)keep_uid)
r>   check_component
ValueErroricalendar_instancesubcomponentsr\   r   copyadd_componentappend)rV   r.   r   r   rW   resultofiltereditz_compnew_objnew_itzs                 r   _filter_search_resultsrr      s   2  8? ~ - F % %? 	k 	#33A{?3SS     3A  	   /=  H  EE!/EEE 	& 	&D$))  &&$&//2&(# , ,B''++++g&&&&%%%% 	MM!Ms   : AApropsfilters_hacksc                 b   ddl m}m}m} |}|}	|}
t	          j                    }|rD| j        r| j        st          j	        d          |t	          j
        | j        | j                  z  }||g}n|gt          |          z   }t          j                    |z   }t	          j        d          }d}| j        }|r>t!          |          }t#          |d          r|j        t          j        j        k    r|}g }ng }t	          j        dd	          }t	          j        d
d	          }t	          j        d          }t	          j        d          |z   }t	          j        d          |z   }t	          j        d          |z   }t	          j        d          t	          j                    z   }t	          j        d          t	          j                    z   }|dk    r|                    |||g           n:|dk    r|                    ||g           n|dk    r|                    |g           | j        s| j        r2|                    t	          j        | j        | j                             | j        s| j        rG|                    t	          j        d          t	          j        | j        | j                  z              dd||fdd||	fdd||
fg}|D ]\  }}}}||fn||f}t7          | |d          }|r"|||vrt          j        d| d|           |}|rV|j                            d          |k    r8|}|dk    rt7          | dd          s| j        d| _        tA          | |d           ||v rH|r!|j                            d          |k    sJ nt	          j        |          }tA          | |d           |r|st          j        d| d          |dk    rd}| j!        D ]|} | j!        |          dk    rPt	          j                    }!|                    t	          j        | "                                          |!z              d| j#        |          }"| "                                }#| $                                dk    rd }#| $                                d!k    r|"j%        }$n|"g}$|$D ]}"t#          |"d"          r|"&                                }"d#}%t#          | d$          r?| | j'        v r6| j(                            | d          }&tS          | j'        |          |&          }%t	          j        |"|%%          }!|                    t	          j        |#          |!z              ~|r|r||z  }||z  }n|r||z  }n|r||z  }t	          j*                    |z   }'t	          j+                    ||'gz   }(|(|fS )&a  Build a CalDAV calendar-query XML request.

    This is a Sans-I/O function - it only builds XML without network I/O.

    :param searcher: CalDAVSearcher instance with search parameters
    :param server_expand: Ask server to expand recurrences
    :param props: Additional CalDAV properties to request
    :param filters: Pre-built filter elements (or None to build from searcher)
    :param _hacks: Compatibility hack mode
    :return: Tuple of (xml_element, comp_class)
    r   )EventJournalTodoz!can't expand without a date rangeN	VCALENDARtag	COMPLETEDT)negate	CANCELLEDzNEEDS-ACTIONSTATUSignore_completed1ignore_completed2ignore_completed3VALARMr5   VEVENTr4   VTODOr6   VJOURNALFz.inconsistent search parameters - comp_class = z, want namezunsupported comp class z for searchr8   undefr:   
CATEGORIESr9   to_icalr   _property_collation)r   ),caldav.calendarobjectresourcerw   rx   ry   r
   CalendarDatarP   rQ   r   ReportErrorExpandlistr   Prop
CompFilterr;   r   hasattrr{   	TextMatch
PropFilter
NotDefinedextendrh   	TimeRangealarm_start	alarm_endr<   ConsistencyError
attributesgetr=   setattrrH   upperr?   lowercatsr   r   _property_case_sensitiver   FilterCalendarQuery))r.   rW   rs   rt   ru   rw   rx   ry   
AsyncEvent	AsyncTodoAsyncJournaldataprops_rJ   	vcalendarcomp_filterr;   vNotCompletedvNotCancelledvNeedsActionvStatusNotCompletedvStatusNotCancelledvStatusNeedsActionvStatusNotDefinedvNoCompleteDatecomp_mappingsflag	comp_name
sync_classasync_classcomp_classesflaggedpropertymatchvalue	property_valuescollation_strr   filter_elemroots)                                            r   _build_search_xml_queryr     s   & CBBBBBBBBB JIL D :~ 	IX\ 	I#$GHHHHNHL999}$u++%8::D,,IK$J 7##7E"" 	w{do6I'I'I!KG N;t<<<MN;t<<<M>.11L/(33mC/(33mC22\A11DO4E4EEok22T_5F5FFO$$$)<>QRSSSS	&	&	&):;<<<<	&	&	&*+,,,~ E Et~hnhlCCDDD 
x1 
OH%%x7KXM_(`(``	
 	
 	
 
(E:.	$	*	J6M 5B * *0i[(3(;
}}*kAZ(D%00 	$%*L*H*H,dZddXbdd   $J 	*;155f==JJ#J&%88 .6-1*HdD)))%% 9"-11&99YFFFFF"oi88HdD))) X+ X$%Vz%V%V%VWWW
 !!! / C C&x0G;;O%%ENN4?8>>+;+;<<uDEEEE.x8E ((I~~:--(	~~<// C C5),, ,!MMOOE !*H&;<< H$@@@%-%F%J%J8UY%Z%ZN$8 4X>% %M uFFFty99EABBBB!C&  w w[ 			 [ 			 W	+--)+K4"55D*r   )T)NTF)FNNN)&r(   rf   r   dataclassesr   r   typingr   r   	icalendarr   icalendar_searcher.collationr	   caldav.elementsr
   r   
caldav.libr   icalendar_searcherr   r   r   caldav.compatibility_hintsr   r)   r+   r   r   tuplerA   rC   r   rM   rS   rU   rr   typer   r-   r   r   <module>r      s          ( ( ( ( ( ( ( ( % % % % % % % %       2 2 2 2 2 2 % % % % % % % %       6++++++DDDDDD555555 I t s    B ' ' ' ' ' ' ' ':*** Tz* :	*
 * 4$;d
"#* * * *Z  
	   "  
#Y	   (
Q
Q
Q 

Q 
Q 
Q 
Q 
   2  $D D*+DD D 	D
 D 

"#D D D DR  "j jjj 9tj 	j
 $Jj 3tj j j j j jr   