U
    Œæ‹hž½  ã                   @   s¦   d dl Z d dlZd dlZd dlmZ d dlm  mZ d dl	m	Z	m
Z
 d dlmZ d dlmZ d dlmZ e e¡Zdd„ Zd	d
„ Zdd„ Zdd„ ZG dd„ dƒZdS )é    N)Úminidom)ÚdatetimeÚ	timedelta)Úsettings)Útimezone)ÚContentFilec              
   C   s®   | sdS zbddddg}|D ]:}zt  |  ¡ |¡ ¡ W   W S  tk
rR   Y qY qX qt d| › ¡ W dS  tk
r¨ } z t d| › d|› ¡ W Y ¢dS d}~X Y nX dS )	a3  
    Helper function to convert time strings to time objects.
    Useful for migrating existing data from CharField to TimeField.
    
    Args:
        time_string (str): Time in string format (e.g., "14:30:00", "2:30 PM")
    
    Returns:
        time: Python time object or None if conversion fails
    Nz%H:%M:%Sz%H:%Mz%I:%M:%S %pz%I:%M %pzCould not parse time string: zError converting time string 'ú': )	r   ÚstrptimeÚstripÚtimeÚ
ValueErrorÚloggerÚwarningÚ	ExceptionÚerror)Ztime_stringÚformatsÚfmtÚe© r   ú//var/www/html/Focus/src/apps/playlists/utils.pyÚconvert_time_string_to_time   s$    ür   c              
   C   sæ   | sdS zšd| krt|   d¡}t|ƒdkrJtt|ƒ\}}}tj|||dW S t|ƒdkrttt|ƒ\}}tj||dW S |  ¡ rŽtjt| ƒdW S t d| › ¡ W dS  t	k
rà } z t 
d	| › d
|› ¡ W Y ¢dS d}~X Y nX dS )aU  
    Helper function to convert duration strings to timedelta objects.
    Useful for migrating existing data from CharField to DurationField.
    
    Args:
        duration_string (str): Duration in string format (e.g., "00:30:00", "30 minutes")
    
    Returns:
        timedelta: Python timedelta object or None if conversion fails
    Nú:é   )ÚhoursÚminutesÚsecondsé   )r   r   )r   z!Could not parse duration string: z"Error converting duration string 'r   )ÚsplitÚlenÚmapÚintr   r   Úisdigitr   r   r   r   )Úduration_stringÚpartsr   r   r   r   r   r   r   Ú#convert_duration_string_to_duration5   s$    
r$   c              
   C   s²   | sdS zfddddddg}|D ]:}zt  |  ¡ |¡ ¡ W   W S  tk
rV   Y qY qX qt d| › ¡ W dS  tk
r¬ } z t d	| › d
|› ¡ W Y ¢dS d}~X Y nX dS )a8  
    Helper function to convert date strings to date objects.
    Useful for migrating existing data from CharField to DateField.
    
    Args:
        date_string (str): Date in string format (e.g., "2023-12-25", "25/12/2023")
    
    Returns:
        date: Python date object or None if conversion fails
    Nú%Y-%m-%dz%d/%m/%Yz%m/%d/%Yz%Y/%m/%dz%d-%m-%Yz%m-%d-%YzCould not parse date string: zError converting date string 'r   )	r   r	   r
   Údater   r   r   r   r   )Zdate_stringr   r   r   r   r   r   Úconvert_date_string_to_dateZ   s(    ú	r'   c                 C   s†   | j r| j  d¡nd}| jr$| jjnd}| jr6| jjnd}d dd„ |D ƒ¡ ¡ }d dd„ |D ƒ¡ ¡ }d	|› d
|› d
|› d
|› S )zÂ
    Generate upload path for playlist XML files.
    
    Args:
        instance: Playlist model instance
        filename: Original filename
        
    Returns:
        str: Upload path
    z%Y_%mZno_dateZ
