o
    ;Di                     @   sV  d dl mZmZmZ d dlmZmZ d dlmZ d dl	m
Z
mZmZmZmZ d dlmZ d dlmZ d dlmZ dJddZdJddZdKddZdKddZ	
	dLddZee_dd ZG dd deZ	
	dMddZee_G dd deZdNdd Zee_			dOd!d"Z e e_ 			dLd#d$Z!e!e_!			dMd%d&Z"e"e_"			dNd'd(Z#e#e_#		dPd)d*Z$e$e_$			
dQd+d,Z%e%e_%G d-d. d.eZ&			
dRd/d0Z'e'e_'G d1d2 d2eZ(			
dSd3d4Z)e)e_)G d5d6 d6eZ*	dTd7d8Z+			
	dUd9d:Z,e,e_,		dUd;d<Z-e-e_-G d=d> d>eZ.d?d@ Z/d dAl0m1Z1 e1dBdCZ2dJdDdEZ3e3e_3dFdG Z4dHdI Z5d
S )V    )absolute_importprint_functiondivision)
itemgetter
attrgetter)	text_type)	asindicesrecordsTablevalues
rowgroupby)DuplicateKeyError)addfield)sortstartstopNc                 C   s   ddl }| }t| }t|}ttt|}||v sJ d||v s'J dt||}	t||}
|du r<t	}nt
||}t|dksKJ dt| }|D ]}||	||
||| qQ|S )zq
    Construct an interval tree for the given table, where each node in the tree
    is a row of the table.

    r   Nstart field not recognisedstop field not recognised!invalid value field specification)intervaltreeIntervalTreeiternextlistmapr   r   indextupler   lenaddi)tabler   r   valuer   treeithdrfldsgetstartgetstopgetvaluevalueindicesrow r*   Q/var/www/Datamplify/venv/lib/python3.10/site-packages/petl/transform/intervals.py	tupletree   s"   
r,   c                 C   s
  ddl }t| }t|}ttt|}||v sJ d||v s#J dt||}	t||}
|du r8t}nt	||}t
|dksGJ dt| }t	||}t
|dksZJ dt| }t }|D ]}||}||vrs| ||< || |	||
||| qc|S )zw
    Construct faceted interval trees for the given table, where each node in
    the tree is a row of the table.

    r   Nr   r   r   zinvalid key)r   r   r   r   r   r   r   r   r   r   r   dictr   r   )r   keyr   r   r    r   r"   r#   r$   r%   r&   r'   r(   
keyindicesgetkeytreesr)   kr*   r*   r+   facettupletrees)   s.   

 r3   c                 C   sH   ddl }t|}t|}| }t| D ]}|||||| q|S )z
    Construct an interval tree for the given table, where each node in the
    tree is a row of the table represented as a record object.

    r   N)r   r   r   r	   r   )r   r   r   r   r%   r&   r!   recr*   r*   r+   
