package org.globsframework.metamodel.impl;

import org.globsframework.metamodel.Annotations;
import org.globsframework.metamodel.GlobType;
import org.globsframework.metamodel.utils.MutableAnnotations;
import org.globsframework.model.Glob;
import org.globsframework.model.Key;
import org.globsframework.model.format.GlobPrinter;
import org.globsframework.utils.collections.MapOfMaps;
import org.globsframework.utils.exceptions.ItemNotFound;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static java.util.Spliterator.SIZED;

public class DefaultAnnotations<T extends MutableAnnotations> implements MutableAnnotations<T> {
    static private final Logger LOGGER = LoggerFactory.getLogger(DefaultAnnotations.class);
    volatile private MapOfMaps<GlobType, Key, Glob> annotations = new MapOfMaps<>();

    public DefaultAnnotations() {
    }

    public DefaultAnnotations(Glob[] annotations) {
        for (Glob annotation : annotations) {
            this.annotations.put(annotation.getType(), annotation.getKey(), annotation);
        }
    }

    public DefaultAnnotations(Annotations annotations) {
        annotations.streamAnnotations()
            .forEach(annotation -> this.annotations.put(annotation.getType(), annotation.getKey(), annotation)
            );
    }

    public T addAnnotation(Glob glob) {
        if (glob != null) {
            synchronized (this) {
                MapOfMaps<GlobType, Key, Glob> tmp = new MapOfMaps<>(annotations);
                Glob old = tmp.put(glob.getType(), glob.getKey(), glob);
                if (old != null && old != glob) {
                    LOGGER.warn(GlobPrinter.toString(glob) + " has replaced " + GlobPrinter.toString(old));
                }
                annotations = tmp;
            }
        }
        return (T)this;
    }

    public T addAnnotations(Stream<Glob> globs) {
        synchronized (this) {
            MapOfMaps<GlobType, Key, Glob> tmp = new MapOfMaps<>(annotations);
            globs.forEach(glob -> {
                Glob old = tmp.put(glob.getType(), glob.getKey(), glob);
                if (old != null && old != glob) {
                    LOGGER.warn(GlobPrinter.toString(glob) + " has replaced " + GlobPrinter.toString(old));
                }
            });

            annotations = tmp;
        }
        return (T)this;
    }

    public Stream<Glob> streamAnnotations() {
        return StreamSupport.stream(Spliterators.spliterator(annotations.iterator(), annotations.size(), SIZED), false);
    }

    public Stream<Glob> streamAnnotations(GlobType type) {
        return annotations.get(type).values().stream();
    }

    public boolean hasAnnotation(Key key) {
        return annotations.containsKey(key.getGlobType(), key);
    }

    public Glob getAnnotation(Key key) {
        Glob annotation = annotations.get(key.getGlobType(), key);
        if (annotation == null) {
            throw new ItemNotFound(key.toString());
        }
        return annotation;
    }

    public Glob findAnnotation(Key key) {
        return annotations.get(key.getGlobType(), key);
    }
}

@@ -325,63 +325,8 @@
 er;%0A
-import org.globsframework.utils.collections.MapOfMaps;%0A
 impo
@@ -453,28 +453,23 @@
 va.util.
-Spliterators
+HashMap
 ;%0Aimport
@@ -479,29 +479,19 @@
 va.util.
-stream.Stream
+Map
 ;%0Aimport
@@ -518,59 +518,8 @@
 ream
-Support;%0A%0Aimport static java.util.Spliterator.SIZED
 ;%0A%0Ap
@@ -730,33 +730,17 @@
 vate Map
-OfMaps%3CGlobType, 
+%3C
 Key, Glo
@@ -760,25 +760,23 @@
 s = new 
-MapOf
+Hash
 Map
-s
 %3C%3E();%0A%0A 
@@ -946,38 +946,16 @@
 ons.put(
-annotation.getType(), 
 annotati
@@ -1106,16 +1106,20 @@
         
+    
 .forEach
@@ -1158,30 +1158,8 @@
 put(
-annotation.getType(), 
 anno
@@ -1187,16 +1187,20 @@
 tation)%0A
+    
         
@@ -1334,33 +1334,17 @@
      Map
-OfMaps%3CGlobType, 
+%3C
 Key, Glo
@@ -1352,33 +1352,31 @@
 %3E tmp = new 
-MapOf
+Hash
 Map
-s
 %3C%3E(annotatio
@@ -1415,32 +1415,16 @@
 tmp.put(
-glob.getType(), 
 glob.get
@@ -1682,32 +1682,33 @@
       return (T)
+ 
 this;%0A    %7D%0A%0A   
@@ -1803,25 +1803,9 @@
  Map
-OfMaps%3CGlobType, 
+%3C
 Key,
@@ -1825,17 +1825,15 @@
 new 
-MapOf
+Hash
 Map
-s
 %3C%3E(a
@@ -1920,24 +1920,8 @@
 put(
-glob.getType(), 
 glob
@@ -2190,16 +2190,17 @@
 turn (T)
+ 
 this;%0A  
@@ -2269,111 +2269,36 @@
 urn 
-StreamSupport.stream(Spliterators.spliterator(annotations.iterator(), annotations.size(), SIZED), false
+annotations.values().stream(
 );%0A 
@@ -2393,18 +2393,8 @@
 ons.
-get(type).
 valu
@@ -2398,32 +2398,71 @@
 alues().stream()
+.filter(glob -%3E glob.getType() == type)
 ;%0A    %7D%0A%0A    pub
@@ -2537,35 +2537,16 @@
 ainsKey(
-key.getGlobType(), 
 key);%0A  
@@ -2633,35 +2633,16 @@
 ons.get(
-key.getGlobType(), 
 key);%0A  
@@ -2846,27 +2846,8 @@
 get(
-key.getGlobType(), 
 key)

remove useless mapOfMap in DefaultAnnotations