no_channelZ	no_regionÚ c                 s   s"   | ]}|  ¡ s|d kr|V  qdS ©)ú-Ú_N©Úisalnum©Ú.0Úcr   r   r   Ú	<genexpr>‘   s       z+playlist_xml_upload_path.<locals>.<genexpr>c                 s   s"   | ]}|  ¡ s|d kr|V  qdS r)   r,   r.   r   r   r   r1   ’   s       z
playlists/ú/)Úbroadcast_dateÚstrftimeÚchannelÚchannel_nameÚzone_channelÚregionÚjoinr
   )ÚinstanceÚfilenameZ	date_pathr6   Zchannel_regionr   r   r   Úplaylist_xml_upload_path   s    r<   c                   @   sˆ   e Zd ZdZddd„Zddd„Zdd„ Zd	d
„ Zdd„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zedd„ ƒZdd„ Zdd„ Zdd„ ZdS ) ÚPlaylistXMLGeneratora;  
        Comprehensive XML generation and management system for broadcast playlist schedules.
        
        This class provides enterprise-grade XML generation capabilities for converting
        playlist database records into industry-standard SCTE-118-3 compliant XML schedules.
        It handles the complete transformation from hierarchical playlist data structures
        to broadcast-ready XML documents suitable for automation systems.
        
        The generator supports the full playlist hierarchy including:
            - Playlist metadata and scheduling information
            - Time windows with precise timing specifications
            - Advertisement availability slots (avails) within windows
            - Individual advertisement records with traffic management
        
        Key features include:
            - SCTE-118-3 schema compliance for broadcast industry standards
            - Comprehensive error handling and validation
            - File system integration with automatic storage management
            - Detailed logging for audit trails and debugging
            - Traffic ID management for advertisement tracking
            - Flexible date formatting and timezone handling
        
        Business Applications:
            - Broadcast automation system integration
            - Compliance reporting and regulatory requirements
            - Advertisement inventory management and billing
            - Schedule distribution to multiple broadcast facilities
            - Quality assurance and validation workflows
        
        Technical Standards:
            - SCTE-118-3 XML schema compliance
            - ISO 8601 date/time formatting
            - UTF-8 encoding for international character support
            - Structured logging for operational monitoring
        
        Example Usage:
            generator = PlaylistXMLGenerator()
            result = generator.generate_schedule(playlist_instance)
            if result['status']:
                xml_file_path = result['file']
                print(f"XML generated: {xml_file_path}")
    Nc                 C   s    || _ t | jj¡| _d| _dS )a  
            Initialize the XML generator with optional playlist context and logging infrastructure.
            
            Sets up the generator instance with logging capabilities, traffic management,
            and optional playlist binding for streamlined processing workflows.
            
            Args:
                playlist (Playlists, optional): Playlist model instance to bind to this generator
                                            Enables streamlined processing for repeated operations
                                            Can be overridden in individual method calls
            
            Attributes:
                playlist (Playlists): Bound playlist instance for default operations
                logger (Logger): Configured logger for operation tracking and debugging
                traffic_id (int): Global traffic counter for advertisement identification
        r   N)ÚplaylistÚloggingÚ	getLoggerÚ	__class__Ú__name__r   Ú
traffic_id)Úselfr>   r   r   r   Ú__init__Ä   s    zPlaylistXMLGenerator.__init__c              
   C   sÞ   |p| j }|s|  d¡S zb|  |¡}|  |¡}|jj|t| d¡ƒdd | j 	d|j
