U
    ^¨jOf  ã                   @   sD  d dl Z e j d d¡ d dlmZ d dlmZmZ d dlmZ d dl	Z	d dl
mZ d dlmZmZmZmZmZ d dl
mZmZ d d	lmZ d d	lmZ d dlZd d
lmZ d dlZe d¡ d dlmZ d dlm Z! G dd„ dƒZ"e"ƒ Z#dd„ Z$d(ddœdd„Z%d)dd„Z&d*dd„Z'd+dd„Z(dd„ Z)d,d"d#„Z*d$d%„ Z+d&d'„ Z,dS )-é    Nz./)Údefaultdict)ÚdatetimeÚ	timedelta)ÚPath)Úget_column_letter)ÚBorderÚSideÚPatternFillÚFontÚ	Alignment)r   Úcolumn_index_from_string)ÚImage)ÚBytesIOÚAggc                   @   s,   e Zd Zdd„ Zdd„ Zdd„ Zdd„ Zd	S )
ÚSimpleLoggerc                 C   s   t d|› �ƒ d S )Nz[INFO] ©Úprint©ÚselfÚmsg© r   ú6/var/www/itgmanager/itgmanager/nanoox/reports_utils.pyÚinfo    s    zSimpleLogger.infoc                 C   s   t d|› �ƒ d S )Nz
[WARNING] r   r   r   r   r   Úwarning#   s    zSimpleLogger.warningc                 C   s   t d|› �ƒ d S )Nz[ERROR] r   r   r   r   r   Úerror&   s    zSimpleLogger.errorc                 C   s   t d|› �ƒ d S )Nz[DEBUG] r   r   r   r   r   Údebug)   s    zSimpleLogger.debugN)Ú__name__Ú
__module__Ú__qualname__r   r   r   r   r   r   r   r   r      s   r   c                  C   s   t  ¡ } | d }|S )zœ
    Retorna la ruta al escritorio del usuario independientemente del sistema operativo.
    Usa Path.home() y asume que la carpeta se llama 'Desktop'.
    ÚDesktop)r   Úhome)r    Údesktopr   r   r   Úget_escritorio_path1   s    	r"   Úsensores_timeseries)Úreturnc                 C   sn   t  d|›�¡ | | }| ¡ }dgdgdœ}| ¡ D ]2\}}||kr6|j||d� td|› d|› �ƒ q6d S )Nz4En 'asegurar_indices_sensores_timeseries' coll_name=)Úbomba_idé   )Ú	centro_idr&   )Z
bomba_id_1Zcentro_id_1)Únameu	   Ã�ndice 'z' creado sobre )Úloggerr   Úindex_informationÚitemsÚcreate_indexr   )ÚdbÚ	coll_nameÚts_colZexisting_indexesZdesired_indexesr(   Úspecr   r   r   Ú$asegurar_indices_sensores_timeseries?   s    þr1   Úmetadatac           
      C   s,  t ƒ  t d|›�¡ t d|›�¡ t d|›�¡ | | }t |d¡}|tdd� }d||dœi}t |¡ d	|id
|ddddœiddid	ddiiddddddddigigiddddddddddddddddœiddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/œid0œig}|j|d1d2�}	t ƒ  d3d4„ |	D ƒS )5u—   Obtiene todas las lecturas de un dÃ­a, agrupadas por alias de bomba,
    usando un aggregation pipeline para offload al servidor Mongo.
    
    Args:
        db: instancia de la base de datos.
        fecha_str: fecha en 'YYYY-MM-DD'.
        centro_id: opcional, filtra por centro.
    
    Returns:
        Dict donde la clave es el alias y el valor
        es la lista de documentos de timeseries.
    ú9En 'obtener_datos_por_fecha_por_alias' sensors_coll_name=ú:En 'obtener_datos_por_fecha_por_alias' metadata_coll_name=z
