// package elem_link -- связь между объектами package elem_link import ( "fmt" "gitp78su.ipnodns.ru/svi/kern/v3" "gitp78su.ipnodns.ru/svi/goarch/lev0/cons" "gitp78su.ipnodns.ru/svi/goarch/lev0/types" ) // ElemLink -- связь между объектами type ElemLink struct { types.IViewLabel CoordEnd_ types.IViewCoord `yaml:"coord_end"` // Координаты второй точки Src_ types.IElemBase `yaml:"src"` // Источник координат Dst_ types.IElemBase `yaml:"dst"` // Получатель координат TypeLink_ string `yaml:"type_link"` // Тип связи } var ( hassert = kern.GetFnHassert() ) // NewElemLink -- возвращает новую связь func NewElemLink(elemLabel types.IViewLabel, coordEnd types.IViewCoord, src, dst types.IElemBase, typeLink string) types.IElemLink { sf := &ElemLink{ IViewLabel: elemLabel, CoordEnd_: coordEnd, Src_: src, Dst_: dst, TypeLink_: typeLink, } sf.SelfCheck() return sf } // SelfCheck -- самопроверка элемента func (sf *ElemLink) SelfCheck() { sf.IViewLabel.SelfCheck() hassert(sf.CoordEnd_ != nil, "ElemLink.SelfCheck(): id=%v, CoordEnd_ == nil", sf.Id()) hassert(sf.Src_ != nil, "ElemLink.SelfCheck(): id=%v, Src_ == nil", sf.Id()) hassert(sf.Dst_ != nil, "ElemLink.SelfCheck(): id=%v, Dst_ == nil", sf.Id()) hassert(sf.TypeLink_ != "", "ElemLink.SelfCheck(): id=%v, TypeLink_ is empty", sf.Id()) } // TypeLink -- тип связи // //go:fix inline func (sf *ElemLink) TypeLink() string { return sf.TypeLink_ } // CoordEnd -- координаты конца связи // //go:fix inline func (sf *ElemLink) CoordEnd() types.IViewCoord { return sf.CoordEnd_ } // Links -- ссылки актора func (sf *ElemLink) Links() []types.IElemBase { return []types.IElemBase{sf.Src_, sf.Dst_} } // Check -- проверяет связи между объектами func (sf *ElemLink) Check() string { if sf.Dst_.Id() == sf.Src_.Id() { return fmt.Sprintf("ВНИМАНИЕ! Источник и получатель совпадают\nsrc=%v, dst=%v\n", sf.Src_.Id(), sf.Dst_.Id()) } if msgErr := sf.checkSrc(); msgErr != "" { return "ОШИБКА при проверке связи источника\n" + msgErr } if msgErr := sf.checkDst(); msgErr != "" { return "ОШИБКА при проверке связи получателя\n" + msgErr } if sf.TypeLink_ == "" { // Проверка на правильность типа связи return "Пустой собственный тип связи\n" } return "" } // проверить связь получателя func (sf *ElemLink) checkDst() string { if sf.Dst_ == nil { return "ОШИБКА получатель `dst` не задан" } // Вычислить на допустимые типы для получателя switch sf.Dst_.Type() { case cons.TypeUseActor: actor, isOk := sf.Dst_.(types.IElemActor) if !isOk { return fmt.Sprintf("Недопустимый тип получателя(%q)\nтип=%q\n", sf.Dst_.Id(), sf.Dst_.Type()) } isOk = false for _, id := range actor.GroupLink().Links() { if id == sf.Id() { isOk = true break } } if !isOk { return fmt.Sprintf("Невзаимная ссылка\nid=%q,dst=(%q)", sf.Id(), actor.Id()) } case cons.TypeUseLink: link, isOk := sf.Dst_.(types.IElemLink) if !isOk { return fmt.Sprintf("Недопустимый тип получателя(%q)\nтип=%q\n", sf.Dst_.Id(), sf.Dst_.Type()) } isOk = sf.Id() == link.Dst().Id() || sf.Id() == link.Src().Id() if !isOk { return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n", sf.Id(), link.Id()) } case cons.TypeUseCase: useCase, isOk := sf.Dst_.(types.IElemUseCase) if !isOk { return fmt.Sprintf("id=%q, Недопустимый тип получателя(%q)\nтип=%q\n", sf.Id(), sf.Dst_.Id(), sf.Dst_.Type()) } isOk = false for id := range useCase.Links() { if id == sf.Id() { isOk = true break } } if !isOk { return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n", sf.Id(), useCase.Id()) } default: // Недопустимый источник return fmt.Sprintf("id=%q, Недопустимый тип получателя(%q)\nid=%q\n", sf.Id(), sf.Dst_.Type(), sf.Dst_.Id()) } return "" } // Проверяет связь источника func (sf *ElemLink) checkSrc() string { if sf.Src_ == nil { return "ВНИМАНИЕ! Источник связи не задан(src)\n" } switch sf.Src_.Type() { case cons.TypeUseActor: isOk := false actor := sf.Src_.(types.IElemActor) for _, id := range actor.GroupLink().Links() { // Проверка на взаимность if id == sf.Id() { isOk = true break } } if !isOk { return fmt.Sprintf("Невзаимная ссылка с актором %q\n", actor.Id()) } case cons.TypeUseLink: link, isOk := sf.Src_.(types.IElemLink) if !isOk { return fmt.Sprintf("Несоответствие типа источника(%q)\nтип='useLink'\n", sf.Src_.Id()) } isOk = sf.Id() == link.Dst().Id() || sf.Id() == link.Src().Id() if !isOk { return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n", sf.Id(), link.Id()) } case cons.TypeUseCase: useCase, isOk := sf.Src_.(types.IElemUseCase) if !isOk { return fmt.Sprintf("id=%q, Тип источника(%q) не совпадает с фактическим\nтип='useCase'\n", sf.Id(), sf.Src_.Id()) } isOk = false for id := range useCase.Links() { // Проверка на взаимность if id == sf.Id() { isOk = true break } } if !isOk { return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n", sf.Id(), useCase.Id()) } default: // Неизвестный источник return fmt.Sprintf("id=%q, неизвестный тип источника(%q)
id=%q\n", sf.Id(), sf.Src_.Type(), sf.Src_.Id()) } return "" } // Src -- возвращает источник связи // //go:fix inline func (sf *ElemLink) Src() types.IElemBase { return sf.Src_ } // Dst -- возвращает получателя связи // //go:fix inline func (sf *ElemLink) Dst() types.IElemBase { return sf.Dst_ }