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.google.inject.Singleton;
022import com.plotsquared.core.location.Location;
023import com.plotsquared.core.plot.PlotArea;
024import com.plotsquared.core.plot.PlotAreaType;
025import com.plotsquared.core.plot.PlotWorld;
026import com.plotsquared.core.util.StringMan;
027import com.sk89q.worldedit.regions.CuboidRegion;
028import org.checkerframework.checker.nullness.qual.NonNull;
029import org.checkerframework.checker.nullness.qual.Nullable;
030
031import java.util.ArrayList;
032import java.util.HashMap;
033import java.util.HashSet;
034import java.util.List;
035import java.util.Map;
036import java.util.Set;
037
038@Singleton
039public class DefaultPlotAreaManager implements PlotAreaManager {
040
041    final PlotArea[] noPlotAreas = new PlotArea[0];
042    private final Map<String, PlotWorld> plotWorlds = new HashMap<>();
043
044    @Override
045    public @NonNull PlotArea[] getAllPlotAreas() {
046        final Set<PlotArea> area = new HashSet<>();
047        for (final PlotWorld world : plotWorlds.values()) {
048            area.addAll(world.getAreas());
049        }
050        return area.toArray(new PlotArea[0]);
051    }
052
053    @Override
054    public @Nullable PlotArea getApplicablePlotArea(final @Nullable Location location) {
055        if (location == null) {
056            return null;
057        }
058        final PlotWorld world = this.plotWorlds.get(location.getWorldName());
059        if (world == null) {
060            return null;
061        }
062        return world.getArea(location);
063    }
064
065    @Override
066    public void addPlotArea(final @NonNull PlotArea plotArea) {
067        PlotWorld world = this.plotWorlds.get(plotArea.getWorldName());
068        if (world != null) {
069            if (world instanceof StandardPlotWorld && world.getAreas().isEmpty()) {
070                this.plotWorlds.remove(plotArea.getWorldName());
071            } else {
072                world.addArea(plotArea);
073                return;
074            }
075        }
076        if (plotArea.getType() != PlotAreaType.PARTIAL) {
077            world = new StandardPlotWorld(plotArea.getWorldName(), plotArea);
078        } else {
079            world = new ScatteredPlotWorld(plotArea.getWorldName());
080            world.addArea(plotArea);
081        }
082        this.plotWorlds.put(plotArea.getWorldName(), world);
083    }
084
085    @Override
086    public void removePlotArea(final @NonNull PlotArea area) {
087        final PlotWorld world = this.plotWorlds.get(area.getWorldName());
088        if (world == null) {
089            return;
090        }
091        if (world instanceof StandardPlotWorld) {
092            this.plotWorlds.remove(world.getWorld());
093        } else {
094            world.removeArea(area);
095            if (world.getAreas().isEmpty()) {
096                this.plotWorlds.remove(world.getWorld());
097            }
098        }
099    }
100
101    @Override
102    public PlotArea getPlotArea(final @NonNull String world, final @Nullable String id) {
103        final PlotWorld plotWorld = this.plotWorlds.get(world);
104        if (plotWorld == null) {
105            return null;
106        }
107        final List<PlotArea> areas = new ArrayList<>(plotWorld.getAreas());
108        if (areas.size() == 1) {
109            return areas.get(0);
110        }
111        if (id == null) {
112            return null;
113        }
114        for (final PlotArea area : areas) {
115            if (StringMan.isEqual(id, area.getId())) {
116                return area;
117            }
118        }
119        return null;
120    }
121
122    @Override
123    public @Nullable PlotArea getPlotArea(final @NonNull Location location) {
124        return this.getApplicablePlotArea(location);
125    }
126
127    @Override
128    public @NonNull PlotArea[] getPlotAreas(final @NonNull String world, final @Nullable CuboidRegion region) {
129        final PlotWorld plotWorld = this.plotWorlds.get(world);
130        if (plotWorld == null) {
131            return noPlotAreas;
132        }
133        if (region == null) {
134            return plotWorld.getAreas().toArray(new PlotArea[0]);
135        }
136        return plotWorld.getAreasInRegion(region).toArray(new PlotArea[0]);
137    }
138
139    @Override
140    public void addWorld(final @NonNull String worldName) {
141        PlotWorld world = this.plotWorlds.get(worldName);
142        if (world != null) {
143            return;
144        }
145        // Create a new empty world. When a new area is added
146        // the world will be re-recreated with the correct type
147        world = new StandardPlotWorld(worldName, null);
148        this.plotWorlds.put(worldName, world);
149    }
150
151    @Override
152    public void removeWorld(final @NonNull String worldName) {
153        this.plotWorlds.remove(worldName);
154    }
155
156    @Override
157    public @NonNull String[] getAllWorlds() {
158        return this.plotWorlds.keySet().toArray(new String[0]);
159    }
160
161}