const { persistGroups, readStoredGroups } = require('./persistence.js') const { getWxApi } = require('../../utils/base-utils.js') const { normalizeStorageCodeInfoCard, DATA_TYPE_OPTIONS, REGISTER_TYPE_OPTIONS, normalizeGroup } = require('../../domain/parameter-groups/model.js') const storageAccessService = require('../storage-access/service.js') const { PROTOCOL_MODE, normalizeProtocolMode } = require('../../domain/protocol-mode.js') const STORAGE_CODE_INFO_KEY = 'parameter-groups-code-info' let initialized = false const subscribers = [] const DEFAULT_STORAGE_CODE_INFO_CARD = normalizeStorageCodeInfoCard(null) let state = { activeProtocolMode: PROTOCOL_MODE.STORAGE_ACCESS, parameterDataTypeOptions: DATA_TYPE_OPTIONS, parameterGroupsByProtocol: { [PROTOCOL_MODE.MODBUS_RTU]: [], [PROTOCOL_MODE.STORAGE_ACCESS]: [] }, parameterRegisterTypeOptions: REGISTER_TYPE_OPTIONS, storageCodeInfoCard: DEFAULT_STORAGE_CODE_INFO_CARD } function getActiveProtocolMode() { return normalizeProtocolMode(state.activeProtocolMode) } function getActiveGroups() { if (getActiveProtocolMode() === PROTOCOL_MODE.NONE) return [] return state.parameterGroupsByProtocol[getActiveProtocolMode()] || [] } function getGroupsForProtocol(protocolMode = getActiveProtocolMode()) { const normalizedProtocolMode = normalizeProtocolMode(protocolMode) if (normalizedProtocolMode === PROTOCOL_MODE.NONE) return [] return state.parameterGroupsByProtocol[normalizedProtocolMode] || [] } function getCodeInfoContext(card = state.storageCodeInfoCard) { return card && card.codeInfoContext ? card.codeInfoContext : {} } function normalizeGroupsForProtocol(parameterGroups = [], protocolMode = getActiveProtocolMode(), options = {}) { const codeInfoContext = protocolMode === PROTOCOL_MODE.STORAGE_ACCESS ? getCodeInfoContext(options.storageCodeInfoCard) : {} return Array.isArray(parameterGroups) ? parameterGroups.map((group) => normalizeGroup({ ...group, codeInfoContext })) : [] } function notify() { const nextState = getState() subscribers.slice().forEach((subscriber) => { subscriber(nextState) }) } function persistActiveGroups(options = {}) { if (options.persist === false) return persistGroups(getActiveGroups(), getActiveProtocolMode()) } function setState(changedData, options = {}) { state = { ...state, ...changedData } persistActiveGroups(options) notify() } function setGroups(parameterGroups, options = {}) { const protocolMode = normalizeProtocolMode(options.protocolMode || getActiveProtocolMode()) if (protocolMode === PROTOCOL_MODE.NONE) { notify() return } const normalizedGroups = normalizeGroupsForProtocol(parameterGroups, protocolMode) const parameterGroupsByProtocol = { ...state.parameterGroupsByProtocol, [protocolMode]: normalizedGroups } state = { ...state, parameterGroupsByProtocol } if (options.persist !== false) persistGroups(normalizedGroups, protocolMode) notify() } function persistStorageCodeInfoCard(card) { const wxApi = getWxApi() if (typeof wxApi.setStorageSync !== 'function') return try { wxApi.setStorageSync(STORAGE_CODE_INFO_KEY, JSON.stringify(card || null)) } catch (error) {} } function readStorageCodeInfoCard() { const wxApi = getWxApi() if (typeof wxApi.getStorageSync !== 'function') return DEFAULT_STORAGE_CODE_INFO_CARD try { const jsonText = wxApi.getStorageSync(STORAGE_CODE_INFO_KEY) return jsonText ? normalizeStorageCodeInfoCard(JSON.parse(jsonText)) : DEFAULT_STORAGE_CODE_INFO_CARD } catch (error) { return DEFAULT_STORAGE_CODE_INFO_CARD } } function setStorageCodeInfo(codeInfo, options = {}) { const card = normalizeStorageCodeInfoCard(codeInfo) storageAccessService.updateSyncedDeviceCaps(card.codeInfoContext || {}) const storageGroups = state.parameterGroupsByProtocol[PROTOCOL_MODE.STORAGE_ACCESS] || [] const normalizedStorageGroups = normalizeGroupsForProtocol(storageGroups, PROTOCOL_MODE.STORAGE_ACCESS, { storageCodeInfoCard: card }) state = { ...state, parameterGroupsByProtocol: { ...state.parameterGroupsByProtocol, [PROTOCOL_MODE.STORAGE_ACCESS]: normalizedStorageGroups }, storageCodeInfoCard: card } if (options.persist !== false) persistGroups(normalizedStorageGroups, PROTOCOL_MODE.STORAGE_ACCESS) if (options.persist !== false) persistStorageCodeInfoCard(card) notify() } function updateGroups(mapper, options = {}) { if (typeof mapper !== 'function') return const protocolMode = normalizeProtocolMode(options.protocolMode || getActiveProtocolMode()) if (protocolMode === PROTOCOL_MODE.NONE) return setGroups(getGroupsForProtocol(protocolMode).map((group, index) => mapper(group, index)), { ...options, protocolMode }) } function switchProtocolMode(protocolMode, options = {}) { const normalizedProtocolMode = normalizeProtocolMode(protocolMode) init(normalizedProtocolMode) if (state.activeProtocolMode === normalizedProtocolMode) { if (options.notify !== false) notify() return } state = { ...state, activeProtocolMode: normalizedProtocolMode } if (options.notify !== false) notify() } function init(protocolMode = state.activeProtocolMode) { const normalizedProtocolMode = normalizeProtocolMode(protocolMode) if (initialized) return const storageCodeInfoCard = readStorageCodeInfoCard() storageAccessService.updateSyncedDeviceCaps(storageCodeInfoCard.codeInfoContext || {}) const protocolOrder = normalizedProtocolMode === PROTOCOL_MODE.MODBUS_RTU ? [PROTOCOL_MODE.MODBUS_RTU, PROTOCOL_MODE.STORAGE_ACCESS] : [PROTOCOL_MODE.STORAGE_ACCESS, PROTOCOL_MODE.MODBUS_RTU] const parameterGroupsByProtocol = { [PROTOCOL_MODE.MODBUS_RTU]: [], [PROTOCOL_MODE.STORAGE_ACCESS]: [] } protocolOrder.forEach((targetProtocolMode) => { parameterGroupsByProtocol[targetProtocolMode] = normalizeGroupsForProtocol( readStoredGroups(targetProtocolMode), targetProtocolMode, { storageCodeInfoCard } ) }) state = { ...state, activeProtocolMode: normalizedProtocolMode, storageCodeInfoCard, parameterGroupsByProtocol } initialized = true } function getState() { return { activeProtocolMode: getActiveProtocolMode(), parameterDataTypeOptions: DATA_TYPE_OPTIONS, parameterGroups: getActiveGroups(), parameterRegisterTypeOptions: REGISTER_TYPE_OPTIONS, storageCodeInfoCard: state.storageCodeInfoCard } } function getGroups() { return getActiveGroups() } function findGroup(groupId, protocolMode = getActiveProtocolMode()) { return getGroupsForProtocol(protocolMode).find((group) => group.id === groupId) } function subscribe(subscriber) { if (typeof subscriber !== 'function') return () => {} init() subscribers.push(subscriber) subscriber(getState()) return () => { const index = subscribers.indexOf(subscriber) if (index >= 0) subscribers.splice(index, 1) } } module.exports = { DATA_TYPE_OPTIONS, REGISTER_TYPE_OPTIONS, findGroup, getGroups, getState, init, setGroups, setState, setStorageCodeInfo, switchProtocolMode, subscribe, updateGroups }