› ¡ dd|jrp|jjnd|dœW S  tk
rØ } z@| j d	t|d
dƒ› dt|ƒ› ¡ |  dt|ƒ› ¡ W Y ¢S d}~X Y nX dS )a1	  
            Generate comprehensive XML schedule content for broadcast automation systems.
            
            This method orchestrates the complete XML generation workflow including structure
            creation, content population, file system storage, and validation. It produces
            SCTE-118-3 compliant XML documents suitable for broadcast automation systems
            and advertisement management platforms.
            
            The generation process handles the complete playlist hierarchy transformation:
                1. Playlist metadata and scheduling parameters
                2. Time window definitions with precise timing
                3. Advertisement availability slots within windows
                4. Individual advertisement records with traffic management
            
            The method provides comprehensive error handling and detailed logging to support
            production deployment and troubleshooting workflows.
            
            Args:
                playlist (Playlists, optional): Playlist model instance to process
                                            Uses bound instance if not provided
                                            Must contain complete hierarchy relationships
            
            Returns:
                dict: Comprehensive generation result containing:
                    - status (bool): Success/failure indicator
                    - message (str): Descriptive result message
                    - file (str): Full file system path to generated XML
                    - filename (str): Generated filename for the XML document
                    - xml_content (str): Complete XML content for immediate use
                    
            Raises:
                AttributeError: If playlist lacks required model relationships
                FileSystemError: If XML file cannot be saved to storage
                ValidationError: If generated XML fails schema validation
                DatabaseError: If playlist data cannot be retrieved
                
            Example Usage:
                result = generator.generate_schedule(my_playlist)
                if result['status']:
                    deploy_to_broadcast_system(result['file'])
                else:
                    handle_generation_error(result['message'])
        zNo playlist providedzutf-8T)Úsavez1Successfully generated XML schedule for playlist z#XML schedule generated successfullyN©ÚstatusÚmessageÚfiler;   z-Failed to generate XML schedule for playlist ÚidÚunknownú: zException: )r>   Ú_error_responseÚ_create_playlist_xmlÚ_generate_xml_filenameÚxml_filerF   r   Úencoder   ÚinforK   Úpathr   r   ÚgetattrÚstr)rD   r>   Ztarget_playlistÚxml_contentr;   r   r   r   r   Úgenerate_scheduleí   s(    2



