
    `j&                    J   d 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 d	Zd
Zde dZde dZde dZde dZdZddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 	 	 ddZddZd dZdddd	 	 	 	 	 	 	 	 	 d!dZdd	 	 	 	 	 d"dZ	 	 	 	 	 	 d#dZd$dZy)%aH  C59 XML document serializer for Liguria ISTAT XML export.

Generates XSD-compliant XML documents from aggregated C59 payload rows.
This module is fully isolated under xml_export/ and does not modify any existing
TXT export, old ISTAT services, or API endpoints.

Uses standard library xml.etree.ElementTree (lxml not required).
    )annotations)date)Sequence)ElementTree)XmlPayloadValidationError)IstatC59RowPayload)format_xml_datez.http://www.regione.liguria.it/turismo/rimovclirim{z}c59z}mensilez}giornalieroz}rigac59AimantisN)available_roomsavailable_bedsoccupied_roomssoftware_namec                    t        | ||       t        | |      }t        ||||       t        ||      }|D ]  }	t	        ||	        t        |      S )a  Build a complete XSD-compliant C59 XML document.
    
    Args:
        structure_code: Structure identifier (idstruttura)
        report_date: Report date (data) in YYYY-MM-DD format
        rows: Aggregated C59 payload rows (already sorted)
        available_rooms: Number of available rooms (numcameredisp)
        available_beds: Number of available beds (numlettidisp)
        occupied_rooms: Number of occupied rooms (numcamereoccupate)
        software_name: Software name (softwaregestionale), defaults to "Aimantis"
        
    Returns:
        Pretty-printed XML string with UTF-8 encoding and XML declaration
        
    Raises:
        XmlPayloadValidationError: If input data is invalid
    r   r   r   r   )_validate_inputs_build_root_element_add_mensile_node_add_giornaliero_node_add_rigac59_node_to_pretty_xml)
structure_codereport_daterowsr   r   r   r   rootgiornalierorows
             ;/backend/istat/xml_export/serializers/c59_xml_serializer.pybuild_c59_xml_documentr!   #   se    8 ^[$7 ~{;D '%#	 (^LK +s+  $    c                    | rt        |       j                         st        d      |t        d      t        |t              st        d      |t        d      t        |      D ]  \  }}t        ||        y)zValidate serializer inputs before building XML.
    
    Raises:
        XmlPayloadValidationError: If any input is invalid
    z.structure_code is required and cannot be emptyNzreport_date is requiredz#report_date must be a date instancez'rows cannot be None (use empty list []))strstripr   
isinstancer   	enumerate_validate_row)r   r   r   idxr   s        r    r   r   W   s|     ^!4!:!:!<'(XYY '(ABBk4('(MNN |'(QRRdOSc3 $r"   c                   t        | t              st        d| d      | j                  dvrt        d| d| j                   d      | j                  r2| j                  j                         rt        | j                        dk7  rt        d| d| j                   d      | j                  dk  rt        d| d	| j                         | j                  dk  rt        d| d
| j                         | j                  dk  rt        d| d| j                         | j                  dk  rt        d| d| j                         y)zrValidate a single C59 row payload.
    
    Raises:
        XmlPayloadValidationError: If row data is invalid
    zRow z' must be an IstatC59RowPayload instance)iez#: nazione must be 'i' or 'e', got ''   z+: residenza must be exactly 3 digits, got 'r   z#: arrivi must be non-negative, got z%: partenze must be non-negative, got z%: presenze must be non-negative, got z#: diurni must be non-negative, got N)r&   r   r   nazione	residenzaisdigitlenarrivipartenzepresenzediurni)r   indexs     r    r(   r(   s   sl    c-.'5'@A
 	

 {{*$'5'<S[[MK
 	

 == 5 5 73s}};MQR;R'5'DS]]OSTU
 	

 zzA~'5'<SZZLI
 	
 ||a'5'>s||nM
 	
 ||a'5'>s||nM
 	
 zzA~'5'<SZZLI
 	
 r"   c                    t        j                  t              }|j                  dt	        |       j                                |j                  dt        |             |S )zBuild the root <c59> element with required attributes.
    
    Args:
        structure_code: Structure identifier
        report_date: Report date
        
    Returns:
        Root XML element
    idstrutturadata)r   ElementROOT_TAGsetr$   r%   r	   )r   r   r   s      r    r   r      sH     x(DHH]C/5578HHV_[12Kr"   r   c               T   t        j                  | t              }|+|dk  rt        d      |j	                  dt        |             |+|dk  rt        d      |j	                  dt        |             |r|nt        }|j	                  dt        |      j                                |S )a  Add the <mensile> (monthly summary) node.
    
    Args:
        root: Parent element
        available_rooms: Available rooms count
        available_beds: Available beds count
        software_name: Software name
        
    Returns:
        Mensile XML element
    r   z$available_rooms must be non-negativenumcameredispz#available_beds must be non-negativenumlettidispsoftwaregestionale)r   
SubElementMENSILE_TAGr   r=   r$   DEFAULT_SOFTWARE_NAMEr%   )r   r   r   r   mensilesoftwares         r    r   r      s    $ $$T;7G "Q+6  	OS%9:!A+5  	NC$78 !.}3HHKK$c(m&9&9&;<Nr"   r   c                   t        j                  | t              }|+|dk  rt        d      |j	                  dt        |             |S )zAdd the <giornaliero> (daily movement) node.
    
    Args:
        root: Parent element
        occupied_rooms: Occupied rooms count
        
    Returns:
        Giornaliero XML element
    r   z#occupied_rooms must be non-negativenumcamereoccupate)r   rB   GIORNALIERO_TAGr   r=   r$   )r   r   r   s      r    r   r      sR     ((?K !A+5  	+S-@Ar"   c                   t        j                  | t              }|j                  d|j                         |j                  d|j
                         |j                  dt        |j                               |j                  dt        |j                               |j                  dt        |j                               |j                  dkD  r'|j                  dt        |j                               |S |j                  dd       |S )	zAdd a <rigac59> (movement row) node.
    
    Args:
        parent: Parent element (giornaliero)
        row: C59 row payload
        
    Returns:
        Rigac59 XML element
    r/   r0   r3   r4   r5   r   r6   0)r   rB   RIGAC59_TAGr=   r/   r0   r$   r3   r4   r5   r6   )parentr   rigas      r    r   r      s     !!&+6D 	HHY$HH[#--(HHXs3::'HHZS\\*+HHZS\\*+ zzA~3szz?+
 K 	3Kr"   c                T   t        j                  t        t               t        j                  | dd      }ddl}|j                  j                  j                  |      }|j                  dd      }|j                  d      D cg c]  }|j                         s| }}dj                  |      dz   }|j                  d	      r|j                  d	d
      }|S |j                  d      r|j                  dd
      }|S |j                  d      r|j                  dd
      }|S c c}w )zSerialize XML tree to pretty-printed UTF-8 string.
    
    Args:
        root: Root XML element
        
    Returns:
        Pretty-printed XML string with declaration
    unicodexml)encodingmethodr   Nz    )indentrR   
z<?xml version="1.0"?>z&<?xml version="1.0" encoding="utf-8"?>z<?xml version="1.0" ?>z&<?xml version="1.0" encoding="UTF-8"?>)r   register_namespaceNAMESPACE_PREFIXC59_NAMESPACEtostringxml.dom.minidomdomminidomparseStringtoprettyxmlsplitr%   join
startswithreplace)r   
xml_stringrQ   r[   
pretty_xmllineliness          r    r   r     s-    ""#3]C %%dYuMJ  ''//
%
%j
1C>J )..t4E4d

T4EE5!D(J 45''#4

  
		7	8''$4

  
		G	H''44


 ) Fs   D%D%)r   r$   r   r   r   Sequence[IstatC59RowPayload]r   
int | Noner   rh   r   rh   r   
str | Nonereturnr$   )r   r$   r   r   r   rg   rj   None)r   r   r7   intrj   rk   )r   r$   r   r   rj   ElementTree.Element)
r   rm   r   rh   r   rh   r   ri   rj   rm   )r   rm   r   rh   rj   rm   )rM   rm   r   r   rj   rm   )r   rm   rj   r$   )__doc__
__future__r   datetimer   typingr   	xml.etreer   istat.xml_export.exceptionsr   #istat.xml_export.models.c59_payloadr   istat.xml_export.xml.xml_utilsr	   rX   rW   r<   rC   rI   rL   rD   r!   r   r(   r   r   r   r   r    r"   r    <module>rw      s   #   ! A B : A  e$=/+}o]3=/+ #  #'!%!% $1 1  1  '	1 
  1  1  1  1  	1 h    '  
	 8'
T& #'!% $'
'  ' 	'
 ' 'Z "&
  	6	 @+r"   