
    ג[i6              	           d Z ddlmZmZmZmZmZ ddlZ G d d          Z	 ddeee	ef         ee         f         de	d	ee	ef         fd
Z
	 ddee	ef         de	d	ee	ef         fdZdS )aQ  
Universal JSON Flattener

This module provides recursive JSON flattening functionality to convert
deeply nested JSON structures into flat key-value pairs suitable for
tabular display and editing.

Key principles:
- NO data loss - ALL fields at ANY depth are preserved
- NO hardcoded field names - works with ANY JSON structure
- Recursive parsing of nested objects and arrays
- Dot notation for nested paths (e.g., "parent.child.0.field")
- Type preservation for all values

CRITICAL: This is a data integrity critical component.
Every field from source JSON MUST appear in flattened output.
    )DictAnyListUnionOptionalNc                      e Zd ZdZddefdZ	 	 ddeeeef         e	e         f         ded	e
d
eeef         fdZde	e         ded	e
d
eeef         fdZdeeef         d
eeef         fdZde	eeef                  d
e	e         fdZ	 dde	eeef                  de
d
e	eeef                  fdZ	 ddeeef         de
d
e	eeef                  fdZdS )JSONFlattenera  
    Universal JSON flattener that converts nested structures to flat key-value pairs.
    
    Handles:
    - Nested dictionaries (unlimited depth)
    - Arrays of primitives
    - Arrays of objects
    - Mixed nested structures
    - Null values
    - All primitive types
    .	separatorc                     || _         dS )z
        Initialize flattener.
        
        Args:
            separator: Character to use for path separation (default: ".")
        N)r   )selfr   s     3/var/www/html/IGF-ODF-V3/services/json_flattener.py__init__zJSONFlattener.__init__$   s     #     Fdata
parent_keypreserve_arraysreturnc                 0   i }t          |t                    r|                                D ]\  }}|r| | j         | n|}t          |t                    r+|                    |                     |||                     Vt          |t                    r+|                    |                     |||                     |||<   nMt          |t                    r+|                    |                     |||                     n|r|||<   n||d<   |S )a  
        Recursively flatten a nested JSON structure.
        
        Args:
            data: Input data (dict or list)
            parent_key: Current path prefix
            preserve_arrays: If True, keep primitive arrays as-is instead of flattening
            
        Returns:
            Flattened dictionary with dot-notation keys
            
        Examples:
            Input: {"a": {"b": {"c": 1}}}
            Output: {"a.b.c": 1}
            
            Input: {"items": [{"id": 1}, {"id": 2}]}
            Output: {"items.0.id": 1, "items.1.id": 2}
            
            Input: {"tags": ["red", "blue"]}
            Output: {"tags.0": "red", "tags.1": "blue"}
            (or {"tags": ["red", "blue"]} if preserve_arrays=True)
        _value)
isinstancedictitemsr   updateflattenlist_flatten_list)r   r   r   r   	flattenedkeyvaluenew_keys           r   r   zJSONFlattener.flatten-   sD   8 	dD!! 	+"jjll / /
UBLUZ>>>>>RUeT** /$$T\\%/%R%RSSSSt,, /$$T%7%7w%X%XYYYY */Ig&&/ d## 		+T//j/RRSSSS  +(,	*%%&*	(#r   r   c                    i }|r"|r t          d |D                       r|||<   |S t          |          D ]\  }}| | j         | }t          |t                    r+|                    |                     |||                     Rt          |t                    r+|                    |                     |||                     |||<   |S )a  
        Flatten a list into indexed keys.
        
        Args:
            items: List to flatten
            parent_key: Current path prefix
            preserve_arrays: If True, keep primitive arrays as-is
            
        Returns:
            Flattened dictionary
        c              3   P   K   | ]!}t          |t          t          f           V  "d S N)r   r   r   ).0items     r   	<genexpr>z.JSONFlattener._flatten_list.<locals>.<genexpr>{   s4      ,b,bTXD4,1O1O-O,b,b,b,b,b,br   )	all	enumerater   r   r   r   r   r   r   )r   r   r   r   r   indexr'   r"   s           r   r   zJSONFlattener._flatten_listg   s   " 	  	u 	,b,b\a,b,b,b)b)b 	$)Ij! %U++ 	* 	*KE4#<T^<U<<G$%% *  dG_!M!MNNNND$'' *  !3!3D'?!S!STTTT &*	'""r   	flat_datac                     i }|                                 D ]\  }}|                    d          r
