package goodcalc import ( "fmt" "math" ) // Matrix contains the stakeholders and the maximal // allowed points of the calculation. The calculation // is pretty simple. Inside each aspect ValuationPoints // can be defined. Over the maximal possible points // the balancePoints are calculated. // // It is possible to define different weights on different // layers (stakeholder, theme and aspect). // This type does not contain any businesslogic of the version // of the matrix. type Matrix struct { MaxPoints int `json:"max_points"` MaxValuationPoints int `json:"max_valuation_points"` // 10 MaxNegValuationPoints int `json:"max_neg_valuation_points"` // -200 NegPointsFactor int `json:"neg_points_factor"` // 50 Stakeholders []*Stakeholder `json:"stakeholders"` Calculation *MatrixCalc `json:"calculation"` } func (m *Matrix) String() string { if m == nil { return "" } var s string s += fmt.Sprintf("MaxPoints: %d\n", m.MaxPoints) s += fmt.Sprintf("MaxValuationPoints: %d\n", m.MaxValuationPoints) s += fmt.Sprintf("MaxNegValuationPoints: %d\n", m.MaxNegValuationPoints) s += fmt.Sprintf("NegPointsFactor: %d\n", m.NegPointsFactor) s += fmt.Sprintf("Calculation: %#v\n", m.Calculation) s += fmt.Sprintf("Stakeholders: {\n%s\n}\n", m.Stakeholders) return s } func (m *Matrix) BalancePoints() int { var balancePoints float64 m.calcWeightFactor() m.setMaxValuationPoints() m.forall(func(t *Theme) { t.Calc.calcMaxPoints() t.calcNrPosAspects() t.calcValPoints() t.calcEstPercentage() t.calcBalancePoints() balancePoints += float64(t.Calc.BalancePoints) balancePoints += float64(t.Calc.NegativeBlancePoints) }) balancePoints = math.Round(balancePoints) return int(balancePoints) } // MatrixCalc contains calculated values type MatrixCalc struct { SumCalcWeight float32 `json:"sum_calc_weight"` WeightFactor float32 `json:"weight_factor"` } // forall is a helper-method for iterating the themes func (m *Matrix) forall(f func(t *Theme)) { for _, s := range m.Stakeholders { for _, t := range s.Themes { f(t) } } } // sumCalcWeight sums all the calculated weights of // the matrix. func (m *Matrix) sumCalcWeight() { // calculate the stakeholder weight to each // theme for _, s := range m.Stakeholders { s.calcWeight() } m.Calculation.SumCalcWeight = 0 m.forall(func(t *Theme) { m.Calculation.SumCalcWeight += t.Calc.CalcWeight }) } func (m *Matrix) calcWeightFactor() { m.sumCalcWeight() m.Calculation.WeightFactor = 0 if m.Calculation.SumCalcWeight != 0 { m.Calculation.WeightFactor = float32(m.MaxPoints) / m.Calculation.SumCalcWeight } // set the weight-factor for all elements of the matrix // this redundancy enables the calculation on the theme // without reading from the matrix m.forall(func(t *Theme) { t.Calc.WeightFactor = m.Calculation.WeightFactor }) } // setMaxValuationPoints writes the config values of the matrix into the themes and // aspects func (m *Matrix) setMaxValuationPoints() { m.forall(func(t *Theme) { maxThemeValPoints := 0 for _, a := range t.Aspects { a.MaxValuationPoints = m.MaxValuationPoints * int(a.Weight) maxThemeValPoints += m.MaxValuationPoints * int(a.Weight) } t.Calc.MaxValuationPoints = maxThemeValPoints for _, na := range t.NegativeAspects { na.MaxValuationPoints = m.MaxNegValuationPoints } t.NegPointsFactor = m.NegPointsFactor }) }