fecha_str=ú%Y-%m-%dr&   ©ÚdaysÚ	timestamp©z$gtez$ltz$matchz$lookupr%   Ú_idÚmeta)ÚfromZ
localFieldZforeignFieldÚasz$unwindz$metaz	meta.tipoÚbombaz$projectr   z$ifNullz$meta.aliasz$concatÚbomba_z	$toStringz	$bomba_id)r:   Úaliasr8   ÚO2ÚSO2ÚTEMPÚSetPointÚSetPointOFFÚRLYÚInStartÚInSelÚControlÚPresionÚIoÚVoÚalarmsÚStatusz$groupz$aliasz$pushz
$timestampz$O2z$SO2z$SENSOR_SO2z$TEMPz$RLYz$InStartz$InSelz$Controlz$Presionz$Ioz$Voz	$SetPointz$SetPointOFFz$alarmsz$Status)r8   rA   rB   Z
SENSOR_SO2rC   rF   rG   rH   rI   rJ   rK   rL   rD   rE   rM   rN   ©r:   ZlecturasT)ÚallowDiskUsec                 S   s   i | ]}|d  |d “qS rO   r   )Ú.0Údocr   r   r   Ú
<dictcomp>å   s      z5obtener_datos_por_fecha_por_alias.<locals>.<dictcomp>)r   r)   r   r   Ústrptimer   Ú	aggregate)
r-   Ú	fecha_strÚsensors_coll_nameÚmetadata_coll_nameÚsensores_ts_colÚfechaÚsiguiente_diaZmatch_tsÚpipelineÚcursorr   r   r   Ú!obtener_datos_por_fecha_por_alias[   sˆ     ÿ
3ü
þÿ      ï ðþâ6r^   c                 C   s(  t ƒ  t d|›�¡ t d|›�¡ | | }| | }t d|›�¡ t |d¡}|tdd� }ddi}i }	| |¡D ]"}
|
 d	d
|
d › �¡|	|
d < qvdt|	 	¡ ƒi||dœdœ}dddddddddddœ
}t
tƒ}| ||¡D ]4}
|	 |
d t|
d ƒ¡}|
 d¡ ||  |
¡ qät ƒ  t|ƒS )Nr3   r4   zmetadata_col=r5   r&   r6   Útipor>   r@   r?   r:   z$inr9   )r%   r8   r   )
r:   r%   r8   rA   rB   rC   rF   rG   rI   rJ   r%   )r   r)   r   r   rT   r   ÚfindÚgetÚlistÚkeysr   ÚstrÚpopÚappendÚdict)r-   rV   rW   rX   Úmetadata_colrY   rZ   r[   Zfiltro_metadataZ	alias_maprR   Z	filtro_tsZcamposÚ
resultadosr@   r   r   r   Ú"_obtener_datos_por_fecha_por_aliasè   sB     þ
ö
rj   Úhistorial_controlc           	   
   C   sˆ   zD| d }|  i ¡}i }|D ]"}| d¡}| dg ¡}|||< q|W S  tk