|dv r|||<   %|                    | j                  }|}t	          |dd                   D ]\  }}|                                r|dk    r||dz
           nd}	|	rt          |t                    s	 t          |          }
t          |t                    sg }t          |          |
k    r(|
                    i            t          |          |
k    (||
         }||vrD|dz   t          |          k     r||dz            nd}|r|                                rg ||<   ni ||<   ||         }|d         }|                                rht          |          }
t          |t                    sg }t          |          |
k    r(|
                    d           t          |          |
k    (|||
<   t          |t                    r|||<   |S )a6  
        Reconstruct nested structure from flattened data.
        
        Args:
            flat_data: Flattened dictionary with dot-notation keys
            
        Returns:
            Nested dictionary/list structure
            
        Note: This is used when writing back to MongoDB or JSON.
        _)_id_source_file_source_path_source_competitionNr      )r   
startswithsplitr   r*   isdigitr   r   intlenappendr   )r   r,   resultflat_keyr!   partscurrentipartr   r+   	next_part	final_keys                r   	unflattenzJSONFlattener.unflatten   s^    (00 7	/ 7	/OHe""3'' H8v,v #(x  NN4>22E G$U3B3Z00 , ,4<<>> ,/01u!>qs$J! *Wd*C*C IIE &gt44 %"$g,,%/ +r*** g,,%/ + &enGG 7* /23A#E

2B$LE!A#JJ	$ /):):)<)< /,.GDMM,.GDM%dmGG b	I  "" /I!'400 ! G'lle+ )NN4((( 'lle+ )!& gt,, /).GI&r   recordsc                     t                      }|D ])}|                    |                                           *d |D             }t          d |D                       }||z   S )z
        Extract all unique keys from a list of flattened records.
        
        Args:
            records: List of flattened dictionaries
            
        Returns:
            Sorted list of all unique keys
        c                 <    g | ]}|                     d           |S r.   r5   r&   ks     r   
<listcomp>z.JSONFlattener.get_all_keys.<locals>.<listcomp>   s)    BBBqS0A0ABBBBr   c                 <    g | ]}|                     d           |S rG   rH   rI   s     r   rK   z.JSONFlattener.get_all_keys.<locals>.<listcomp>   s)    III!q||C7H7HIAIIIr   )setr   keyssorted)r   rD   all_keysrecordmetadata_keys	data_keyss         r   get_all_keyszJSONFlattener.get_all_keys   sv     55 	+ 	+FOOFKKMM**** CBHBBBIIxIIIJJ	y((r   Tfill_missingc                     |sg S |                      |          }|s|S g }|D ]7}i }|D ]}|                    |d          ||<   |                    |           8|S )a,  
        Ensure all records have the same keys (columns).
        
        Args:
            records: List of flattened dictionaries
            fill_missing: If True, add missing keys with None values
            
        Returns:
            List of normalized records with consistent keys
        N)rT   getr:   )r   rD   rU   rP   
normalizedrQ   normalized_recordr    s           r   normalize_recordszJSONFlattener.normalize_records   s      	I $$W-- 	N 
 	1 	1F " ? ?)/C)>)>!#&&/0000r   	json_dataextract_arraysc                 .    |s                      |          gS g }                      |          }i }|                                D ]}|                     j                  }t	          |          D ]\  }}	|	                                r j                            |d|                   }
