
    9g5i                        d Z ddlmZ ddlmZmZ ddlmZmZ ddl	m
Z
mZmZ e G d d             Ze G d d	             Zy
)zKPI tree data structure.    )annotations)	dataclassfield)AnyIterator)KPINodeConfigNodeTypeKPICategoryc                  N   e Zd ZU dZded<   ded<   ded<   dZded	<   d
Zded<   ej                  Z	ded<   d
Z
ded<   dZded<   dZded<    ee      Zded<    edd      Zded<   ed!d       Zed!d       Zed"d       Zed"d       Zed"d       Zed#d       Zd$dZd%d Zy)&KPINodezKPI tree node.stridnamer	   	node_typeNz
str | Noneformula unitr
   categorydescriptionfloat | Nonevaluetargetdefault_factorylist[KPINode]childrenF)defaultreprKPINode | Noneparentc                    | j                   | j                  y| j                  dk(  ry| j                   | j                  z  dz  S )z3Calculate achievement rate (actual / target * 100).Nr   d   r   r   selfs    a/var/www/tkim.planitai.co.jp/gemegg/20251207-make-pdf-report/project/planitai-kpi/src/kpi/tree.pyachievement_ratezKPINode.achievement_rate   sA     ::!4;;!zzDKK'#--    c                f    | j                   | j                  y| j                   | j                  z
  S )zCalculate gap from target.Nr#   r$   s    r&   gapzKPINode.gap(   s-     ::!4zzDKK''r(   c                    | j                   duS )z!Check if this node has a formula.N)r   r$   s    r&   is_calculatedzKPINode.is_calculated/   s     ||4''r(   c                2    t        | j                        dk(  S )z+Check if this is a leaf node (no children).r   )lenr   r$   s    r&   is_leafzKPINode.is_leaf4   s     4==!Q&&r(   c                    | j                   du S )z+Check if this is the root node (no parent).N)r    r$   s    r&   is_rootzKPINode.is_root9   s     {{d""r(   c                N    | j                   y| j                   j                  dz   S )zCalculate depth from root.r      )r    depthr$   s    r&   r4   zKPINode.depth>   s&     ;;{{  1$$r(   c                H    | |_         | j                  j                  |       y)zAdd a child node.N)r    r   append)r%   childs     r&   	add_childzKPINode.add_childE   s    U#r(   c                d   | j                   | j                  | j                  j                  | j                  | j
                  | j                  j                  | j                  | j                  | j                  | j                  | j                  D cg c]  }|j                          c}dS c c}w )zConvert to dictionary.)r   r   typer   r   r   r   r   r'   r*   r   )r   r   r   r   r   r   r   r   r'   r*   r   to_dict)r%   cs     r&   r;   zKPINode.to_dictJ   s     ''IINN((||II++ZZkk $ 5 588.2mm<<
 	
 =s   B-)returnr   )r=   bool)r=   int)r7   r   r=   Noner=   zdict[str, Any])__name__
__module____qualname____doc____annotations__r   r   r
   FINANCEr   r   r   r   r   listr   r    propertyr'   r*   r,   r/   r1   r4   r8   r;    r(   r&   r   r      s    G
IGZD#N'//Hk/K E<FL $D9Hm9"4e<FN<. . ( ( ( ( ' ' # # % %$

r(   r   c                      e Zd ZU dZded<    ee      Zded<   e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dddZddZy)KPITreezKPI tree structure.r   rootr   zdict[str, KPINode]nodesc           
        i }|D ]i  }t        |j                  |j                  |j                  |j                  |j
                  |j                  |j                        }|||j                  <   k |D ]X  }||j                     }|j                  D ]8  }||vrt        d| d|j                   d      ||   }|j                  |       : Z |j                         D cg c]"  }|j                  t        j                  k(  s!|$ }}|st        d      t        |      dkD  rt        d      |d   }	 | |	|	      S c c}w )
zBuild tree from configuration.

        Args:
            node_configs: List of node configurations.

        Returns:
            Constructed KPI tree.

        Raises:
            ValueError: If tree structure is invalid.
        )r   r   r   r   r   r   r   zChild node 'z' not found for ''zNo KGI node foundr3   zMultiple KGI nodes foundr   )rM   rN   )r   r   r   r:   r   r   r   r   r   
ValueErrorr8   valuesr   r	   KGIr.   )
clsnode_configsrN   cfgnodechild_idr7   n
root_nodesrM   s
             r&   from_configzKPITree.from_configb   s=    %' 
	!C66XX((XXOOD !E#&&M
	!   	&C=DLL &5($|H:=NsvvhVW%XYYhu%	&	& "'OA1;;(,,3NaO
O011z?Q788!}E** Ps    "D>D>c                z    |j                         D ](  \  }}|| j                  v s|| j                  |   _        * y)zmSet actual values for nodes.

        Args:
            values: Dictionary mapping node ID to value.
        N)itemsrN   r   )r%   rR   node_idr   s       r&   
