/*
* This file is part of the Illarion project.
*
* Copyright © 2015 - Illarion e.V.
*
* Illarion is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Illarion is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
package illarion.client.world;
import org.jetbrains.annotations.Contract;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* This class is used to organise the maps into groups. This is done to show and hide whole groups of maps.
*
* @author Martin Karing <nitram@illarion.org>
*/
public final class MapGroup {
/**
* In case this flag is turned {@code true} the entire map group is hidden. This value has no effect at all in
* case the {@link #parent} is not set to {@code null}.
*/
private boolean hidden;
/**
* The parent group that will overwrite the local hidden value. This is used to connect multiple map groups.
*/
@Nullable
private MapGroup parent;
/**
* This list contains a list of groups that will overwrite the hidden state of the group. In case one of the
* groups in this list is hidden, this group will be assumed hidden as well.
*/
@Nullable
private Set<MapGroup> overwritingGroups;
/**
* This list stores the children of this map group.
*/
@Nullable
private List<MapGroup> children;
/**
* Get the root group. This could either be this group or a parent group that has not further parent.
*
* @return the root group
*/
@Nonnull
@Contract(pure = true)
public MapGroup getRootGroup() {
MapGroup currentGroup = this;
while (true) {
MapGroup parentGroup = currentGroup.parent;
if (parentGroup == null) {
return currentGroup;
}
currentGroup = parentGroup;
}
}
/**
* Check if this map group is currently hidden.
*
* @return {@code in case the map group is hidden}
*/
public boolean isHidden() {
if (getRootGroup().isOverwritingGroupHidden()) {
return true;
}
return hidden;
}
/**
* Check if one of the overwriting groups of this map group is flagged as hidden.
*
* @return {@code true} in case one of the overwriting groups is hidden
*/
private boolean isOverwritingGroupHidden() {
@Nullable Set<MapGroup> lclList = overwritingGroups;
if (lclList != null) {
for (MapGroup group : lclList) {
assert group != null;
if (group.isHidden()) {
return true;
}
}
}
return false;
}
@Contract(pure = true)
public boolean isRootGroup() {
return parent == null;
}
/**
* Set the hidden flag of this map group.
*
* @param hidden the hidden flag
*/
public void setHidden(boolean hidden) {
MapGroup other = this;
while (true) {
if (other.parent == null) {
other.hidden = hidden;
other.sendHiddenToChildren();
return;
}
other = other.parent;
}
}
/**
* Send the hidden flag to all children.
*/
private void sendHiddenToChildren() {
if (children == null) {
return;
}
for (MapGroup aChildren : children) {
aChildren.hidden = hidden;
}
}
/**
* Apply a parent to this map group.
*
* @param parent the parent of this group
*/
public void setParent(@Nonnull MapGroup parent) {
if (parent.parent != null) {
throw new IllegalArgumentException("Set a parent group that is not a root group is not allowed.");
}
if (this.parent != null) {
throw new IllegalArgumentException("Setting a parent to a group that already has a parent is not allows");
}
this.parent = parent;
parent.addChild(this);
if (children != null) {
children.forEach(parent::addChild);
children = null;
}
Set<MapGroup> overwriting = overwritingGroups;
overwritingGroups = null;
if (overwriting != null) {
parent.addOverwritingGroups(overwriting);
}
}
/**
* Add a child to the list of children of this map group.
*
* @param child the child to add
*/
private void addChild(@Nonnull MapGroup child) {
if (children == null) {
children = new ArrayList<>();
}
if (!children.contains(child)) {
children.add(child);
}
}
/**
* Add a group to the list of overwriting groups.
*
* @param group the group to add to the list of overwriting groups
*/
public void addOverwritingGroup(@Nonnull MapGroup group) {
if (parent != null) {
throw new IllegalStateException("Adding overwriting groups no non-root groups is not allowed.");
}
if (overwritingGroups == null) {
overwritingGroups = new CopyOnWriteArraySet<>();
}
if (!overwritingGroups.contains(group)) {
overwritingGroups.add(group);
}
}
public void addOverwritingGroups(@Nonnull Collection<MapGroup> groups) {
if (parent != null) {
throw new IllegalStateException("Adding overwriting groups no non-root groups is not allowed.");
}
if (overwritingGroups == null) {
overwritingGroups = new CopyOnWriteArraySet<>();
}
overwritingGroups.addAll(groups);
}
}