elem_link.go 6.3 KB

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