set_valueszKPITree.set_values   s:     %lln 	2NGU$**$,1

7#)	2r(   c                z    |j                         D ](  \  }}|| j                  v s|| j                  |   _        * y)zoSet target values for nodes.

        Args:
            targets: Dictionary mapping node ID to target.
        N)r]   rN   r   )r%   targetsr^   r   s       r&   set_targetszKPITree.set_targets   s:      '}} 	4OGV$**$-3

7#*	4r(   c                8    | j                   j                  |      S )zGet node by ID.)rN   get)r%   r^   s     r&   get_nodezKPITree.get_node   s    zz~~g&&r(   c                v    | j                   j                         D cg c]  }|j                  s| c}S c c}w )z!Get all leaf nodes (INPUT nodes).)rN   rR   r/   r%   rY   s     r&   
get_leaveszKPITree.get_leaves   s)    ::,,.<a!))<<<   66c                v    | j                   j                         D cg c]  }|j                  s| c}S c c}w )zGet all nodes with formulas.)rN   rR   r,   rg   s     r&   get_calculated_nodeszKPITree.get_calculated_nodes   s)    ::,,.Ba!//BBBri   c              #     K   | j                   g}|r4|j                  d      }| |j                  |j                         |r3yyw)z%Iterate nodes in breadth-first order.r   N)rM   popextendr   )r%   queuerW   s      r&   iter_breadth_firstzKPITree.iter_breadth_first   s;     99Q<DJLL' s   AAAc              #     K   | j                   g}|r<|j                         }| |j                  t        |j                               |r;yyw)z#Iterate nodes in depth-first order.N)rM   rm   rn   reversedr   )r%   stackrW   s      r&   iter_depth_firstzKPITree.iter_depth_first   s>     99;DJLL$--01 s   A
AAc                6    | j                   j                         S )zConvert tree to dictionary.)rM   r;   r$   s    r&   r;   zKPITree.to_dict   s    yy  ""r(   c                d    g ddfd | j                          dj                        S )z$Convert tree to text representation.c                z   d|z  z  }| j                   | j                   dnd}| j                  r| j                  nd}j                  | d| j                   d| j                   d| d| 	       | j
                  r j                  | d| j
                          | j                  D ]  } ||d	z           y )
N z,.0f-r   z- z (z): z  Formula: r3   )r   r   r6   r   r   r   r   )	rW   r4   prefix	value_strunit_strr7   _renderindentliness	         r&   r}   z KPITree.to_text.<locals>._render   s    EFN+F04

0F4::d+CI$(IItyy2HLLF82dii[477)3yk8*UV||x{4<<.AB *uqy)*r(   
)r   )rW   r   r4   r?   r=   r@   )rM   join)r%   r~   r}   r   s    `@@r&   to_textzKPITree.to_text   s/    	* 	* 			yyr(   c           	        g }t               d	fd | j                         t        | j                  j                               z
  }|r|j	                  d|        | j                  j                         D ]g  }|j                  sddl}|j                  d|j                        }|D ]3  }|| j                  vs|j	                  d| d|j                   d       5 i |S )
zZValidate tree structure.

        Returns:
            List of validation errors.
        c                n    j                  | j                         | j                  D ]
  } |        y )N)addr   r   )rW   r7   visitvisiteds     r&   r   zKPITree.validate.<locals>.visit   s-    KK  er(   zOrphan nodes found: r   Nz	\{(\w+)\}zUnknown variable 'z' in formula for 'rP   )rW   r   r=   r@   )
setrM   rN   keysr6   rR   r   refindallr   )	r%   errorsorphansrW   r   refsrefr   r   s	          @@r&   validatezKPITree.validate   s      %	
 	diidjjoo'(72MM0	:; JJ%%' 	^D||zz,= ^C$**,(:3%?QRVRYRYQZZ[&\]^	^ r(   N)rU   zlist[KPINodeConfig]r=   rL   )rR   dict[str, float]r=   r@   )ra   r   r=   r@   )r^   r   r=   r   )r=   r   )r=   zIterator[KPINode]rA   )   )r~   r?   r=   r   )r=   z	list[str])rB   rC   rD   rE   rF   r   dictrN   classmethodr[   r_   rb   re   rh   rk   rp   rt   r;   r   r   rJ   r(   r&   rL   rL   [   s`    
M %d ;E;,+ ,+\24'=C(2# ( r(   rL   N)rE   
__future__r   dataclassesr   r   typingr   r   
src.configr   r	   r
   r   rL   rJ   r(   r&   <module>r      sP     " (   ; ; L
 L
 L
^ ] ] ]r(   