001/*
002 * PlotSquared, a land and world management plugin for Minecraft.
003 * Copyright (C) IntellectualSites <https://intellectualsites.com>
004 * Copyright (C) IntellectualSites team and contributors
005 *
006 * This program is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
018 */
019package com.plotsquared.core.plot.world;
020
021import com.plotsquared.core.location.Location;
022import com.plotsquared.core.plot.PlotArea;
023import com.plotsquared.core.plot.PlotAreaType;
024import com.plotsquared.core.util.StringMan;
025import com.sk89q.worldedit.regions.CuboidRegion;
026import org.checkerframework.checker.nullness.qual.NonNull;
027import org.checkerframework.checker.nullness.qual.Nullable;
028
029import java.util.Collections;
030import java.util.HashSet;
031import java.util.Set;
032import java.util.function.Consumer;
033
034public interface PlotAreaManager {
035
036    /**
037     * Get the plot area for a particular location. This
038     * method assumes that the caller already knows that
039     * the location belongs to a plot area, in which
040     * case it will return the appropriate plot area.
041     * <p>
042     * If the location does not belong to a plot area,
043     * it may still return an area.
044     *
045     * @param location The location
046     * @return An applicable area, or null
047     */
048    @Nullable PlotArea getApplicablePlotArea(@Nullable Location location);
049
050    /**
051     * Get the plot area, if there is any, for the given
052     * location. This may return null, if given location
053     * does not belong to a plot area.
054     *
055     * @param location The location
056     * @return The area if found, else {@code null}
057     */
058    @Nullable PlotArea getPlotArea(@NonNull Location location);
059
060    /**
061     * Get the plot area in a world with an (optional ID).
062     * If the world has more than one plot area, and ID must be
063     * supplied. If the world only has one plot area, the ID will
064     * be ignored
065     *
066     * @param world World name
067     * @param id    Area ID
068     * @return Plot area matching the criteria
069     */
070    @Nullable PlotArea getPlotArea(@NonNull String world, @Nullable String id);
071
072    /**
073     * Get all plot areas in a world, with an optional region constraint
074     *
075     * @param world  World name
076     * @param region Optional region
077     * @return All plots in the region
078     */
079    @NonNull PlotArea[] getPlotAreas(@NonNull String world, @Nullable CuboidRegion region);
080
081    /**
082     * Get all plot areas recognized by PlotSquared
083     *
084     * @return All plot areas
085     */
086    @NonNull PlotArea[] getAllPlotAreas();
087
088    /**
089     * Get all worlds recognized by PlotSquared
090     *
091     * @return All world names
092     */
093    @NonNull String[] getAllWorlds();
094
095    /**
096     * Add a plot area
097     *
098     * @param area Area
099     */
100    void addPlotArea(@NonNull PlotArea area);
101
102    /**
103     * Remove a plot area
104     *
105     * @param area Area
106     */
107    void removePlotArea(@NonNull PlotArea area);
108
109    /**
110     * Add a world
111     *
112     * @param worldName Name of the world to add
113     */
114    void addWorld(@NonNull String worldName);
115
116    /**
117     * Remove a world
118     *
119     * @param worldName Name of the world to remove
120     */
121    void removeWorld(@NonNull String worldName);
122
123    /**
124     * Method that delegates to {@link #getPlotAreas(String, CuboidRegion)} but returns an
125     * immutable set, instead of an array
126     *
127     * @param world  World name
128     * @param region Optional region
129     * @return All areas in the world (and region)
130     */
131    default @NonNull Set<@NonNull PlotArea> getPlotAreasSet(
132            final @NonNull String world,
133            final @Nullable CuboidRegion region
134    ) {
135        final PlotArea[] areas = this.getPlotAreas(world, region);
136        final Set<PlotArea> set = new HashSet<>();
137        Collections.addAll(set, areas);
138        return Collections.unmodifiableSet(set);
139    }
140
141    /**
142     * Method identical to {@link #getPlotAreasSet(String, CuboidRegion)} but that
143     * does not take in a region, and returns a modifiable set
144     *
145     * @param world World name
146     * @return Modifiable set containing all plot areas in the specified world
147     */
148    default @NonNull Set<@NonNull PlotArea> getPlotAreasSet(final @NonNull String world) {
149        final Set<PlotArea> set = new HashSet<>();
150        Collections.addAll(set, this.getPlotAreas(world, null));
151        return set;
152    }
153
154    /**
155     * Get a plot area from a search string in the format "world;id" or "world,id"
156     * where the ID portion is optional
157     *
158     * @param search Search string
159     * @return An area that matches the search string, or {@code null}
160     */
161    default @Nullable PlotArea getPlotAreaByString(final @NonNull String search) {
162        String[] split = search.split("[;,]");
163        PlotArea[] areas = this.getPlotAreas(split[0], null);
164        if (areas == null) {
165            for (PlotArea area : this.getAllPlotAreas()) {
166                if (area.getWorldName().equalsIgnoreCase(split[0])) {
167                    if (area.getId() == null || split.length == 2 && area.getId()
168                            .equalsIgnoreCase(split[1])) {
169                        return area;
170                    }
171                }
172            }
173            return null;
174        }
175        if (areas.length == 1) {
176            return areas[0];
177        } else if (split.length == 1) {
178            return null;
179        } else {
180            for (PlotArea area : areas) {
181                if (StringMan.isEqual(split[1], area.getId())) {
182                    return area;
183                }
184            }
185            return null;
186        }
187    }
188
189    /**
190     * Check if a plot world.
191     *
192     * <p>
193     * Use {@link #getPlotAreaByString(String)} to get the PlotArea object
194     * </p>
195     *
196     * @param world the world
197     * @return if a plot world is registered
198     */
199    default boolean hasPlotArea(final @NonNull String world) {
200        return this.getPlotAreas(world, null).length != 0;
201    }
202
203    /**
204     * Check if a given world is an augmented plot world
205     *
206     * @param world World name
207     * @return {@code true} if the world is augmented plot world, {@code false} if not
208     */
209    default boolean isAugmented(final @NonNull String world) {
210        final PlotArea[] areas = this.getPlotAreas(world, null);
211        return areas != null && (areas.length > 1 || areas[0].getType() != PlotAreaType.NORMAL);
212    }
213
214    /**
215     * Perform an action on each recognized plot area
216     *
217     * @param action Action to perform
218     */
219    default void forEachPlotArea(final @NonNull Consumer<? super PlotArea> action) {
220        for (final PlotArea area : this.getAllPlotAreas()) {
221            action.accept(area);
222        }
223    }
224
225}