package repository import ( "errors" "fmt" "joylink.club/rtsssimulation/repository/model/proto" ) var repositoryMap = make(map[string]*Repository) func BuildRepository(source *proto.Repository) (*Repository, error) { repository := NewRepository(source.Id, source.Version) buildModels(source, repository) err := buildModelRelationship(source, repository) if err == nil { repositoryMap[buildRepositoryKey(source.Id, source.Version)] = repository } return repository, err } func buildRepositoryKey(id string, version string) string { return id + "_" + version } func getRepository(id string, version string) (*Repository, error) { repository := repositoryMap[buildRepositoryKey(id, version)] if repository == nil { return repository, errors.New(fmt.Sprintf("%s-%s的仓库未找到", id, version)) } return repository, nil } func buildModels(source *proto.Repository, repository *Repository) { for _, protoData := range source.KilometerConverts { repository.addKilometerConvert(protoData) } for _, protoData := range source.PhysicalSections { m := NewPhysicalSection(protoData.Id) repository.physicalSectionMap[m.Id()] = m } for _, protoData := range source.CheckPoints { if protoData.Type != proto.CheckPointType_Boundary { m := NewCheckPoint(protoData.Id, protoData.Km, protoData.Type) repository.checkPointMap[m.Id()] = m } } for _, protoData := range source.Turnouts { m := NewTurnout(protoData.Id, protoData.Km) repository.turnoutMap[m.Id()] = m } for _, protoData := range source.Signals { m := NewSignal(protoData.Id, protoData.Km) repository.signalMap[m.Id()] = m } for _, protoData := range source.Responders { m := NewResponder(protoData.Id, protoData.Km) repository.responderMap[m.Id()] = m } for _, protoData := range source.Slopes { m := NewSlope(protoData.Id, protoData.Kms, protoData.Degree) repository.slopeMap[m.Id()] = m } for _, protoData := range source.SectionalCurvatures { m := NewSectionalCurvature(protoData.Id, protoData.Kms, protoData.Radius) repository.sectionalCurvatureMap[m.Id()] = m } } func buildModelRelationship(source *proto.Repository, repository *Repository) error { err := buildCheckPointRelationShip(source, repository) if err != nil { return err } err = buildPhysicalSectionRelationShip(source, repository) if err != nil { return err } err = buildTurnoutRelationShip(source, repository) if err != nil { return err } err = buildSignalRelationShip(source, repository) if err != nil { return err } err = buildResponderRelationShip(source, repository) if err != nil { return err } return err } func buildCheckPointRelationShip(source *proto.Repository, repo *Repository) error { for _, protoData := range source.CheckPoints { cp := repo.checkPointMap[protoData.Id] isBoundary := cp.pointType == proto.CheckPointType_Boundary for _, protoDp := range protoData.DevicePorts { switch protoDp.DeviceType { case proto.DeviceType_DeviceType_PhysicalSection: section := repo.physicalSectionMap[protoDp.DeviceId] if isBoundary { //是区段边界 err := section.bindBoundaryKm(cp.km, protoDp.Port) if err != nil { return err } } else { //检测点关联区段端口 cp.bindDevicePort(&PhysicalSectionPort{ section: section, port: protoDp.Port, }) //区段关联检测点 section.bindDevices(cp) } case proto.DeviceType_DeviceType_Turnout: turnout := repo.turnoutMap[protoDp.DeviceId] if isBoundary { //是区段边界 err := turnout.bindBoundaryKm(cp.km, protoDp.Port) if err != nil { return err } } else { //检测点关联道岔端口 cp.bindDevicePort(&TurnoutPort{ turnout: turnout, port: protoDp.Port, }) //道岔关联检测点 turnout.bindDevice(cp, protoDp.Port) } } } } return nil } func buildResponderRelationShip(source *proto.Repository, repository *Repository) error { for _, protoData := range source.Responders { responder := repository.responderMap[protoData.Id] //应答器和区段相互关联 interrelateResponderAndPhysicalSection(responder, repository.physicalSectionMap[protoData.SectionId]) //应答器和道岔相互关联 tp := protoData.TurnoutPort if tp != nil { if tp.DeviceType != proto.DeviceType_DeviceType_Turnout { return errors.New(fmt.Sprintf("应答器[%s]关联的[%s-%s-%s]并非道岔端口", responder.Id(), tp.DeviceId, tp.DeviceType, tp.Port)) } interrelateResponderAndTurnout(responder, repository.turnoutMap[tp.DeviceId], tp.Port) } } return nil } func buildSignalRelationShip(source *proto.Repository, repository *Repository) error { for _, protoData := range source.Signals { signal := repository.signalMap[protoData.Id] //信号机和区段相互关联 interrelateSignalAndPhysicalSection(signal, repository.physicalSectionMap[protoData.SectionId]) //信号机和道岔相互关联 tp := protoData.TurnoutPort if tp != nil { if tp.DeviceType != proto.DeviceType_DeviceType_Turnout { return errors.New(fmt.Sprintf("信号机[%s]关联的[%s-%s-%s]并非道岔端口", signal.Id(), tp.DeviceId, tp.DeviceType, tp.Port)) } interrelateSignalAndTurnout(signal, repository.turnoutMap[tp.DeviceId], tp.Port) } } return nil } func buildTurnoutRelationShip(source *proto.Repository, repo *Repository) error { for _, protoData := range source.Turnouts { turnout := repo.turnoutMap[protoData.Id] err := buildTurnoutPortRelation(repo, turnout, proto.Port_A, protoData.ADevicePort) if err != nil { return err } err = buildTurnoutPortRelation(repo, turnout, proto.Port_B, protoData.BDevicePort) if err != nil { return err } err = buildTurnoutPortRelation(repo, turnout, proto.Port_C, protoData.CDevicePort) return err } return nil } func buildTurnoutPortRelation(repo *Repository, turnout *Turnout, port proto.Port, protoDp *proto.DevicePort) error { model, err := repo.getModel(protoDp.DeviceId, protoDp.DeviceType) if err != nil { return err } dp, err := buildDevicePort(model, protoDp.Port) if err != nil { return err } err = turnout.bindDevicePort(port, dp) return err } func buildPhysicalSectionRelationShip(source *proto.Repository, repository *Repository) error { for _, protoData := range source.PhysicalSections { section := repository.physicalSectionMap[protoData.Id] //A端关联 if protoData.ADevicePort != nil { err := buildSectionPortRelation(repository, section, proto.Port_A, protoData.ADevicePort) if err != nil { return err } } //B端关联 if protoData.BDevicePort != nil { err := buildSectionPortRelation(repository, section, proto.Port_B, protoData.BDevicePort) if err != nil { return err } } } return nil } // 构建物理区段指定端口的关联关系。区段{section}的{port}端口关联{protoDp} func buildSectionPortRelation(repo *Repository, section *PhysicalSection, port proto.Port, protoDp *proto.DevicePort) error { model, err := repo.getModel(protoDp.DeviceId, protoDp.DeviceType) if err != nil { return err } dp, err := buildDevicePort(model, protoDp.Port) if err != nil { return err } err = section.bindDevicePort(port, dp) if err != nil { return err } return nil } func buildDevicePort(device Identity, port proto.Port) (DevicePort, error) { var dp DevicePort switch device.Type() { case proto.DeviceType_DeviceType_PhysicalSection: section := device.(*PhysicalSection) dp = &PhysicalSectionPort{ section: section, port: port, } case proto.DeviceType_DeviceType_Turnout: turnout := device.(*Turnout) dp = &TurnoutPort{ turnout: turnout, port: port, } case proto.DeviceType_DeviceType_Link: link := device.(*Link) dp = &LinkPort{ link: link, port: port, } case proto.DeviceType_DeviceType_LinkNode: linkNode := device.(*LinkNode) dp = &LinkNodePort{ node: linkNode, port: port, } default: return nil, errors.New(fmt.Sprintf("[%s]类型设备没有端口", device.Type())) } return dp, nil } // 相互关联道岔和检测点 func interrelateTurnoutAndCheckPoints(turnout *Turnout, point *CheckPoint, port proto.Port) { turnout.bindDevice(point, port) point.bindDevicePort(&TurnoutPort{ turnout: turnout, port: port, }) } // 相互关联物理区段和信号机 func interrelateSignalAndPhysicalSection(signal *Signal, section *PhysicalSection) { section.bindDevices(signal) signal.bindSection(section) } // 相互关联信号机和道岔 func interrelateSignalAndTurnout(signal *Signal, turnout *Turnout, port proto.Port) { signal.bindTurnoutPort(TurnoutPort{ turnout: turnout, port: port, }) turnout.bindDevice(signal, port) } // 相互关联应答器和物理区段 func interrelateResponderAndPhysicalSection(responder *Responder, section *PhysicalSection) { responder.bindSection(section) section.bindDevices(responder) } // 相互关联应答器和道岔 func interrelateResponderAndTurnout(responder *Responder, turnout *Turnout, port proto.Port) { responder.bindTurnoutPort(TurnoutPort{ turnout: turnout, port: port, }) turnout.bindDevice(responder, port) }