recordtreeK   s   r5   c                 C   sn   ddl }t|}t|}t|}t }t| D ]}	||	}
|
|vr'| ||
< ||
 ||	||	|	 q|S )zn
    Construct faceted interval trees for the given table, where each node in 
    the tree is a record.

    r   N)r   r   r-   r	   r   r   )r   r.   r   r   r   r%   r&   r0   r1   r4   r2   r*   r*   r+   facetrecordtrees[   s   r6   Fc                 C   s   t | |||d}t||dS )a  
    Construct an interval lookup for the given table. E.g.::

        >>> import petl as etl
        >>> table = [['start', 'stop', 'value'],
        ...          [1, 4, 'foo'],
        ...          [3, 7, 'bar'],
        ...          [4, 9, 'baz']]
        >>> lkp = etl.intervallookup(table, 'start', 'stop')
        >>> lkp.search(0, 1)
        []
        >>> lkp.search(1, 2)
        [(1, 4, 'foo')]
        >>> lkp.search(2, 4)
        [(1, 4, 'foo'), (3, 7, 'bar')]
        >>> lkp.search(2, 5)
        [(1, 4, 'foo'), (3, 7, 'bar'), (4, 9, 'baz')]
        >>> lkp.search(9, 14)
        []
        >>> lkp.search(19, 140)
        []
        >>> lkp.search(0)
        []
        >>> lkp.search(1)
        [(1, 4, 'foo')]
        >>> lkp.search(2)
        [(1, 4, 'foo')]
        >>> lkp.search(4)
        [(3, 7, 'bar'), (4, 9, 'baz')]
        >>> lkp.search(5)
        [(3, 7, 'bar'), (4, 9, 'baz')]

    Note start coordinates are included and stop coordinates are excluded
    from the interval. Use the `include_stop` keyword argument to include the
    upper bound of the interval when finding overlaps.

    Some examples using the `include_stop` and `value` keyword arguments::
    
        >>> import petl as etl
        >>> table = [['start', 'stop', 'value'],
        ...          [1, 4, 'foo'],
        ...          [3, 7, 'bar'],
        ...          [4, 9, 'baz']]
        >>> lkp = etl.intervallookup(table, 'start', 'stop', include_stop=True,
        ...                          value='value')
        >>> lkp.search(0, 1)
        ['foo']
        >>> lkp.search(1, 2)
        ['foo']
        >>> lkp.search(2, 4)
        ['foo', 'bar', 'baz']
        >>> lkp.search(2, 5)
        ['foo', 'bar', 'baz']
        >>> lkp.search(9, 14)
        ['baz']
        >>> lkp.search(19, 140)
        []
        >>> lkp.search(0)
        []
        >>> lkp.search(1)
        ['foo']
        >>> lkp.search(2)
        ['foo']
        >>> lkp.search(4)
        ['foo', 'bar', 'baz']
        >>> lkp.search(5)
        ['bar', 'baz']

    r   r   r    include_stop)r,   IntervalTreeLookup)r   r   r   r    r9   r!   r*   r*   r+   intervallookupo   s   Hr;   c                 C   sz   |d u r|r|d }|d8 }||f}n|f}n|r!|d7 }|d8 }||f}t |dkr4t| j| }|S t| j| }|S )N      )r   sortedoverlapat)r!   r   r   r9   argsresultsr*   r*   r+   _search_tree   s   
rC   c                   @   s$   e Zd ZdddZdddZeZdS )	r:   Fc                 C   s   || _ || _d S N)r!   r9   )selfr!   r9   r*   r*   r+   __init__   s   
zIntervalTreeLookup.__init__Nc                 C   s    t | j||| j}dd |D S )Nc                 S   s   g | ]}|j qS r*   )data).0rr*   r*   r+   
<listcomp>   s    z-IntervalTreeLookup.search.<locals>.<listcomp>)rC   r!   r9   rE   r   r   rB   r*   r*   r+   search   s   zIntervalTreeLookup.searchFrD   __name__
__module____qualname__rF   rL   findr*   r*   r*   r+   r:      s    

r:   Tc                 C   s   t | |||d}t|||dS )a  
    Construct an interval lookup for the given table, returning at most one
    result for each query. E.g.::

        >>> import petl as etl
        >>> table = [['start', 'stop', 'value'],
        ...          [1, 4, 'foo'],
        ...          [3, 7, 'bar'],
        ...          [4, 9, 'baz']]
        >>> lkp = etl.intervallookupone(table, 'start', 'stop', strict=False)
        >>> lkp.search(0, 1)
        >>> lkp.search(1, 2)
        (1, 4, 'foo')
        >>> lkp.search(2, 4)
        (1, 4, 'foo')
        >>> lkp.search(2, 5)
        (1, 4, 'foo')
        >>> lkp.search(9, 14)
        >>> lkp.search(19, 140)
        >>> lkp.search(0)
        >>> lkp.search(1)
        (1, 4, 'foo')
        >>> lkp.search(2)
        (1, 4, 'foo')
        >>> lkp.search(4)
        (3, 7, 'bar')
        >>> lkp.search(5)
        (3, 7, 'bar')

    If ``strict=True``, queries returning more than one result will
    raise a `DuplicateKeyError`. If ``strict=False`` and there is
    more than one result, the first result is returned.

    Note start coordinates are included and stop coordinates are excluded
    from the interval. Use the `include_stop` keyword argument to include the
    upper bound of the interval when finding overlaps.

    r7   )strictr9   )r,   IntervalTreeLookupOne)r   r   r   r    r9   rS   r!   r*   r*   r+   intervallookupone   s   )rU   c                   @   s$   e Zd ZdddZd	ddZeZdS )