r‚ } z t d|› d|jj› �¡ ‚ W 5 d}~X Y nX dS )u%  
    Obtiene todos los logs de la colecciÃ³n 'historial_control' y los organiza en un diccionario.
    Las llaves del diccionario son las fechas (en formato 'YYYY-MM-DD') y los valores son listas de logs.

    :return: Diccionario con las fechas como llaves y listas de logs como valores.
    rk   ÚdateÚlogsz6Error al obtener el historial de 'historial_control': Ú N)r`   ra   Ú	Exceptionr)   r   Ú__traceback__Ú	tb_lineno)	r-   r.   Ú
collectionÚ	documentsÚhistorial_dictrR   rl   rm   Úer   r   r   Úget_historial_control_as_dict(  s    


rv   c               
   C   sè   zšt ddd�} tdddd�}d}d}d	}d
}d}td||d�}td||d�}td||d�}	td||d�}
ttddd�tddd�tddd�tddd�d�}W n: tk
rÔ } ztd|jj› d|› �ƒ‚W 5 d }~X Y nX | ||||	||
fS )NTÚFFFFFF)ÚbÚcolorÚsolidÚe84e0e)Ú	fill_typeÚstart_colorÚ	end_colorZ92CDDCZ92DC97ZFFFF00ÚC8C8C8ZEE6b6EÚthinÚ000000)Úborder_stylery   )ÚleftÚrightÚtopÚbottomzError obteniendo estilos (ú): )r
   r	   r   r   ro   rp   rq   )ÚfontÚfillZcelesteZverdeZamarilloZgrisZrojoÚfill_inyÚfill_iny_manÚfill_vdfÚ
fill_alarmÚborderru   r   r   r   Ú
get_stylesF  sF    þþþþþ


ý
*r�   ÚCé   é   é   c              
   C   s   z¼t |ƒ}t|ƒD ]œ}|d dkr$q|||  }|dkrNt d|› d�¡  q°|dk rjt d|› d�¡ qt|ƒ}	|	› |› �}
t|ƒ}d|_d	|_|  	||
¡ t 
d
|
› �¡ qt d¡ W n> tk
rú } z t d|jj› d|› d�¡ W 5 d}~X Y nX dS )uÙ  
    Inserta repetidamente la imagen en la hoja, avanzando horizontalmente
    columnas que pueden exceder la 'Z' (soporta AA, AB, etc.).
    
    :param worksheet: Hoja de cÃ¡lculo (openpyxl worksheet)
    :param img_path: Ruta al archivo de imagen
    :param start_column: Columna inicial (string), p.ej "C"
    :param start_row: Fila inicial (int)
    :param repeats: CuÃ¡ntas veces quieres repetir la imagen
    :param step: CuÃ¡ntas columnas saltar cada vez (int)
    é   r&   i @  zLa columna calculada (u/   ) excede el lÃ­mite de Excel (XFD). Deteniendo.u   Ã�ndice de columna no vÃ¡lido (z). Se ignora.iX  iÂ  zImagen insertada en uG   Marca de agua agregada (con expansiÃ³n de columnas) satisfactoriamente.z!Error insertando marcas de agua (r‡   Ú.N)r   Úranger)   r   r   r   ÚExcelImgÚwidthÚheightÚ	add_imager   r   ro   rp   rq   )Ú	worksheetÚimg_pathÚstart_columnÚ	start_rowÚrepeatsÚstepÚstart_col_numÚiÚ	col_indexÚnew_col_strÚnew_positionÚimg_copyru   r   r   r   Úadd_markwater_imagest  s,     r§   c           (         s\  �zt j dddddddœ¡ t|ƒD �]ì\}‰ �z¢t |ˆ  d ¡}|ˆ  d }|ˆ  d }	t|ƒdks‚t|ƒdks‚t|	ƒdkr–t ˆ › d	�¡ W q&‡ ‡fd
d„|ˆ  D ƒ}
|ˆ  }d|
rÀdnd |rÌdnd }d}d}d\}}t j	||fdd�}d\}}}|| }|| }| 
||||g¡}|j||dddd� | t|ƒt|ƒ¡ | dd¡ |jddd� |jdddd� |jddd� | ¡ \}}|
�ròt |
¡}t|ƒdk�rÀt t t |¡¡¡nd}|j||gt|ƒ ||dddd � | ||¡ |�rXt |¡}t|ƒdk�r&t t t |¡¡¡nd}|j||gt|ƒ ||d!dd"d � | ||¡ | ¡ }|j||	d#d$d%dd&� | t|ƒt|ƒ¡ | dt|	ƒd' ¡ |jd#d$dd� |jdd$d� |j tjd(d)�¡ |j t d*¡¡ | ¡  |jd+ˆ › �dd� |  d,¡ |j!|d-� | "¡ D ]}| #d.¡ | $d/¡ �q| %¡ \}}| %¡ \} }!||  }"||! }#|j&|"|#|d0d1|j'd2� t(ƒ }$|j)|$d3dd4� t  *|¡ |$ +d¡ t,|$ƒ}%d5\|%_-|%_.|ˆ  d6 d7 }&|  /|%|&¡ W q& t0k
�r }' zt 1d8|'j2j3› d9|'› �¡ W 5 d }'~'X Y q&X q&W n> t0k
�rV }' zt 1d:|'j2j3› d;|'› �¡ W 5 d }'~'X Y nX d S )<Né   é   é   )z	font.sizezaxes.titlesizezxtick.labelsizezytick.labelsizezlegend.fontsizezfigure.titlesizeÚtsrA   rB   r   z sin datos para graficar.c                    s   g | ]}|ˆˆ  kr|‘qS r   r   )rQ   r«   ©Zchannel_dataÚrangos_bomba_on_tsr   r   Ú
<listcomp>Å  s   ÿz)insert_matplot_graphs.<locals>.<listcomp>r”   r&   g333333Ó?)é   g333333@éd   )ÚfigsizeÚdpi)gš™™™™™¹?çffffffî?r³   zNivel de O2 (mg/L)z#1e4882)Úlabelry   Ú	linewidthé   u   Hora del dÃ­aé   )Úfontsize)ry   r¸   Úy)ÚaxisÚ
labelcolorglÁlÁF?z#92CDDCu   InyecciÃ³n O2 - AutomÃ¡tica)r˜   r†   ry   Úalphar´   z#92DC97u   InyecciÃ³n O2 Manualu   SaturaciÃ³n %z#ab0202z--)r´   ry   Ú	linestylerµ   é
   é<   )Úintervalz%H:%MzSensor T)r†   é-   r„   zupper center)g      à?gš™™™™™É¿)ÚncolÚlocÚbbox_to_anchorÚbbox_transformÚpng)Úformatr²   )ià  i$  ÚL_GraphÚ2z!Error generando reporte en linea rn   u   Error insertando grÃ¡ficos (r‡   )4ÚpltÚrcParamsÚupdateÚ	enumerateÚmdatesÚdate2numÚlenr)   r   ÚfigureÚadd_axesÚplotÚset_xlimÚminÚmaxÚset_ylimÚ
set_xlabelÚ
set_ylabelÚtick_paramsÚget_ylimÚnpÚdiffÚsortÚbarÚtwinxÚxaxisÚset_major_locatorÚMinuteLocatorÚset_major_formatterÚDateFormatterÚautofmt_xdateÚ	set_titleÚgridÚsubplots_adjustÚget_xticklabelsÚset_rotationÚset_haÚget_legend_handles_labelsÚlegendÚ	transAxesr   ÚsavefigÚcloseÚseekr—   r˜   r™   rš   ro   r   rp   rq   )(r›   Úvalues_for_chartsÚrangos_iny_on_tsr­   Úrangos_iny_on_manual_tsÚRangosÚidxÚxÚo2Úso2Úts_inyectingÚts_iny_manualÚtotal_graphsrÂ   Úbottom_marginZ	ancho_figZalto_figÚfigrƒ   r„   r…   r˜   r™   Úax1Úy_minÚy_maxÚx_injÚdxÚax2ÚlblÚlines_1Úlabels_1Úlines_2Úlabels_2ÚhandlesÚlabelsÚimg_dataÚimgZceldaru   r   r¬   r   Úinsert_matplot_graphs¨  s   ú	$ÿ
ÿ
þ
  ý þ

ÿþù	

ÿþù	  ü þ
ÿÿ

 û	

ÿÿr  c           .      C   sÖ  �z�t |ƒD �]r\}}t|| | d ƒ}t|| | d ƒ}t|| | d ƒ}t|| | d ƒ}t|| | d ƒ}t|| | d ƒ}t||||||ƒ | |t|d ƒ  }||_||_| |t|d ƒ  }| |t|d ƒ  }| |t|d ƒ  }| |t|d ƒ  }| |t|d ƒ  }| |t|d ƒ  } ||_||_||_||_||_|| _||_||_||_||_||_|| _qtt|ƒƒD ]8}!| j|d |!| | d |d |!| | | d� �qŽ|D �]}| || d || d	 … }"t |"ƒD ]Ú\}#}$t |$ƒD ]r\}%}&||&_	|$d
 j
|| k}'|$d
 j
|	| k�o<|'}(|$d
 j
|
| k})|(�r^||&_n|'�rj||&_|)�r||&_�q|$d j
}*t|$d j
› d|#› d|%› d|d › d�ƒ |*�röd|*k�rö|#dk�rö||&_�qö�qÌ| jd|| d d�D ]$}$|$D ]}&tddddd�|&_�qô�qì| jD ]v}!d
}+|!D ]B}&z.|&j
d k	�rTtt|&j
ƒƒ|+k�rTt|&j
ƒ}+W n   Y nX �q$|+d },|,dk�r|,| j|!d
 j _�qW n> tk
�rÐ }- zt d|-jj› d|-› �¡ W 5 d }-~-X Y nX d S )Nr&   r”   é   r’   é   é   )rž   r�   Úend_rowÚ
end_columnÚceldaInicialÚ
celdaFinalr   éÿÿÿÿz row: z col: z
  offset: rn   ÚA)Úmin_rowÚmax_rowÚcenterTF)Ú
horizontalÚverticalÚshrink_to_fitÚ	wrap_textz"Error aplicando estilos a celdas (r‡   )rÍ   r   r   rd   rˆ   r‰   r–   rÐ   Úmerge_cellsrŽ   ÚvalueÚ	iter_rowsr   Ú	alignmentÚcolumnsÚcolumn_dimensionsÚcolumn_letterr˜   ro   r)   r   rp   rq   ).r›   Ú
bomb_namesrö   Úcant_keys_tablaÚtablas_distÚh_offsetÚv_offsetÚ
max_columnÚrangos_bomba_onÚrangos_iny_onÚrangos_iny_on_manualrŽ   rˆ   r‰   rŠ   rŒ   r‹   r�   r÷   ÚchannelÚLetra1ÚLetra2ÚLetra3ZLetra4ZLetra5ZLetra6Ú
cell_mergeÚcell_1Úcell_2Úcell_3Zcell_4Zcell_5Zcell_6ÚcolumnÚ
cell_ranger¢   ÚrowÚjÚcellÚbomb_activeZactive_inyectionZ
iny_manualZalarm_cell_valueÚ
max_lengthÚadjusted_widthru   r   r   r   Úapply_cell_stylesT  s¢    ú	
ý



*ý
 

r@  )r#   )r#   r2   )r#   r2   )rk   )r�   r‘   r’   r“   )-ÚsysÚpathÚinsertÚcollectionsr   r   r   Úpathlibr   ÚopenpyxlÚopenpyxl.utilsr   Úopenpyxl.stylesr   r   r	   r
   r   r   Úopenpyxl.drawing.imager   r—   ÚnumpyrÜ   Úior   Ú
matplotlibÚuseÚmatplotlib.pyplotÚpyplotrÊ   Úmatplotlib.datesÚdatesrÎ   r   r)   r"   r1   r^   rj   rv   r�   r§   r  r@  r   r   r   r   Ú<module>   s:   

 
@
.
4 -