/*
 * Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all
 *  copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 */

package me.lucko.luckperms.sponge.service.persisted;

import lombok.ToString;
import me.lucko.luckperms.api.context.ContextSet;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.MemorySubjectData;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.util.Tristate;

import java.util.*;
import java.util.stream.Collectors;

import static me.lucko.luckperms.sponge.service.LuckPermsService.convertContexts;

/**
 * Holds SubjectData in a "gson friendly" format for serialization
 */
@ToString
public class SubjectDataHolder {
    private final Map<Map<String, String>, Map<String, Boolean>> permissions;
    private final Map<Map<String, String>, Map<String, String>> options;
    private final Map<Map<String, String>, List<Map.Entry<String, String>>> parents;

    public SubjectDataHolder(Map<Set<Context>, Map<String, String>> options, Map<Set<Context>, Map<String, Boolean>> permissions, Map<Set<Context>, List<Map.Entry<String, String>>> parents) {
        this.options = new HashMap<>();
        for (Map.Entry<Set<Context>, Map<String, String>> e : options.entrySet()) {
            this.options.put(convertContexts(e.getKey()).toMap(), new HashMap<>(e.getValue()));
        }

        this.permissions = new HashMap<>();
        for (Map.Entry<Set<Context>, Map<String, Boolean>> e : permissions.entrySet()) {
            this.permissions.put(convertContexts(e.getKey()).toMap(), new HashMap<>(e.getValue()));
        }

        this.parents = new HashMap<>();
        for (Map.Entry<Set<Context>, List<Map.Entry<String, String>>> e : parents.entrySet()) {
            this.parents.put(convertContexts(e.getKey()).toMap(), e.getValue().stream().map(p -> new AbstractMap.SimpleEntry<>(p.getKey(), p.getValue())).collect(Collectors.toList()));
        }
    }

    public SubjectDataHolder(MemorySubjectData data) {
        this(
                data.getAllOptions(),
                data.getAllPermissions(),
                data.getAllParents().entrySet().stream()
                        .collect(Collectors.toMap(
                                Map.Entry::getKey,
                                e -> e.getValue().stream()
                                        .map(s -> new AbstractMap.SimpleEntry<>(
                                                s.getContainingCollection().getIdentifier(),
                                                s.getIdentifier())
                                        )
                                        .collect(Collectors.toList())
                                )
                        )
        );
    }

    public void copyTo(MemorySubjectData subjectData, PermissionService service) {
        for (Map.Entry<Map<String, String>, Map<String, Boolean>> e : permissions.entrySet()) {
            Set<Context> contexts = convertContexts(ContextSet.fromMap(e.getKey()));
            for (Map.Entry<String, Boolean> perm : e.getValue().entrySet()) {
                subjectData.setPermission(contexts, perm.getKey(), Tristate.fromBoolean(perm.getValue()));
            }
        }

        for (Map.Entry<Map<String, String>, Map<String, String>> e : options.entrySet()) {
            Set<Context> contexts = convertContexts(ContextSet.fromMap(e.getKey()));
            for (Map.Entry<String, String> option : e.getValue().entrySet()) {
                subjectData.setOption(contexts, option.getKey(), option.getValue());
            }
        }

        for (Map.Entry<Map<String, String>, List<Map.Entry<String, String>>> e : parents.entrySet()) {
            Set<Context> contexts = convertContexts(ContextSet.fromMap(e.getKey()));
            for (Map.Entry<String, String> parent : e.getValue()) {
                subjectData.addParent(contexts, service.getSubjects(parent.getKey()).get(parent.getValue()));
            }
        }
    }
}

@@ -1196,16 +1196,56 @@
 isted;%0A%0A
+import com.google.common.base.Splitter;%0A
 import l
@@ -2004,33 +2004,14 @@
 ist%3C
-Map.Entry%3CString, String%3E
+String
 %3E%3E p
@@ -2923,38 +2923,8 @@
  -%3E 
-new AbstractMap.SimpleEntry%3C%3E(
 p.ge
@@ -2929,17 +2929,24 @@
 getKey()
-,
+ + %22/%22 +
  p.getVa
@@ -2951,17 +2951,16 @@
 Value())
-)
 .collect
@@ -4690,33 +4690,14 @@
 ist%3C
-Map.Entry%3CString, String%3E
+String
 %3E%3E e
@@ -4827,33 +4827,14 @@
 or (
-Map.Entry%3CString, String%3E
+String
  par
@@ -4851,24 +4851,108 @@
 tValue()) %7B%0A
+                List%3CString%3E parts = Splitter.on('/').limit(2).splitToList(parent);%0A
             
@@ -5014,19 +5014,16 @@
 (par
-en
 t
+s
 .get
-Key
 (
+0
 )).g
@@ -5032,21 +5032,16 @@
 (par
-en
 t
+s
 .get
-Value
 (
+1
 )));

Fix Sponge defaults serialization