rT   TFc                 C   s   || _ || _|| _d S rD   )r!   rS   r9   )rE   r!   rS   r9   r*   r*   r+   rF     s   
zIntervalTreeLookupOne.__init__Nc                 C   sJ   t | j||| j}t|dkrd S t|dkr | jr t||f|d jS )Nr   r<   )rC   r!   r9   r   rS   r   rG   rK   r*   r*   r+   rL     s   
zIntervalTreeLookupOne.search)TFrD   rN   r*   r*   r*   r+   rT     s    

	rT   c                 C   s   t | ||d}t||dS )zg
    As :func:`petl.transform.intervals.intervallookup` but return records
    instead of tuples.

    r   r   r8   )r5   r:   )r   r   r   r9   r!   r*   r*   r+   intervalrecordlookup"  s   rW   c                 C   s   t | ||d}t|||dS )zj
    As :func:`petl.transform.intervals.intervallookupone` but return records
    instead of tuples.

    rV   r9   rS   )r5   rT   )r   r   r   r9   rS   r!   r*   r*   r+   intervalrecordlookupone0  s   rY   c           	      C   s:   t | ||||d}t }|D ]}t|| |d||< q|S )a  

    Construct a faceted interval lookup for the given table. E.g.::

        >>> import petl as etl
        >>> table = (('type', 'start', 'stop', 'value'),
        ...          ('apple', 1, 4, 'foo'),
        ...          ('apple', 3, 7, 'bar'),
        ...          ('orange', 4, 9, 'baz'))
        >>> lkp = etl.facetintervallookup(table, key='type', start='start', stop='stop')
        >>> lkp['apple'].search(1, 2)
        [('apple', 1, 4, 'foo')]
        >>> lkp['apple'].search(2, 4)
        [('apple', 1, 4, 'foo'), ('apple', 3, 7, 'bar')]
        >>> lkp['apple'].search(2, 5)
        [('apple', 1, 4, 'foo'), ('apple', 3, 7, 'bar')]
        >>> lkp['orange'].search(2, 5)
        [('orange', 4, 9, 'baz')]
        >>> lkp['orange'].search(9, 14)
        []
        >>> lkp['orange'].search(19, 140)
        []
        >>> lkp['apple'].search(1)
        [('apple', 1, 4, 'foo')]
        >>> lkp['apple'].search(2)
        [('apple', 1, 4, 'foo')]
        >>> lkp['apple'].search(4)
        [('apple', 3, 7, 'bar')]
        >>> lkp['apple'].search(5)
        [('apple', 3, 7, 'bar')]
        >>> lkp['orange'].search(5)
        [('orange', 4, 9, 'baz')]

    r7   r8   )r3   r-   r:   )	r   r.   r   r   r    r9   r1   outr2   r*   r*   r+   facetintervallookup?  s
   %r[   c           
      C   s<   t | ||||d}t }|D ]}	t||	 ||d||	< q|S )a7  
    Construct a faceted interval lookup for the given table, returning at most
    one result for each query.
    
    If ``strict=True``, queries returning more than one result will
    raise a `DuplicateKeyError`. If ``strict=False`` and there is
    more than one result, the first result is returned.

    r7   rX   )r3   r-   rT   )
r   r.   r   r   r    r9   rS   r1   rZ   r2   r*   r*   r+   facetintervallookuponen  s   
r\   c                 C   s8   t | |||d}t }|D ]}t|| |d||< q|S )zZ
    As :func:`petl.transform.intervals.facetintervallookup` but return records.
    
    rV   r8   )r6   r-   r:   )r   r.   r   r   r9   r1   rZ   r2   r*   r*   r+   facetintervalrecordlookup  s
   r]   c           	      C   s:   t | |||d}t }|D ]}t|| ||d||< q|S )z]
    As :func:`petl.transform.intervals.facetintervallookupone` but return
    records.

    rV   rX   )r6   r-   rT   )	r   r.   r   r   r9   rS   r1   rZ   r2   r*   r*   r+   facetintervalrecordlookupone  s   
