import { Navigation , NavigationIndicator } from '@/services/data/tuples/navigation-types' ; import { useEffect , useState } from 'react' ; import { useNavigationEditEventBus } from './navigation-edit-event-bus' ; import { NavigationEditEventTypes } from './navigation-edit-event-bus-types' ; import { AllCalculatedIndicatorValues , AllCalculatedIndicatorValuesData , AllIndicatedValuesCalculationResult , CalculatedIndicatorValues , NavigationIndicatorCalculatedValues } from './types' ; const needApplyComputed = ( computed , current ) => { if ( ! current . calculated ) { return true ; } const { failed , failureReason , shouldComputeScore , score } = computed ; return current . failed != failed || current . failureReason != failureReason || current . shouldComputeScore != shouldComputeScore || current . score ?. value != score ?. value ; } ; /**
 * for handle changes of indicators values,
 * 1. root node
 * 2. compute indicator
 */ export const useIndicatorValuesAggregator = ( options ) => { const { navigation , shouldAvoidIndicatorRemovedAndValuesCalculated , shouldAvoidFormulaChanged , shouldAvoidScoreIncludeChanged , compute , onComputed } = options ; const { on , off , fire } = useNavigationEditEventBus ( ) ; const [ allValues ] = useState < AllCalculatedIndicatorValues > ( { data : [ ] , calculated : false , failed : false , shouldComputeScore : false } ) ; useEffect ( ( ) => { const defendNavigation = ( navigation , navigationIndicator , func ) => { if ( shouldAvoidIndicatorRemovedAndValuesCalculated ( navigation , navigationIndicator ) ) { return ; } func ( ) ; } ; const doCalculate = ( ) => { const computed = compute ( allValues . data ) ; if ( needApplyComputed ( computed , allValues ) ) { const { failed , failureReason , shouldComputeScore , score } = computed ; allValues . calculated = true ; allValues . failed = failed ; allValues . failureReason = failureReason ; allValues . shouldComputeScore = shouldComputeScore ; allValues . score = score ; onComputed ( { failed , failureReason , shouldComputeScore , score } ) ; } } ; const calculate = ( ) => { if ( allValues . data . length === 0 && ( navigation . indicators || [ ] ) . length > 1 ) { ( async ( ) => { allValues . data = await Promise . all ( ( navigation . indicators || [ ] ) . filter ( indicator => ! shouldAvoidIndicatorRemovedAndValuesCalculated ( navigation , indicator ) ) . map ( indicator => { return new Promise < NavigationIndicatorCalculatedValues > ( resolve => { fire ( NavigationEditEventTypes . ASK_CALCULATED_VALUES , navigation , indicator , ( values ) => { resolve ( { indicator , values } ) ; } ) ; } ) ; } ) ) ; doCalculate ( ) ; } ) ( ) ; } else { doCalculate ( ) ; } } ; const onIndicatorRemoved = ( aNavigation , navigationIndicator ) => { defendNavigation ( aNavigation , navigationIndicator , ( ) => { const index = allValues . data . findIndex ( ( { indicator } ) => indicator === navigationIndicator ) ; if ( index !== - 1 ) { allValues . data . splice ( index , 1 ) ; } calculate ( ) ; } ) ; } ; const onValuesCalculated = ( aNavigation , navigationIndicator , values ) => { defendNavigation ( aNavigation , navigationIndicator , ( ) => { const pair = allValues . data . find ( ( { indicator } ) => indicator === navigationIndicator ) ; if ( pair == null ) { allValues . data . push ( { indicator : navigationIndicator , values } ) ; } else { pair . values = values ; } calculate ( ) ; } ) ; } ; const onFormulaChanged = ( aNavigation , aNavigationIndicator ) => { if ( shouldAvoidFormulaChanged ( aNavigation , aNavigationIndicator ) ) { return ; } calculate ( ) ; } ; const onScoreIncludeChanged = ( aNavigation , aNavigationIndicator ) => { if ( shouldAvoidScoreIncludeChanged ( aNavigation , aNavigationIndicator ) ) { return ; } calculate ( ) ; } ; on ( NavigationEditEventTypes . INDICATOR_REMOVED , onIndicatorRemoved ) ; on ( NavigationEditEventTypes . VALUES_CALCULATED , onValuesCalculated ) ; on ( NavigationEditEventTypes . INDICATOR_FORMULA_CHANGED , onFormulaChanged ) ; on ( NavigationEditEventTypes . INDICATOR_SCORE_INCLUDE_CHANGED , onScoreIncludeChanged ) ; return ( ) => { off ( NavigationEditEventTypes . INDICATOR_REMOVED , onIndicatorRemoved ) ; off ( NavigationEditEventTypes . VALUES_CALCULATED , onValuesCalculated ) ; off ( NavigationEditEventTypes . INDICATOR_FORMULA_CHANGED , onFormulaChanged ) ; off ( NavigationEditEventTypes . INDICATOR_SCORE_INCLUDE_CHANGED , onScoreIncludeChanged ) ; } ; } , [ on , off , fire , navigation , allValues , shouldAvoidIndicatorRemovedAndValuesCalculated , shouldAvoidFormulaChanged , shouldAvoidScoreIncludeChanged , compute , onComputed ] ) ; return allValues ; } ;