t          |	          }|dz   t          |          k     r% j                            ||dz   d                   nd}|
|vri ||
<   |||
         vri ||
         |<   |r||         ||
         |         |<   n||         ||
         |         d<    nِ|rt          |                                 fd          }t          ||                                                   D ]s}||         |                                         }|                                D ]'\  }}|                    | j        z             s|||<   (|                    |           tn|g}|S )a  
        Flatten a JSON file that may contain arrays of records.
        
        This is specifically designed for ODF JSON files where the actual
        records are nested inside arrays within the structure.
        
        Args:
            json_data: Parsed JSON data
            extract_arrays: If True, extract array items as separate records
            
        Returns:
            List of flattened records
            
        Example:
            Input: {
                "odf_body": {
                    "competition": {
                        "participant": [
                            {"code": 1, "name": "A"},
                            {"code": 2, "name": "B"}
                        ]
                    }
                }
            }
            
            Output: [
                {
                    "odf_body.competition.participant.0.code": 1,
                    "odf_body.competition.participant.0.name": "A"
                },
                {
                    "odf_body.competition.participant.1.code": 2,
                    "odf_body.competition.participant.1.name": "B"
                }
            ]
        Nr4   r   r   c                 8    |                      j                  S r%   )countr   )xr   s    r   <lambda>z1JSONFlattener.flatten_json_file.<locals>.<lambda>d  s    !''$.BYBY r   )r    )r   rN   r6   r   r*   r7   joinr8   r9   maxrO   copyr   r5   r:   )r   r[   r\   rD   flatarray_pathsr    r=   r?   r@   
array_basearray_indexarray_suffixdeepest_arrayr+   rQ   r!   s   `                r   flatten_json_filezJSONFlattener.flatten_json_file  se   R  	-LL++,,  ||I&& 99;; 	 	CIIdn--E %U++  4<<>> !%!4!4U2A2Y!?!?J"%d))KGHsSQVZZGW#_4>#6#6uQqSTT{#C#C#C]_L!4 524J/"+j*AA B?AJ/< $ SMQRUYJ/<\JJIMcJ/<XFE%*  	   0 0 2 28Y8Y8Y8YZZZM  M : ? ? A ABB 	' 	'$]3E:??AA #'**,, , ,JC>>-$.*HII ,&+sv&&&&	' fGr   Nr
   )r   F)T)__name__
__module____qualname____doc__strr   r   r   r   r   boolr   r   rC   rT   rZ   rk    r   r   r	   r	      s       
 
# ## # # # #  %	8 8DcNDI-.8 8 	8
 
c3h8 8 8 8t'Cy' ' 	'
 
c3h' ' ' 'RG4S> Gd38n G G G GR)Dc3h$8 )T#Y ) ) ) )2 "   d38n%    
d38n		       J  $d dS>d d 
d38n		d d d d d dr   r	   r
   r   r   r   c                 J    t          |          }|                    |           S )z
    Convenience function to flatten JSON data.
    
    Args:
        data: Input JSON data
        separator: Path separator (default: ".")
        
    Returns:
        Flattened dictionary
    )r	   r   )r   r   	flatteners      r   flatten_jsonrv   x  s%     i((IT"""r   r,   c                 J    t          |          }|                    |           S )z
    Convenience function to unflatten data.
    
    Args:
        flat_data: Flattened dictionary
        separator: Path separator (default: ".")
        
    Returns:
        Nested structure
    )r	   rC   )r,   r   ru   s      r   unflatten_jsonrx     s%     i((Iy)))r   rl   )rp   typingr   r   r   r   r   jsonr	   rq   rv   rx   rs   r   r   <module>r{      s   $ 4 3 3 3 3 3 3 3 3 3 3 3 3 3 ^ ^ ^ ^ ^ ^ ^ ^F # #
S#XS	)
*## 
#s(^# # # #( * *CH~** 
#s(^* * * * * *r   