r^   c                 C   s6   |du |du ksJ dt | |||||||||	|
dS )a  
    Join two tables by overlapping intervals. E.g.::

        >>> import petl as etl
        >>> left = [['begin', 'end', 'quux'],
        ...         [1, 2, 'a'],
        ...         [2, 4, 'b'],
        ...         [2, 5, 'c'],
        ...         [9, 14, 'd'],
        ...         [1, 1, 'e'],
        ...         [10, 10, 'f']]
        >>> right = [['start', 'stop', 'value'],
        ...          [1, 4, 'foo'],
        ...          [3, 7, 'bar'],
        ...          [4, 9, 'baz']]
        >>> table1 = etl.intervaljoin(left, right,
        ...                           lstart='begin', lstop='end',
        ...                           rstart='start', rstop='stop')
        >>> table1.lookall()
        +-------+-----+------+-------+------+-------+
        | begin | end | quux | start | stop | value |
        +=======+=====+======+=======+======+=======+
        |     1 |   2 | 'a'  |     1 |    4 | 'foo' |
        +-------+-----+------+-------+------+-------+
        |     2 |   4 | 'b'  |     1 |    4 | 'foo' |
        +-------+-----+------+-------+------+-------+
        |     2 |   4 | 'b'  |     3 |    7 | 'bar' |
        +-------+-----+------+-------+------+-------+
        |     2 |   5 | 'c'  |     1 |    4 | 'foo' |
        +-------+-----+------+-------+------+-------+
        |     2 |   5 | 'c'  |     3 |    7 | 'bar' |
        +-------+-----+------+-------+------+-------+
        |     2 |   5 | 'c'  |     4 |    9 | 'baz' |
        +-------+-----+------+-------+------+-------+

        >>> # include stop coordinate in intervals
        ... table2 = etl.intervaljoin(left, right,
        ...                           lstart='begin', lstop='end',
        ...                           rstart='start', rstop='stop',
        ...                           include_stop=True)
        >>> table2.lookall()
        +-------+-----+------+-------+------+-------+
        | begin | end | quux | start | stop | value |
        +=======+=====+======+=======+======+=======+
        |     1 |   2 | 'a'  |     1 |    4 | 'foo' |
        +-------+-----+------+-------+------+-------+
        |     2 |   4 | 'b'  |     1 |    4 | 'foo' |
        +-------+-----+------+-------+------+-------+
        |     2 |   4 | 'b'  |     3 |    7 | 'bar' |
        +-------+-----+------+-------+------+-------+
        |     2 |   4 | 'b'  |     4 |    9 | 'baz' |
        +-------+-----+------+-------+------+-------+
        |     2 |   5 | 'c'  |     1 |    4 | 'foo' |
        +-------+-----+------+-------+------+-------+
        |     2 |   5 | 'c'  |     3 |    7 | 'bar' |
        +-------+-----+------+-------+------+-------+
        |     2 |   5 | 'c'  |     4 |    9 | 'baz' |
        +-------+-----+------+-------+------+-------+
        |     9 |  14 | 'd'  |     4 |    9 | 'baz' |
        +-------+-----+------+-------+------+-------+
        |     1 |   1 | 'e'  |     1 |    4 | 'foo' |
        +-------+-----+------+-------+------+-------+

    Note start coordinates are included and stop coordinates are excluded
    from the interval. Use the `include_stop` keyword argument to include the
    upper bound of the interval when finding overlaps.

    An additional key comparison can be made, e.g.::
    
        >>> import petl as etl
        >>> left = (('fruit', 'begin', 'end'),
        ...         ('apple', 1, 2),
        ...         ('apple', 2, 4),
        ...         ('apple', 2, 5),
        ...         ('orange', 2, 5),
        ...         ('orange', 9, 14),
        ...         ('orange', 19, 140),
        ...         ('apple', 1, 1))
        >>> right = (('type', 'start', 'stop', 'value'),
        ...          ('apple', 1, 4, 'foo'),
        ...          ('apple', 3, 7, 'bar'),
        ...          ('orange', 4, 9, 'baz'))
        >>> table3 = etl.intervaljoin(left, right,
        ...                           lstart='begin', lstop='end', lkey='fruit',
        ...                           rstart='start', rstop='stop', rkey='type')
        >>> table3.lookall()
        +----------+-------+-----+----------+-------+------+-------+
        | fruit    | begin | end | type     | start | stop | value |
        +==========+=======+=====+==========+=======+======+=======+
        | 'apple'  |     1 |   2 | 'apple'  |     1 |    4 | 'foo' |
        +----------+-------+-----+----------+-------+------+-------+
        | 'apple'  |     2 |   4 | 'apple'  |     1 |    4 | 'foo' |
        +----------+-------+-----+----------+-------+------+-------+
        | 'apple'  |     2 |   4 | 'apple'  |     3 |    7 | 'bar' |
        +----------+-------+-----+----------+-------+------+-------+
        | 'apple'  |     2 |   5 | 'apple'  |     1 |    4 | 'foo' |
        +----------+-------+-----+----------+-------+------+-------+
        | 'apple'  |     2 |   5 | 'apple'  |     3 |    7 | 'bar' |
        +----------+-------+-----+----------+-------+------+-------+
        | 'orange' |     2 |   5 | 'orange' |     4 |    9 | 'baz' |
        +----------+-------+-----+----------+-------+------+-------+

    N:facet key field must be provided for both or neither table)	lstartlstoprstartrstoplkeyrkeyr9   lprefixrprefix)IntervalJoinView)leftrightr`   ra   rb   rc   rd   re   r9   rf   rg   r*   r*   r+   intervaljoin  s   k
rk   c                   @   $   e Zd Z			d	ddZdd ZdS )
rh   r   r   NFc                 C   sF   || _ || _|| _|| _|| _|| _|| _|| _|	| _|
| _	|| _
d S rD   )ri   r`   ra   rd   rj   rb   rc   re   r9   rf   rg   )rE   ri   rj   r`   ra   rb   rc   rd   re   r9   rf   rg   r*   r*   r+   rF   !  s   
zIntervalJoinView.__init__c                 C   s8   t | j| j| j| j| j| j| j| j| j	d | j
| jddS )NFri   rj   r`   ra   rb   rc   rd   re   r9   missingrf   rg   	leftouter)iterintervaljoinri   rj   r`   ra   rb   rc   rd   re   r9   rf   rg   rE   r*   r*   r+   __iter__0  s   zIntervalJoinView.__iter__	r   r   r   r   NNFNNrO   rP   rQ   rF   rr   r*   r*   r*   r+   rh     s    
rh   c                 C   s8   |du |du ksJ dt | |||||||||	|
|dS )aq  
    Like :func:`petl.transform.intervals.intervaljoin` but rows from the left 
    table without a match in the right table are also included. E.g.::

        >>> import petl as etl
        >>> left = [['begin', 'end', 'quux'],
        ...         [1, 2, 'a'],
        ...         [2, 4, 'b'],
        ...         [2, 5, 'c'],
        ...         [9, 14, 'd'],
        ...         [1, 1, 'e'],
        ...         [10, 10, 'f']]
        >>> right = [['start', 'stop', 'value'],
        ...          [1, 4, 'foo'],
        ...          [3, 7, 'bar'],
        ...          [4, 9, 'baz']]
        >>> table1 = etl.intervalleftjoin(left, right,
        ...                               lstart='begin', lstop='end',
        ...                               rstart='start', rstop='stop')
        >>> table1.lookall()
        +-------+-----+------+-------+------+-------+
        | begin | end | quux | start | stop | value |
        +=======+=====+======+=======+======+=======+
        |     1 |   2 | 'a'  |     1 |    4 | 'foo' |
        +-------+-----+------+-------+------+-------+
        |     2 |   4 | 'b'  |     1 |    4 | 'foo' |
        +-------+-----+------+-------+------+-------+
        |     2 |   4 | 'b'  |     3 |    7 | 'bar' |
        +-------+-----+------+-------+------+-------+
        |     2 |   5 | 'c'  |     1 |    4 | 'foo' |
        +-------+-----+------+-------+------+-------+
        |     2 |   5 | 'c'  |     3 |    7 | 'bar' |
        +-------+-----+------+-------+------+-------+
        |     2 |   5 | 'c'  |     4 |    9 | 'baz' |
        +-------+-----+------+-------+------+-------+
        |     9 |  14 | 'd'  | None  | None | None  |
        +-------+-----+------+-------+------+-------+
        |     1 |   1 | 'e'  | None  | None | None  |
        +-------+-----+------+-------+------+-------+
        |    10 |  10 | 'f'  | None  | None | None  |
        +-------+-----+------+-------+------+-------+

    Note start coordinates are included and stop coordinates are excluded
    from the interval. Use the `include_stop` keyword argument to include the
    upper bound of the interval when finding overlaps.

    Nr_   )
r`   ra   rb   rc   rd   re   r9   rn   rf   rg   )IntervalLeftJoinView)ri   rj   r`   ra   rb   rc   rd   re   r9   rn   rf   rg   r*   r*   r+   intervalleftjoinB  s   3
rv   c                   @   rl   )
ru   r   r   NFc                 C   sL   || _ || _|| _|| _|| _|| _|| _|| _|	| _|
| _	|| _
|| _d S rD   )ri   r`   ra   rd   rj   rb   rc   re   rn   r9   rf   rg   )rE   ri   rj   r`   ra   rb   rc   rd   re   rn   r9   rf   rg   r*   r*   r+   rF     s   
zIntervalLeftJoinView.__init__c                 C   s:   t | j| j| j| j| j| j| j| j| j	| j
| j| jddS )NTrm   )rp   ri   rj   r`   ra   rb   rc   rd   re   r9   rn   rf   rg   rq   r*   r*   r+   rr     s   zIntervalLeftJoinView.__iter__)
r   r   r   r   NNNFNNrt   r*   r*   r*   r+   ru     s    
ru   c
           
      C   s4   |du |du ksJ dt | |||||||||	d
