/**
* PermissionsEx
* Copyright (C) zml and PermissionsEx contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ninja.leaping.permissionsex.backend.sql;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import ninja.leaping.permissionsex.util.ThrowingBiConsumer;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import static ninja.leaping.permissionsex.util.Util.appendImmutable;
import static ninja.leaping.permissionsex.util.Util.updateImmutable;
class Segment {
private volatile int id;
private final Set<Map.Entry<String, String>> contexts;
private final Map<String, Integer> permissions;
private final Map<String, String> options;
private final List<SubjectRef> parents;
private final Integer permissionDefault;
private final AtomicReference<ImmutableList<ThrowingBiConsumer<SqlDao, Segment, SQLException>>> updatesToPerform = new AtomicReference<>();
Segment(int id, Set<Map.Entry<String, String>> contexts, Map<String, Integer> permissions, Map<String, String> options, List<SubjectRef> parents, Integer permissionDefault, ImmutableList<ThrowingBiConsumer<SqlDao, Segment, SQLException>> updates) {
this.id = id;
this.contexts = ImmutableSet.copyOf(contexts);
this.permissions = permissions;
this.options = options;
this.parents = parents;
this.permissionDefault = permissionDefault;
this.updatesToPerform.set(updates);
}
static Segment empty(int id) {
return new Segment(id, ImmutableSet.of(), ImmutableMap.of(), ImmutableMap.of(), ImmutableList.of(), null, null);
}
static Segment empty(int id, Set<Map.Entry<String, String>> contexts) {
return new Segment(id, contexts, ImmutableMap.of(), ImmutableMap.of(), ImmutableList.of(), null, null);
}
private Segment newWithUpdate(Map<String, Integer> permissions, Map<String, String> options, List<SubjectRef> parents, Integer permissionDefault, ThrowingBiConsumer<SqlDao, Segment, SQLException> updateFunc) {
return new Segment(this.id, this.contexts, permissions, options, parents, permissionDefault, appendImmutable(this.updatesToPerform.get(), updateFunc));
}
static Segment unallocated() {
return Segment.empty(-1);
}
static Segment unallocated(Set<Map.Entry<String, String>> contexts) {
return Segment.empty(-1, contexts);
}
public int getId() {
if (id == SqlConstants.UNALLOCATED) {
throw new IllegalStateException("Unable to find issues");
}
return id;
}
public Set<Map.Entry<String, String>> getContexts() {
return contexts;
}
public Map<String, Integer> getPermissions() {
return permissions;
}
public Map<String, String> getOptions() {
return options;
}
public List<SubjectRef> getParents() {
return parents;
}
public Integer getPermissionDefault() {
return permissionDefault;
}
public Segment withOption(String key, String value) {
return newWithUpdate(this.permissions, updateImmutable(this.options, key, value), this.parents, this.permissionDefault, (dao, seg) -> {
dao.setOption(seg, key, value);
});
}
public Segment withoutOption(String key) {
if (options == null || !options.containsKey(key)) {
return this;
}
Map<String, String> newOptions = new HashMap<>(options);
newOptions.remove(key);
return newWithUpdate(this.permissions, newOptions, this.parents, this.permissionDefault, (dao, seg) -> {
dao.clearOption(seg, key);
});
}
public Segment withOptions(Map<String, String> values) {
Map<String, String> immValues = values == null ? null : ImmutableMap.copyOf(values);
return newWithUpdate(permissions, immValues, parents, permissionDefault, (dao, seg) -> {
dao.setOptions(seg, immValues);
});
}
public Segment withoutOptions() {
return newWithUpdate(permissions, null, parents, permissionDefault, (dao, seg) -> dao.setOptions(seg, null));
}
public Segment withPermission(String permission, int value) {
return newWithUpdate(updateImmutable(permissions, permission, value), options, parents, permissionDefault, (dao, seg) -> dao.setPermission(seg, permission, value));
}
public Segment withoutPermission(String permission) {
if (permissions == null || !permissions.containsKey(permission)) {
return this;
}
Map<String, Integer> newPermissions = new HashMap<>(permissions);
newPermissions.remove(permission);
return newWithUpdate(newPermissions, options, parents, permissionDefault, (dao, seg) -> dao.clearPermission(seg, permission));
}
public Segment withPermissions(Map<String, Integer> values) {
Map<String, Integer> immValues = values == null ? null : ImmutableMap.copyOf(values);
return newWithUpdate(immValues, options, parents, permissionDefault, (dao, seg) -> dao.setPermissions(seg, immValues));
}
public Segment withoutPermissions() {
return newWithUpdate(null, options, parents, permissionDefault, (dao, seg) -> dao.setPermissions(seg, null));
}
public Segment withDefaultValue(Integer permissionDefault) {
return newWithUpdate(permissions, options, parents, permissionDefault, (dao, seg) -> dao.setDefaultValue(seg, permissionDefault));
}
public Segment withAddedParent(SubjectRef parent) {
ImmutableList.Builder<SubjectRef> parents = ImmutableList.builder();
parents.add(parent);
if (this.parents != null) {
parents.addAll(this.parents);
}
return newWithUpdate(permissions, options, parents.build(), permissionDefault, (dao, seg) -> dao.addParent(seg, parent));
}
public Segment withRemovedParent(SubjectRef parent) {
if (this.parents == null || this.parents.isEmpty()) {
return this;
}
final List<SubjectRef> newParents = new ArrayList<>(parents);
if (!newParents.remove(parent)) {
return this;
}
return newWithUpdate(permissions, options, newParents, permissionDefault, (dao, seg) -> dao.removeParent(seg, parent));
}
public Segment withParents(List<SubjectRef> parents) {
List<SubjectRef> immValues = parents == null ? null : ImmutableList.copyOf(parents);
return newWithUpdate(permissions, options, immValues, permissionDefault, (dao, seg) -> dao.setParents(seg, immValues));
}
public Segment withoutParents() {
return newWithUpdate(permissions, options, null, permissionDefault, (dao, seg) -> dao.setParents(seg, null));
}
List<ThrowingBiConsumer<SqlDao, Segment, SQLException>> popUpdates() {
return this.updatesToPerform.getAndSet(null);
}
void doUpdates(SqlDao dao) throws SQLException {
List<ThrowingBiConsumer<SqlDao, Segment, SQLException>> updateFuncs = popUpdates();
if (updateFuncs != null) {
for (ThrowingBiConsumer<SqlDao, Segment, SQLException> consumer : updateFuncs) {
consumer.accept(dao, this);
}
}
}
@Override
public String toString() {
return "Segment{" +
"id=" + id +
", contexts=" + contexts +
", permissions=" + permissions +
", options=" + options +
", parents=" + parents +
", permissionDefault=" + permissionDefault +
'}';
}
public boolean isEmpty() {
return (this.permissions == null || this.permissions.isEmpty())
&& (this.options == null || this.options.isEmpty())
&& (this.parents == null || this.parents.isEmpty())
&& this.permissionDefault == null;
}
boolean isUnallocated() {
return this.id == SqlConstants.UNALLOCATED;
}
public void setId(int id) {
this.id = id;
}
}