# DetailedAvailabilityListenerFileParseByOperaImpl.java

    package cloud.wconnect.rateshop.service.revenue.detailedavailability;

    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.SystemPlatformEnum;
    import cloud.wconnect.commonlib.pojo.bo.ReportDataBO;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.rateshop.pojo.bo.revenue.RoomTypeRoomsBO;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.google.common.collect.Lists;
    import org.apache.commons.lang3.StringUtils;
    import org.dom4j.Document;
    import org.dom4j.Element;
    import org.dom4j.Node;
    import org.dom4j.io.SAXReader;
    import org.springframework.stereotype.Service;

    import java.io.InputStream;
    import java.util.List;
    import java.util.Objects;

    /**
     * @author yyt
     * 2025/02/12
     */
    @Service
    @DS("rate_shop")
    public class DetailedAvailabilityListenerFileParseByOperaImpl implements IDetailedAvailabilityListenerFileParse {

        private static final String SOURCE = SystemPlatformEnum.OPERA.getDesc();

        /**
         * 判断支持的平台
         *
         * @param source 平台
         * @return boolean
         * @author yyt
         * @date 2025/02/12
         */
        @Override
        public boolean supports(String source) {
            return SOURCE.equals(source);
        }

        /**
         * 解析报告数据
         *
         * @param propertyId 资产 id
         * @param timeZone   时区
         * @param in         文件流
         * @param startDate  开始日期
         * @param endDate    结束日期
         * @return RoomTypeRoomsBO
         * @author yyt
         * @date 2025/02/12
         */
        @Override
        public ReportDataBO<RoomTypeRoomsBO> parseReportForNext14Days(Integer propertyId, String timeZone, InputStream in,
                                                                      Long startDate, Long endDate) throws Exception {
            List<RoomTypeRoomsBO> roomTypeRoomsBOS = Lists.newArrayList();

            // 报告中的数据在处理范围内
            boolean isInScope = false;

            // 解析文件数据
            Document document = new SAXReader().read(in);
            List<Node> dateNodes = document.selectNodes("//DAY");
            for (Node node : dateNodes) {
                Element element = (Element) node;
                String targetDateStr = element.elementText("BUSINESS_DATE");
                String[] strArray = targetDateStr.split("-");
                if (strArray.length != 3) {
                    continue;
                }

                long dataDate = DateTimeUtils.dateStrToEpochSecond(targetDateStr, BaseConstant.DATE_FORMAT_MM_DD_YY_STRIKE, timeZone);
                if (dataDate < startDate || dataDate > endDate) {
                    continue;
                } else {
                    isInScope = true;
                }

                List<Node> childNodes = node.selectNodes("./LIST_ROOM_TYPE/ROOM_TYPE");
                for (Node childNode : childNodes) {
                    Element elementChild = (Element) childNode;
                    String roomType = elementChild.elementText("MARKET_CODE");
                    if (StringUtils.isBlank(roomType)) continue;

                    // 查找可用房间数
                    Integer rooms = null;
                    List<Node> roomsNodes = childNode.selectNodes("./LIST_DETAIL/DETAIL");
                    for (Node roomsNode : roomsNodes) {
                        Element roomsElement = (Element) roomsNode;
                        String roomsStr = roomsElement.elementText("NO_OF_ROOMS1");
                        if (StringUtils.isNotBlank(roomsStr)) {
                            if (Objects.isNull(rooms)) {
                                rooms = 0;
                            }

                            rooms += Integer.parseInt(roomsStr);
                        }
                    }

                    roomTypeRoomsBOS.add(new RoomTypeRoomsBO(dataDate, roomType, rooms));
                }
            }

            return new ReportDataBO<>(isInScope, roomTypeRoomsBOS);
        }

    }