package story_service import ( "context" "evening_detective/internal/modules/cleaner" "evening_detective/internal/modules/formatter" "regexp" "strings" ) type StoryService struct { cleaner cleaner.ICleaner formatter formatter.IFormatter story *Story storyStorage IStoryStorage } func NewStoryService( cleaner cleaner.ICleaner, formatter formatter.IFormatter, storyStorage IStoryStorage, ) (*StoryService, error) { s := &StoryService{ cleaner: cleaner, formatter: formatter, storyStorage: storyStorage, } story, err := s.storyStorage.Load(context.Background()) if err != nil { return nil, err } s.story = story return s, nil } func (s *StoryService) Update(ctx context.Context) error { if err := s.storyStorage.Save(ctx, s.story); err != nil { return err } story, err := s.storyStorage.Load(ctx) if err != nil { return err } s.story = story return nil } func (s *StoryService) GetPlace(code string) *Place { if strings.HasPrefix(code, "[") || strings.HasSuffix(code, "]") { return &Place{ Code: code, Name: "Не найдено", Text: "Уважаемые детективы внимательно прочитайте правила.", } } clearCode := s.cleaner.ClearCode(code) for _, place := range s.story.Places { if s.cleaner.ClearCode(place.Code) == clearCode { applications := make([]*Application, 0, len(place.Applications)) for _, application := range place.Applications { name := s.cleaner.ClearText(application.Name) applications = append( applications, &Application{ Name: name, }, ) } return &Place{ Code: place.Code, Name: place.Name, Text: s.cleaner.ClearText(place.Text), Applications: applications, } } } return &Place{ Code: code, Name: "Не найдено", Text: "Такой точки не существует.", } } func (s *StoryService) UpdatePlace(ctx context.Context, code string, node *GraphNode) error { if code != "" && node.Code == "" { return s.deletePlace(ctx, code) } if code == "" && node.Code != "" { return s.addPlace(ctx, node) } if code == "" || node.Code == "" { return nil } return s.updatePlace(ctx, code, node) } func (s *StoryService) deletePlace(ctx context.Context, code string) error { for i := range s.story.Places { if s.story.Places[i].Code == code { s.story.Places = append(s.story.Places[:i], s.story.Places[i+1:]...) break } } return s.Update(ctx) } func (s *StoryService) addPlace(ctx context.Context, node *GraphNode) error { s.story.Places = append( s.story.Places, &Place{ Code: node.Code, Name: node.Name, Text: s.formatter.FormatText(node.Text), Applications: s.getApplications(node), }, ) return s.Update(ctx) } func (s *StoryService) updatePlace(ctx context.Context, code string, node *GraphNode) error { for i := range s.story.Places { if s.story.Places[i].Code == code { s.story.Places[i] = &Place{ Code: node.Code, Name: node.Name, Text: s.formatter.FormatText(node.Text), Applications: s.getApplications(node), } return s.Update(ctx) } } for i := range s.story.Places { if s.story.Places[i].Code == node.Code { s.story.Places[i] = &Place{ Code: code, Name: node.Name, Text: s.formatter.FormatText(node.Text), Applications: s.getApplications(node), } break } } return s.Update(ctx) } func (s *StoryService) getApplications(node *GraphNode) []*Application { nodeApplications := make([]*Application, 0, len(node.Applications)) for _, application := range node.Applications { nodeApplications = append( nodeApplications, &Application{ Name: application.Name, }, ) } return nodeApplications } func (s *StoryService) GetGraph(ctx context.Context) *Graph { m := make(map[string]string, len(s.story.Places)) nodes := make([]*GraphNode, 0, len(s.story.Places)) for _, place := range s.story.Places { m[s.cleaner.ClearCode(place.Code)] = place.Code applications := make([]*GraphApplication, 0, len(place.Applications)) for _, application := range place.Applications { applications = append( applications, &GraphApplication{ Name: application.Name, }, ) } nodes = append( nodes, &GraphNode{ Code: place.Code, Name: place.Name, Text: place.Text, Applications: applications, }, ) } edges := make([]*GraphEdge, 0, len(s.story.Places)*3) for _, place := range s.story.Places { placeLinks := s.findPlaceLinksInText(place.Text) for _, placeLink := range placeLinks { edges = append( edges, &GraphEdge{ From: m[s.cleaner.ClearCode(place.Code)], To: m[s.cleaner.ClearCode(placeLink)], Type: "node", }, ) } for _, application := range place.Applications { placeLinks := s.findPlaceLinksInText(application.Name) for _, placeLink := range placeLinks { edges = append( edges, &GraphEdge{ From: m[s.cleaner.ClearCode(place.Code)], To: m[s.cleaner.ClearCode(placeLink)], Type: "application", }, ) } } } return &Graph{ Nodes: nodes, Edges: edges, } } func (s *StoryService) findPlaceLinksInText(text string) []string { re := regexp.MustCompile(`\(\[[a-zA-Zа-яА-Я\d-]+\]\)`) return re.FindAllString(text, -1) }