S )a1  
    Return rows from the `left` table with no overlapping rows from the `right`
    table.

    Note start coordinates are included and stop coordinates are excluded
    from the interval. Use the `include_stop` keyword argument to include the
    upper bound of the interval when finding overlaps.

    Nr_   )r`   ra   rb   rc   rd   re   r9   rn   )IntervalAntiJoinView)
ri   rj   r`   ra   rb   rc   rd   re   r9   rn   r*   r*   r+   intervalantijoin  s   
rx   c                   @   $   e Zd Z			d	ddZdd ZdS )
rw   r   r   NFc                 C   s@   || _ || _|| _|| _|| _|| _|| _|| _|	| _|
| _	d S rD   )
ri   r`   ra   rd   rj   rb   rc   re   rn   r9   )rE   ri   rj   r`   ra   rb   rc   rd   re   rn   r9   r*   r*   r+   rF     s   
zIntervalAntiJoinView.__init__c                 C   s8   t | j| j| j| j| j| j| j| j| j	| j
d d dddS )NT)ri   rj   r`   ra   rb   rc   rd   re   r9   rn   rf   rg   ro   anti)rp   ri   rj   r`   ra   rb   rc   rd   re   r9   rn   rq   r*   r*   r+   rr     s    zIntervalAntiJoinView.__iter__)r   r   r   r   NNNFrt   r*   r*   r*   r+   rw     s    
rw   c           !   	   #   s   t | }t|}ttt|}t |}t|}ttt|}t|| t|| |d ur2t|| t|| t|| |d urEt||  d u rUt|}|sT|| nt fdd|D }|sn|fdd|D  t|V  t|	|}t|	|}|d u rt
||||d}|j}|D ]>}||}||}|||}|r|s|D ]}t|}|| t|V  qq|rt|}|s||	gt|  t|V  qd S t|||||d}t }|D ]	}|| j||< qtt|| } |D ]c}| |}||}||}z	|| ||}W n ty   d }Y n ty"   d }Y nw |r>|s=|D ]}t|}|| t|V  q+q|rWt|}|sR||	gt|  t|V  qd S )Nc                 3       | ]} | V  qd S rD   r*   rH   f)rf   r*   r+   	<genexpr>      z#iterintervaljoin.<locals>.<genexpr>c                 3   r{   rD   r*   r|   )rg   r*   r+   r~     r   r8   r.   r   r   r9   )r   r   r   r   r   r   extendr   r   r   r;   rL   r   r[   r-   KeyErrorAttributeError)!ri   rj   r`   ra   rb   rc   rd   re   r9   rn   rf   rg   ro   rz   litlhdrlfldsritrhdrrfldsouthdr	getlstartgetlstoplookuprL   lrowr   r   rrowsrrowoutrowr}   getlkeyr*   )rf   rg   r+   rp     s   












