package story_service import ( "context" "encoding/json" "fmt" "log" "os" "regexp" "strings" ) type StoryService struct { story *Story } func NewStoryService(filepath string) (*StoryService, error) { s := &StoryService{} if err := s.Load(filepath); err != nil { return nil, err } return s, nil } func (s *StoryService) Load(filepath string) error { data, err := os.ReadFile(filepath) if err != nil { return fmt.Errorf("story file %s not found", filepath) } log.Printf("load story from: %s", filepath) story := &Story{} if err := json.Unmarshal(data, story); err != nil { return err } s.story = story return nil } func (s *StoryService) Save(filepath string) error { story := s.story data, err := json.Marshal(story) if err != nil { return err } if err := os.WriteFile(filepath, data, 0x777); err != nil { return err } log.Printf("save story to: %s", filepath) return nil } func (s *StoryService) GetPlace(code string) *Place { if strings.HasPrefix(code, "[") || strings.HasSuffix(code, "]") { return &Place{ Code: code, Name: "Не найдено", Text: "Уважаемые детективы внимательно прочитайте правила.", } } code = clearCode(code) for _, place := range s.story.Places { if clearCode(place.Code) == code { re := regexp.MustCompile(`\(\[[a-zA-Zа-яА-Я\d-]+\]\)`) text := re.ReplaceAllString(place.Text, "") return &Place{ Code: place.Code, Name: place.Name, Text: text, Applications: place.Applications, } } } return &Place{ Code: code, Name: "Не найдено", Text: "Такой точки не существует.", } } func (s *StoryService) GetGraph(ctx context.Context) *Graph { m := make(map[string]int32, len(s.story.Places)) nodes := make([]*GraphNode, 0, len(s.story.Places)) for i, place := range s.story.Places { m[clearCode(place.Code)] = int32(i) applications := make([]*GraphApplication, 0, len(place.Applications)) for _, application := range place.Applications { applications = append( applications, &GraphApplication{ Name: application.Name, }, ) } nodes = append( nodes, &GraphNode{ ID: int32(i), Label: 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 { re := regexp.MustCompile(`\(\[[a-zA-Zа-яА-Я\d-]+\]\)`) matches := re.FindAllString(place.Text, -1) for _, match := range matches { edges = append( edges, &GraphEdge{ From: m[clearCode(place.Code)], To: m[clearMatch(match)], }, ) } } return &Graph{ Nodes: nodes, Edges: edges, } }