/*
 * citygml4j - The Open Source Java API for CityGML
 * https://github.com/citygml4j
 *
 * Copyright 2013-2020 Claus Nagel <claus.nagel@gmail.com>
 *
 * 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 org.citygml4j.model.core;

import org.xmlobjects.gml.model.geometry.GeometryProperty;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class GeometryInfo {
    private final Map<Integer, List<GeometryProperty<?>>> geometries = new HashMap<>();
    private final Map<Integer, List<ImplicitGeometryProperty>> implicitGeometries = new HashMap<>();

    public List<GeometryProperty<?>> getGeometries() {
        return geometries.values().stream()
                .flatMap(Collection::stream)
                .collect(Collectors.toList());
    }

    public List<GeometryProperty<?>> getGeometries(int lod) {
        return geometries.getOrDefault(lod, Collections.emptyList());
    }

    public List<GeometryProperty<?>> getNonLodGeometries() {
        return getGeometries(-1);
    }

    public void addGeometry(int lod, GeometryProperty<?> property) {
        if (lod >= 0 && property != null)
            geometries.computeIfAbsent(lod, v -> new ArrayList<>()).add(property);
    }

    public void addGeometry(GeometryProperty<?> property) {
        addGeometry(-1, property);
    }

    public boolean hasGeometries() {
        return !geometries.isEmpty();
    }

    public boolean hasGeometries(int lod) {
        return lod >= 0 && geometries.containsKey(lod);
    }

    public boolean hasNonLodGeometries() {
        return hasGeometries(-1);
    }

    public List<ImplicitGeometryProperty> getImplicitGeometries() {
        return implicitGeometries.values().stream()
                .flatMap(Collection::stream)
                .collect(Collectors.toList());
    }

    public List<ImplicitGeometryProperty> getImplicitGeometries(int lod) {
        return implicitGeometries.getOrDefault(lod, Collections.emptyList());
    }

    public List<ImplicitGeometryProperty> getNonLodImplicitGeometries() {
        return getImplicitGeometries(-1);
    }

    public void addImplicitGeometry(int lod, ImplicitGeometryProperty property) {
        if (lod >= 0 && property != null)
            implicitGeometries.computeIfAbsent(lod, v -> new ArrayList<>()).add(property);
    }

    public void addImplicitGeometry(ImplicitGeometryProperty property) {
        addImplicitGeometry(-1, property);
    }

    public boolean hasImplicitGeometries() {
        return !implicitGeometries.isEmpty();
    }

    public boolean hasImplicitGeometries(int lod) {
        return lod >= 0 && implicitGeometries.containsKey(lod);
    }

    public boolean hasNonLodImplicitGeometries() {
        return hasImplicitGeometries(-1);
    }
}

@@ -1480,32 +1480,74 @@
 %0A        return 
+lod %3E Integer.MIN_VALUE ?%0A                
 geometries.getOr
@@ -1575,32 +1575,74 @@
 ons.emptyList())
+ :%0A                Collections.emptyList()
 ;%0A    %7D%0A%0A    pub
@@ -1712,27 +1712,24 @@
 eturn ge
-tGe
 ometries
 (-1);%0A  
@@ -1712,35 +1712,88 @@
 eturn geometries
-(-1
+.getOrDefault(Integer.MIN_VALUE, Collections.emptyList()
 );%0A    %7D%0A%0A    pu
@@ -1863,36 +1863,24 @@
         if (
-lod %3E= 0 && 
 property != 
@@ -1875,32 +1875,59 @@
 property != null
+ && lod %3E Integer.MIN_VALUE
 )%0A            ge
@@ -2074,24 +2074,116 @@
     
-addGeometry(-1, 
+if (property != null)%0A            geometries.computeIfAbsent(Integer.MIN_VALUE, v -%3E new ArrayList%3C%3E()).add(
 prop
@@ -2338,27 +2338,42 @@
 return lod %3E
-= 0
+ Integer.MIN_VALUE
  && geometri
@@ -2458,20 +2458,17 @@
  return 
-hasG
+g
 eometrie
@@ -2460,35 +2460,62 @@
 eturn geometries
-(-1
+.containsKey(Integer.MIN_VALUE
 );%0A    %7D%0A%0A    pu
@@ -2809,32 +2809,74 @@
 %0A        return 
+lod %3E Integer.MIN_VALUE ?%0A                
 implicitGeometri
@@ -2912,32 +2912,74 @@
 ons.emptyList())
+ :%0A                Collections.emptyList()
 ;%0A    %7D%0A%0A    pub
@@ -3060,20 +3060,17 @@
  return 
-getI
+i
 mplicitG
@@ -3070,35 +3070,88 @@
 plicitGeometries
-(-1
+.getOrDefault(Integer.MIN_VALUE, Collections.emptyList()
 );%0A    %7D%0A%0A    pu
@@ -3238,28 +3238,16 @@
     if (
-lod %3E= 0 && 
 property
@@ -3246,32 +3246,59 @@
 property != null
+ && lod %3E Integer.MIN_VALUE
 )%0A            im
@@ -3466,32 +3466,124 @@
     
-addImplicitGeometry(-1, 
+if (property != null)%0A            implicitGeometries.computeIfAbsent(Integer.MIN_VALUE, v -%3E new ArrayList%3C%3E()).add(
 prop
@@ -3770,11 +3770,26 @@
 od %3E
-= 0
+ Integer.MIN_VALUE
  && 
@@ -3898,20 +3898,17 @@
  return 
-hasI
+i
 mplicitG
@@ -3920,11 +3920,38 @@
 ries
-(-1
+.containsKey(Integer.MIN_VALUE
 );%0A 

allow negative LoDs in GeometryInfo