rp   c
                    sv    du |du ksJ d du r"t |||||	dfdd}
nt||||||	d fdd}
t| ||
S )aJ  
    Convenience function to join the left table with values from a specific 
    field in the right hand table.
    
    Note start coordinates are included and stop coordinates are excluded
    from the interval. Use the `include_stop` keyword argument to include the
    upper bound of the interval when finding overlaps.

    Nr_   )r   r   r    r9   c                    s     |  |  S rD   rL   r)   )lkpr`   ra   r*   r+   <lambda>P      z$intervaljoinvalues.<locals>.<lambda>c                    s   |     |  |  S rD   r   r   rd   r   r`   ra   r*   r+   r   T  s    )r;   r[   r   )ri   rj   r    r`   ra   rb   rc   rd   re   r9   r}   r*   r   r+   intervaljoinvalues>  s   

r   c	           	      C   s2   |du |du ksJ dt | ||||||||d	S )ze
    Subtract intervals in the right hand table from intervals in the left hand 
    table.
    
    Nr_   )r`   ra   rb   rc   rd   re   r9   )IntervalSubtractView)	ri   rj   r`   ra   rb   rc   rd   re   r9   r*   r*   r+   intervalsubtract[  s   
r   c                   @   ry   )
r   r   r   NFc
           
      C   s:   || _ || _|| _|| _|| _|| _|| _|| _|	| _d S rD   )	ri   r`   ra   rd   rj   rb   rc   re   r9   )