ýü$z&PlaylistXMLGenerator.generate_schedulec              	   C   sˆ   |j r|j jnd}d dd„ |D ƒ¡ ¡ }|jj}|jj}|jrL|j d¡nd}t	|j
ƒ}|jrddnd}|› d|› d|› d|› |› d		S )
a  
            Generate descriptive filename for XML schedule files based on playlist metadata.
            
            Creates standardized filenames that include essential playlist identification
            information for file management, organization, and automated processing systems.
            The filename format supports sorting, filtering, and identification of specific
            playlist versions and configurations.
            
            Args:
                playlist (Playlists): Playlist model instance containing metadata
                                    Must have channel, zone, and date relationships
            
            Returns:
                str: Generated filename in format: YYYYMMDD-zone-network-version[_draft].sch
                    Examples: "20250730-EST-NBC-1.sch", "20250731-PST-CBS-2_draft.sch"
                    
            Filename Components:
                - Date: YYYYMMDD format for chronological sorting
                - Zone: Geographic or programming zone identifier
                - Network: Broadcast network identifier
                - Version: Playlist version number for change tracking
                - Draft suffix: Added for draft playlists to prevent confusion
                - Extension: .sch for schedule file identification
        rL   r(   c                 s   s"   | ]}|  ¡ s|d kr|V  qdS r)   r,   r.   r   r   r   r1   ƒ  s       z>PlaylistXMLGenerator._generate_xml_filename.<locals>.<genexpr>ú%Y%m%dZnodateZ_draftr*   z.sch)r5   r6   r9   r
   Úid_zone_channelÚzonenameÚnetworknamer3   r4   rV   ÚversionÚis_draft)rD   r>   r6   Ú	zone_nameÚnetwork_nameZdate_strZversion_strZ	draft_strr   r   r   rP   `  s    
z+PlaylistXMLGenerator._generate_xml_filenamec                 C   sÞ   d| _ |  |j¡}t d¡}| dt|ƒ¡ | dt|ƒ› d¡ | dt|ƒ› d¡ | dt|jjƒ¡ | d	t|jj	ƒ¡ | d
t|j
ƒ¡ | dd¡ | dd¡ | dd¡ |  ||¡ tj|dd}|  |¡}|S )a±  
            Create comprehensive XML document structure conforming to SCTE-118-3 broadcast standards.
            
            This method orchestrates the complete transformation of playlist database records
            into industry-standard XML format suitable for broadcast automation systems.
            It handles the hierarchical structure creation, attribute population, and
            formatting to ensure compliance with broadcast industry standards.
            
            The XML structure includes:
                - Root Schedule element with broadcast metadata
                - Window elements representing time slots
                - Avail elements for advertisement opportunities
                - Ad elements with traffic management information
            
            Args:
                playlist (Playlists): Complete playlist model instance with relationships
                                    Must include windows, avails, and ads hierarchy
            
            Returns:
                str: Formatted XML document string ready for broadcast system consumption
                    Includes proper indentation and encoding for human readability
                    
            XML Schema Compliance:
                - SCTE-118-3 standard for broadcast scheduling
                - ISO 8601 date/time formatting
                - Proper namespace declarations
                - Required attribute specifications
        r   ZScheduleÚbroadcastDateZbegDateTimezT00:01:00+00:00ZendDateTimezT23:59:59+00:00ÚnetworkNameÚzoneNameÚrevisionÚlevelÚ0Zxmlnsz&http://www.scte.org/schemas/118-3/201XZschemaVersionz http://www.w3.org/2001/XMLSchemaÚunicode)Úencoding)rC   Ú_format_broadcast_dater3   ÚxmlZElementÚsetrV   r7   r\   r[   r]   Ú_add_windowsÚETÚtostringÚ_format_xml)rD   r>   r3   ÚrootÚ
xml_stringZformatted_xmlr   r   r   rO   ¨  s     #

z)PlaylistXMLGenerator._create_playlist_xmlc                 C   sd   |j  ¡  d¡}|D ]J}t |d¡}| dt|jƒ dd¡› d¡ | d|j	¡ |  
||¡ qdS )	a  
            Add window elements and their nested content to the XML structure.
            
            This method processes all time windows associated with the playlist and creates
            corresponding XML elements with proper timing attributes and nested content.
            Windows represent discrete time periods within the broadcast schedule where
            advertisements can be scheduled.
            
            Args:
                windows_element (xml.Element): Parent XML element to contain window elements
                                            Typically the root Schedule element
                playlist (Playlists): Playlist instance containing window relationships
                                    Must have accessible windows queryset
            
            Processing Flow:
                1. Query all windows ordered by start time
                2. Create XML element for each window
                3. Set timing attributes (start time, duration)
                4. Add nested avails for each window
        Úwindow_startÚWindowZwindowStartú ÚTú+00:00ZwindowDurationN)ÚwindowsÚallÚorder_byrm   Ú
SubElementrk   rV   rr   ÚreplaceÚwindow_durationÚ_add_avails)rD   Zwindows_elementr>   rw   ÚwindowZwindow_elementr   r   r   rl   û  s     z!PlaylistXMLGenerator._add_windowsc                 C   st   |j  ¡  d¡}|D ]Z}t |d¡}| dd¡ | dt|jƒ¡ | dt|jƒ 	dd¡› d	¡ |  
||¡ qd
S )a)  
            Add advertisement availability elements and their nested advertisements to XML.
            
            This method processes all avails (advertisement slots) within a window and creates
            corresponding XML elements with proper positioning and timing attributes.
            Avails represent specific opportunities for advertisement placement within
            broadcast windows.
            
            Args:
                avails_element (xml.Element): Parent window element to contain avail elements
                                            Receives avail children for hierarchical structure
                window (Windows): Window instance containing avail relationships
                                Must have accessible avails queryset
            
            Processing Flow:
                1. Query all avails ordered by position within window
                2. Create XML element for each avail
                3. Set positioning and timing attributes
                4. Add nested advertisements for each avail
        ÚavailinwindowÚAvailZavailNumrf   ÚavailInWindowZ
availStartrt   ru   rv   N)Úavailsrx   ry   rm   rz   rk   rV   r   Úavail_startr{   Ú_add_ads)rD   Zavails_elementr~   r‚   ÚavailÚavail_elementr   r   r   r}   4  s     z PlaylistXMLGenerator._add_availsc                 C   sÖ   |j  ¡  d¡}|D ]¼}|  jd7  _t |d¡}| d|jj› d¡ | dd¡ | dt	 
d	t	 t|jjƒ¡¡¡ | d
t|jƒ¡ | dd¡ | d|jjjj¡ | d|j| jkrÄt|jƒnt| jƒ¡ qd S )NÚpositioninavailé   ZSpotZadIdÚsecZ	eventTypeZLOIÚlengthz%H%M%S00ÚpositionInAvailZschedSourceÚLocalÚspotIdÚ	trafficId)Úadspots_in_availrx   ry   rC   rm   rz   rk   ÚadspotÚdurationr   r4   Úgmtimer    rV   r‡   Úoriginal_filerJ   ÚnameÚ	trafficid)rD   r†   r…   Zad_placementsZadplacementZ
ad_elementr   r   r   r„   p  s    "zPlaylistXMLGenerator._add_adsc                 C   s@   t |tƒr tt |d¡ d¡ƒS t|dƒr4| d¡S t|ƒS dS )a„  
            Format broadcast date to standardized YYYYMMDD string for XML attributes.
            
            This method handles multiple input date formats and converts them to the
            standardized 8-digit date format required by broadcast systems and XML schemas.
            It provides robust date handling for various input types including strings,
            datetime objects, and other date representations.
            
            Args:
                broadcast_date (str|datetime|object): Broadcast date in various formats
                                                    Supports string dates, datetime objects,
                                                    and other date-like objects
            
            Returns:
                str: Formatted date string in YYYYMMDD format
                    Examples: "20250730", "20251215", "20240101"
                    
            Supported Input Formats:
                - String dates in YYYY-MM-DD format
                - Python datetime objects
                - Other objects with strftime method
                - Fallback string conversion for unknown types
        r%   rY   r4   N)Ú
isinstancerV   r   r	   r4   Úhasattr)rD   r3   r   r   r   ri   €  s
    


	z+PlaylistXMLGenerator._format_broadcast_datec              
   C   s~   z8t  |¡}|jddd}dd„ | d¡D ƒ}d |¡W S  tk
rx } z"| j dt|ƒ› ¡ | W Y ¢S d}~X Y nX dS )a0  
            Format XML string with proper indentation and cleanup for human readability.
            
            This method transforms raw XML strings into properly formatted documents
            with consistent indentation, line breaks, and whitespace management.
            It enhances readability for debugging, validation, and manual review
            while maintaining XML validity and compliance.
            
            Args:
                xml_string (str): Raw XML string without formatting
                                Generated from ElementTree or similar XML creation tools
            
            Returns:
                str: Formatted XML string with proper indentation and structure
                    Includes consistent spacing and line breaks for readability
                    
            Formatting Features:
                - Two-space indentation for nested elements
                - Removal of empty lines for clean output
                - Proper line breaks between elements
                - UTF-8 encoding compatibility
        z  N)Úindentrh   c                 S   s   g | ]}|  ¡ r|‘qS r   )r
   )r/   Úliner   r   r   Ú
<listcomp>Ü  s      z4PlaylistXMLGenerator._format_xml.<locals>.<listcomp>Ú
zFailed to format XML: )	r   ZparseStringZtoprettyxmlr   r9   r   r   r   rV   )rD   rq   ÚdomÚ	formattedÚlinesr   r   r   r   ro   ³  s    
z PlaylistXMLGenerator._format_xmlc                 C   s   ddt |ƒ› dddœS )aÂ  
            Create standardized error response structure for consistent error handling.
            
            This method generates uniform error response dictionaries that match the
            success response format, enabling consistent error handling across all
            XML generation operations. It provides structured error information
            suitable for logging, user feedback, and automated error processing.
            
            Args:
                message (str): Descriptive error message explaining the failure
                            Should provide sufficient context for debugging
            
            Returns:
                dict: Standardized error response containing:
                    - status (bool): False to indicate failure
                    - message (str): Formatted error message with context
                    - file (None): No file path for failed operations
                    - filename (None): No filename for failed operations 
                    
            Error Response Structure:
                Matches success response format for consistent handling
                Enables uniform error processing across different failure scenarios
        Fz!Failed to generate XML schedule: NrG   )rV   )rD   rI   r   r   r   rN   í  s
    üz$PlaylistXMLGenerator._error_responsec              
   C   s´   z,ddl m} |j dd¡j| d}t|ƒW S  |jk
rX   dd| › dd	d	d
œ Y S  tk
r® } z:t 	d| › dt
|ƒ› ¡ ddt
|ƒ› d	d	d
œ W Y ¢S d	}~X Y nX d	S )a¶  
            Regenerate XML for an existing playlist using static method interface.
            
            This static method provides a convenient interface for regenerating XML
            schedules for existing playlists without requiring generator instantiation.
            It handles playlist retrieval, generator creation, and XML generation
            with comprehensive error handling for production deployment scenarios.
            
            Args:
                playlist_id (int): Database ID of the playlist to regenerate
                                Must correspond to existing Playlists record
            
            Returns:
                dict: Generation result from generateSchedule method
                    Contains status, message, file path, and XML content
                    
            Use Cases:
                - Batch XML regeneration for schedule updates
                - API endpoints for on-demand XML generation
                - Maintenance scripts for system updates
                - Error recovery for failed initial generation
                
            Note: Method references 'generateSchedule' function that should be 'generate_schedule'
        r   ©Ú	Playlistsr5   r7   ©rK   FúPlaylist with ID ú
 not foundNrG   ú&Failed to regenerate XML for playlist rM   úFailed to regenerate XML: ©Zapps.playlists.modelsr    ÚobjectsÚselect_relatedÚgetZgenerateScheduleÚDoesNotExistr   r   r   rV   ©Úplaylist_idr    r>   r   r   r   r   Úregenerate_playlist_xml  s"    

ü
üz,PlaylistXMLGenerator.regenerate_playlist_xmlc              
   C   s´   z,ddl m} |j dd¡j| d}t|ƒW S  |jk
rX   dd| › dd	d	d
œ Y S  tk
r® } z:t 	d| › dt
|ƒ› ¡ ddt
|ƒ› d	d	d
œ W Y ¢S d	}~X Y nX d	S )zã
        Regenerate XML for an existing playlist.
        
        Args:
            playlist_id: ID of the playlist to regenerate
            
        Returns:
            dict: Result dictionary from generateSchedule
        r   rŸ   r5   r7   r¡   Fr¢   r£   NrG   r¤   rM   r¥   r¦   r«   r   r   r   r­   W  s"    


ü
üc              
   C   sX   zt  | ¡ dddœW S  t jk
rR } zddt|ƒ› dœ W Y ¢S d}~X Y nX dS )zº
        Validate the generated XML content.
        
        Args:
            xml_content: XML content string
            
        Returns:
            dict: Validation result
        TzXML is valid)ÚvalidrI   FzInvalid XML: N)rm   Ú
fromstringZ
ParseErrorrV   )rW   r   r   r   r   Úvalidate_playlist_xmlw  s
    

z*PlaylistXMLGenerator.validate_playlist_xmlc              
   C   s¨   z\| j  ¡ }tdd„ | j  ¡ D ƒƒ}tdd„ | j  ¡ D ƒƒ}| j| j| j|||| j| jdœW S  t	k
r¢ } z(t
 d| j› dt|ƒ› ¡ i  W Y ¢S d}~X Y nX dS )zÇ
        Get a summary of the playlist XML structure.
        
        Args:
            playlist: Playlist model instance
            
        Returns:
            dict: Summary information
        c                 s   s   | ]}|j  ¡ V  qd S ©N)r‚   Úcount)r/   r~   r   r   r   r1   “  s     z@PlaylistXMLGenerator.get_playlist_xml_summary.<locals>.<genexpr>c                 s   s(   | ] }|j  ¡ D ]}|j ¡ V  qqd S r±   )r‚   rx   Úadspotsr²   )r/   r~   r…   r   r   r   r1   ”  s    þ)r¬   r]   r^   Úwindows_countÚavails_countÚ	ads_countr3   Úduration_minutesz#Failed to get playlist summary for rM   N)rw   r²   Úsumrx   rK   r]   r^   r3   r·   r   r   r   rV   )r>   r´   rµ   r¶   r   r   r   r   Úget_playlist_xml_summary‡  s$    

þøz-PlaylistXMLGenerator.get_playlist_xml_summary)N)N)rB   Ú
__module__Ú__qualname__Ú__doc__rE   rX   rP   rO   rl   r}   r„   ri   ro   rN   Ústaticmethodr­   r°   r¹   r   r   r   r   r=   ˜   s    +
)
sHS9<3:$
E r=   )Úosr   r?   Zxml.domr   Zxml.etree.ElementTreeZetreeZElementTreerm   r   r   Údjango.confr   Údjango.utilsr   Údjango.core.files.baser   r@   rB   r   r   r$   r'   r<   r=   r   r   r   r   Ú<module>   s   
%%'