001/*
002 *  Copyright (c) 2023-2026, Agents-Flex (fuhai999@gmail.com).
003 *  <p>
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.agentsflex.core.util;
017
018import com.alibaba.fastjson2.JSON;
019
020import java.lang.reflect.Array;
021import java.util.Collection;
022import java.util.HashMap;
023import java.util.Map;
024import java.util.function.Function;
025
026public class Maps extends HashMap<String, Object> {
027
028    public static Maps of() {
029        return new Maps();
030    }
031
032    public static Maps of(String key, Object value) {
033        Maps maps = Maps.of();
034        maps.put(key, value);
035        return maps;
036    }
037
038    public static Maps ofNotNull(String key, Object value) {
039        return new Maps().setIfNotNull(key, value);
040    }
041
042    public static Maps ofNotEmpty(String key, Object value) {
043        return new Maps().setIfNotEmpty(key, value);
044    }
045
046    public static Maps ofNotEmpty(String key, Maps value) {
047        return new Maps().setIfNotEmpty(key, value);
048    }
049
050
051    public Maps set(String key, Object value) {
052        super.put(key, value);
053        return this;
054    }
055
056    public Maps setChild(String key, Object value) {
057        if (key.contains(".")) {
058            String[] keys = key.split("\\.");
059            Map<String, Object> currentMap = this;
060            for (int i = 0; i < keys.length; i++) {
061                String currentKey = keys[i].trim();
062                if (currentKey.isEmpty()) {
063                    continue;
064                }
065                if (i == keys.length - 1) {
066                    currentMap.put(currentKey, value);
067                } else {
068                    //noinspection unchecked
069                    currentMap = (Map<String, Object>) currentMap.computeIfAbsent(currentKey, k -> Maps.of());
070                }
071            }
072        } else {
073            super.put(key, value);
074        }
075
076        return this;
077    }
078
079    public Maps setOrDefault(String key, Object value, Object orDefault) {
080        if (isNullOrEmpty(value)) {
081            return this.set(key, orDefault);
082        } else {
083            return this.set(key, value);
084        }
085    }
086
087    public Maps setIf(boolean condition, String key, Object value) {
088        if (condition) put(key, value);
089        return this;
090    }
091
092    public Maps setIf(Function<Maps, Boolean> func, String key, Object value) {
093        if (func.apply(this)) put(key, value);
094        return this;
095    }
096
097    public Maps setIfNotNull(String key, Object value) {
098        if (value != null) put(key, value);
099        return this;
100    }
101
102    public Maps setIfNotEmpty(String key, Object value) {
103        if (!isNullOrEmpty(value)) {
104            put(key, value);
105        }
106        return this;
107    }
108
109    public Maps setIfNotEmpty(Map<String, Object> source) {
110        if (!isNullOrEmpty(source)) {
111            this.putAll(source);
112        }
113        return this;
114    }
115
116
117    public Maps setIfContainsKey(String checkKey, String key, Object value) {
118        if (this.containsKey(checkKey)) {
119            this.put(key, value);
120        }
121        return this;
122    }
123
124    public Maps setIfNotContainsKey(String checkKey, String key, Object value) {
125        if (!this.containsKey(checkKey)) {
126            this.put(key, value);
127        }
128        return this;
129    }
130
131    public String toJSON() {
132        return JSON.toJSONString(this);
133    }
134
135
136    private static boolean isNullOrEmpty(Object value) {
137        if (value == null) {
138            return true;
139        }
140
141        if (value instanceof Collection && ((Collection<?>) value).isEmpty()) {
142            return true;
143        }
144
145        if (value instanceof Map && ((Map<?, ?>) value).isEmpty()) {
146            return true;
147        }
148
149        if (value.getClass().isArray() && Array.getLength(value) == 0) {
150            return true;
151        }
152
153        return value instanceof String && ((String) value).trim().isEmpty();
154    }
155}