rE   ri   rj   r`   ra   rb   rc   rd   re   r9   r*   r*   r+   rF   o  s   
zIntervalSubtractView.__init__c              
   C   s*   t | j| j| j| j| j| j| j| j| j		S rD   )
iterintervalsubtractri   rj   r`   ra   rb   rc   rd   re   r9   rq   r*   r*   r+   rr   |  s   zIntervalSubtractView.__iter__r   r   r   r   NNFrt   r*   r*   r*   r+   r   m  s    
r   c	              	   #   sN   t | }	t|	}
ttt|
}t |}t|}t|
| t|
| |d ur+t|
| t|| t|| |d ur>t|| t|}t|V  t|
||f\}}t||}tt|||f  |d u rt||||d}|j	}|	D ]@}||\}}|||}|st|V  qot
 fdd|D tdd}t|||D ]\}}t|}|||< |||< t|V  qqod S t|||||d}tt|
| }|	D ]`}||}||\}}z
|| 	||}W n ty   d }Y n ty   d }Y nw |st|V  qt
 fdd|D tdd}t|||D ]\}}t|}|||< |||< t|V  qqd S )Nr8   c                       g | ]} |qS r*   r*   rH   r   
getrcoordsr*   r+   rJ     r   z(iterintervalsubtract.<locals>.<listcomp>r   r.   r   c                    r   r*   r*   r   r   r*   r+   rJ     r   )r   r   r   r   r   r   r   r   r;   rL   r>   	_subtractr[   r   r   )ri   rj   r`   ra   rb   rc   rd   re   r9   r   r   r   r   r   r   	lstartidxlstopidx
getlcoordsr   rL   r   r   r   r   rivsxyrZ   r   r*   r   r+   r     s~   









r   )
namedtupleIntervalz
start stopc                 c   s    |du rt | |d} tt| ||fD ]}|V  qdS t | ||fd} t| |||fdD ]\}}t|D ]}|f| V  q5q-dS )z
    Utility function to collapse intervals in a table. 
    
    If no facet `key` is given, returns an iterator over `(start, stop)` tuples.
    
    If facet `key` is given, returns an iterator over `(key, start, stop)`
    tuples.
    
    Nr   )r.   r    )r   	_collapser   r   )r   r   r   r.   ivr2   gr*   r*   r+   collapsedintervals  s   r   c                 c   s    d}| D ]/\}}|du rt ||}q||j  kr|k r'n nt |j|}q||jkr4|V  t ||}q|dur>|V  dS dS )zG
    Collapse an iterable of intervals sorted by start coord.
    
    N)	_Intervalr   r   )	intervalsspanr   r   r*   r*   r+   r     s   


r   c                 c   s\    | }d}t |D ]\}}||k rt||V  |}q	|dur*||k r,t||V  dS dS dS )z;
    Subtract intervals from a spanning interval.
    
    N)r   r   )r   r   r   remainder_startsub_stop	sub_startr*   r*   r+   r     s   r   )r   r   NrV   )r   r   NF)r   r   NFT)r   r   F)r   r   FT)FTrs   )
r   r   r   r   NNFNNN)r   r   r   r   NNFNrM   r   )6
__future__r   r   r   operatorr   r   petl.compatr   petl.util.baser   r	   r
   r   r   petl.errorsr   petl.transform.basicsr   petl.transform.sortsr   r,   r3   r5   r6   r;   rC   objectr:   rU   rT   rW   rY   r[   r\   r]   r^   rk   rh   rv   ru   rx   rw   rp   r   r   r   r   collectionsr   r   r   r   r   r*   r*   r*   r+   <module>   s    


"

L
-


,



s#
<$
%
^

M

