use_link.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // package use_link -- связь между объектами
  2. package use_link
  3. import (
  4. "fmt"
  5. "gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
  6. "gitp78su.ipnodns.ru/svi/goarch/lev0/cons"
  7. "gitp78su.ipnodns.ru/svi/goarch/lev0/types"
  8. "gitp78su.ipnodns.ru/svi/goarch/pkg/elems/coord"
  9. "gitp78su.ipnodns.ru/svi/goarch/pkg/elems/elem_base"
  10. )
  11. // UseLink -- связь между объектами
  12. type UseLink struct {
  13. *elem_base.ElemBase
  14. CoordEnd_ *coord.Coord `json:"coord1"` // Координаты второй точки
  15. Src_ alias.Id `json:"src"` // Источник координат
  16. Dst_ alias.Id `json:"dst"` // Получатель координат
  17. TypeLink_ string `json:"typeLink"` // Тип связи
  18. }
  19. // NewUseLink -- возвращает новую связь
  20. func NewUseLink(elem map[string]interface{}) (*UseLink, error) {
  21. elemBase, err := elem_base.NewElemBase(elem)
  22. if err != nil {
  23. return nil, fmt.Errorf("NewUseLink(): in create BaseSvg, err=\n\t%w", err)
  24. }
  25. id := elemBase.Id_
  26. _src := elemBase.Elem_["src"]
  27. src0, isOk := _src.(string)
  28. if !isOk {
  29. return nil, fmt.Errorf("NewUseLink(): id=%q, field `src` not string, type=%T, value=%v", id, _src, elemBase.StrElem_)
  30. }
  31. src := alias.Id(src0)
  32. if src == "" {
  33. return nil, fmt.Errorf("NewUseLink(): id=%q, `src` is empty", id)
  34. }
  35. _dst := elemBase.Elem_["dst"]
  36. dst0, isOk := _dst.(string)
  37. if !isOk {
  38. return nil, fmt.Errorf("NewUseLink(): id=%q, field `dst` not string, type=%T, value=%+v<br>%+v", id, _dst, _dst, elemBase.StrElem_)
  39. }
  40. dst := alias.Id(dst0)
  41. _typeLink, isOk := elemBase.Elem_["type_link"]
  42. if !isOk {
  43. return nil, fmt.Errorf("NewUseLink(): name=%q, field `type_link` not found<br>%+v", id, elemBase.StrElem_)
  44. }
  45. typeLink, isOk := _typeLink.(string)
  46. if !isOk {
  47. return nil, fmt.Errorf("NewUseLink(): name=%q, `type_link`(%+v) not string", id, _typeLink)
  48. }
  49. if typeLink == "" {
  50. return nil, fmt.Errorf("NewUseLink(): name=%q, type_link=%q is empty", id, typeLink)
  51. }
  52. sf := &UseLink{
  53. ElemBase: elemBase,
  54. CoordEnd_: coord.NewCoord("coord1", elem),
  55. Src_: src,
  56. Dst_: dst,
  57. TypeLink_: typeLink,
  58. }
  59. return sf, nil
  60. }
  61. // Links -- ссылки актора
  62. func (sf *UseLink) Links() []alias.Id {
  63. return []alias.Id{sf.Src_, sf.Dst_}
  64. }
  65. // Check -- проверяет связи между объектами
  66. func (sf *UseLink) Check(mapDrawer map[alias.Id]types.IElemDrawer) string {
  67. if sf.Dst_ == sf.Src_ {
  68. return fmt.Sprintf("ВНИМАНИЕ! Источник и получатель совпадают\nsrc=%v, dst=%v\n", sf.Src_, sf.Dst_)
  69. }
  70. if msgErr := sf.checkSrc(mapDrawer); msgErr != "" {
  71. return "ОШИБКА при проверке связи источника\n" + msgErr
  72. }
  73. if msgErr := sf.checkDst(mapDrawer); msgErr != "" {
  74. return "ОШИБКА при проверке связи получателя\n" + msgErr
  75. }
  76. if sf.TypeLink_ == "" { // Проверка на правильность типа связи
  77. return "Пустой собственный тип связи\n"
  78. }
  79. return ""
  80. }
  81. // проверить связь получателя
  82. func (sf *UseLink) checkDst(mapDrawer map[alias.Id]types.IElemDrawer) string {
  83. if sf.Dst_ == "" {
  84. return "ОШИБКА получатель `dst` не задан"
  85. }
  86. dst, isOk := mapDrawer[sf.Dst_] // Вычислить, если такой получатель
  87. if !isOk {
  88. return "Отсутствует собственный получатель(dst)\n"
  89. }
  90. // Вычислить на допустимые типы для получателя
  91. switch dst.Type() {
  92. case cons.TypeUseActor:
  93. actor, isOk := dst.(types.IActor)
  94. if !isOk {
  95. return fmt.Sprintf("Недопустимый тип получателя(%q)\nтип=%q\n", dst.Id(), dst.Type())
  96. }
  97. isOk = false
  98. for _, id := range actor.Links() {
  99. if id == sf.Id_ {
  100. isOk = true
  101. break
  102. }
  103. }
  104. if !isOk {
  105. return fmt.Sprintf("Невзаимная ссылка\nid=%q,dst=(%q)", sf.Id_, actor.Id())
  106. }
  107. case cons.TypeUseLink:
  108. link, isOk := dst.(types.ILinker)
  109. if !isOk {
  110. return fmt.Sprintf("Недопустимый тип получателя(%q)\nтип=%q\n", dst.Id(), dst.Type())
  111. }
  112. isOk = sf.Id_ == link.DstId() || sf.Id_ == link.SrcId()
  113. if !isOk {
  114. return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n", sf.Id_, link.Id())
  115. }
  116. case cons.TypeUseCase:
  117. useCase, isOk := dst.(types.IUseCase)
  118. if !isOk {
  119. return fmt.Sprintf("id=%q, Недопустимый тип получателя(%q)\nтип=%q\n", sf.Id_, dst.Id(), dst.Type())
  120. }
  121. isOk = false
  122. for _, id := range useCase.Links() {
  123. if id == sf.Id_ {
  124. isOk = true
  125. break
  126. }
  127. }
  128. if !isOk {
  129. return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n", sf.Id_, useCase.Id())
  130. }
  131. default: // Недопустимый источник
  132. return fmt.Sprintf("id=%q, Недопустимый тип получателя(%q)\nid=%q\n", sf.Id_, dst.Type(), dst.Id())
  133. }
  134. return ""
  135. }
  136. // Проверяет связь источника
  137. func (sf *UseLink) checkSrc(mapDrawer map[alias.Id]types.IElemDrawer) string {
  138. if sf.Src_ == "" {
  139. return "ВНИМАНИЕ! Источник связи не задан(src)\n"
  140. }
  141. src, isOk := mapDrawer[sf.Src_]
  142. if !isOk {
  143. return "Отсутствует источник(src)\n"
  144. }
  145. switch src.Type() {
  146. case cons.TypeUseActor:
  147. isOk = false
  148. actor := types.IActor(src)
  149. for _, id := range actor.Links() { // Проверка на взаимность
  150. if id == sf.Id_ {
  151. isOk = true
  152. break
  153. }
  154. }
  155. if !isOk {
  156. return fmt.Sprintf("Невзаимная ссылка с актором %q\n", actor.Id())
  157. }
  158. case cons.TypeUseLink:
  159. link, isOk := src.(types.ILinker)
  160. if !isOk {
  161. return fmt.Sprintf("Несоответствие типа источника(%q)\nтип='useLink'\n", src.Id())
  162. }
  163. isOk = sf.Id_ == link.DstId() || sf.Id_ == link.SrcId()
  164. if !isOk {
  165. return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n", sf.Id_, link.Id())
  166. }
  167. case cons.TypeUseCase:
  168. useCase, isOk := src.(types.IUseCase)
  169. if !isOk {
  170. return fmt.Sprintf("id=%q, Тип источника(%q) не совпадает с фактическим\nтип='useCase'\n", sf.Id_, src.Id())
  171. }
  172. isOk = false
  173. for _, id := range useCase.Links() { // Проверка на взаимность
  174. if id == sf.Id_ {
  175. isOk = true
  176. break
  177. }
  178. }
  179. if !isOk {
  180. return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n", sf.Id_, useCase.Id())
  181. }
  182. default: // Неизвестный источник
  183. return fmt.Sprintf("id=%q, неизвестный тип источника(%q)<br>id=%q\n", sf.Id_, src.Type(), src.Id())
  184. }
  185. return ""
  186. }
  187. // SrcId -- возвращает источник связи
  188. func (sf *UseLink) SrcId() alias.Id {
  189. return sf.Src_
  190. }
  191. // DstId -- возвращает получателя связи
  192. func (sf *UseLink) DstId() alias.Id {
  193. return sf.Dst_
  194. }