/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.logging.slf4j;

import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.logging.log4j.MarkerManager;
import org.slf4j.IMarkerFactory;
import org.slf4j.Marker;

/**
 * Log4j/SLF4J bridge to create SLF4J Markers based on name or based on existing SLF4J Markers.
 */
public class Log4jMarkerFactory implements IMarkerFactory {

    private final ConcurrentMap<String, Marker> markerMap = new ConcurrentHashMap<String, Marker>();

    /**
     * Returns a Log4j Marker that is compatible with SLF4J.
     * @param name The name of the Marker.
     * @return A Marker.
     */
    @Override
    public Marker getMarker(final String name) {
        if (name == null) {
            throw new IllegalArgumentException("Marker name must not be null");
        }
        Marker marker = markerMap.get(name);
        if (marker != null) {
            return marker;
        }
        final org.apache.logging.log4j.Marker log4jMarker = MarkerManager.getMarker(name);
        return addMarkerIfAbsent(name, log4jMarker);
    }

    private Marker addMarkerIfAbsent(final String name, final org.apache.logging.log4j.Marker log4jMarker) {
        final Marker marker = new Log4jMarker(log4jMarker);
        final Marker existing = markerMap.putIfAbsent(name, marker);
        return existing == null ? marker : existing;
    }

    /**
     * Returns a Log4j Marker converted from an existing custom SLF4J Marker.
     * @param marker The SLF4J Marker to convert.
     * @return A converted Log4j/SLF4J Marker.
     * @since 2.1
     */
    public Marker getMarker(final Marker marker) {
        if (marker == null) {
            throw new IllegalArgumentException("Marker must not be null");
        }
        Marker m = markerMap.get(marker.getName());
        if (m != null) {
            return m;
        }
        return addMarkerIfAbsent(marker.getName(), convertMarker(marker));
    }

    private static org.apache.logging.log4j.Marker convertMarker(final Marker original) {
        if (original == null) {
            throw new IllegalArgumentException("Marker must not be null");
        }
        final org.apache.logging.log4j.Marker marker = MarkerManager.getMarker(original.getName());
        if (original.hasReferences()) {
            final Iterator it = original.iterator();
            while (it.hasNext()) {
                final Marker next = (Marker) it.next();
                // kind of hope nobody uses cycles in their Markers. I mean, why would you do that?
                marker.addParents(convertMarker(next));
            }
        }
        return marker;
    }

    /**
     * Returns true if the Marker exists.
     * @param name The Marker name.
     * @return true if the Marker exists, false otherwise.
     */
    @Override
    public boolean exists(final String name) {
        return markerMap.containsKey(name);
    }

    /**
     * Log4j does not support detached Markers. This method always returns false.
     * @param name The Marker name.
     * @return false
     */
    @Override
    public boolean detachMarker(final String name) {
        return false;
    }

    /**
     * Log4j does not support detached Markers for performance reasons. The returned Marker is attached.
     * @param name The Marker name.
     * @return
     */
    @Override
    public Marker getDetachedMarker(final String name) {
        return getMarker(name);
    }


}

@@ -829,16 +829,73 @@
 slf4j;%0A%0A
+import java.util.ArrayList;%0Aimport java.util.Collection;%0A
 import j
@@ -1004,16 +1004,56 @@
 ntMap;%0A%0A
+import org.apache.logging.log4j.Logger;%0A
 import o
@@ -1087,24 +1087,77 @@
 kerManager;%0A
+import org.apache.logging.log4j.status.StatusLogger;%0A
 import org.s
@@ -1368,16 +1368,84 @@
 tory %7B%0A%0A
+    private static final Logger LOGGER = StatusLogger.getLogger();%0A%0A
     priv
@@ -3190,32 +3190,293 @@
 ll%22);%0A        %7D%0A
+        return convertMarker(original, new ArrayList%3CMarker%3E());%0A    %7D%0A%0A    private static org.apache.logging.log4j.Marker convertMarker(final Marker original,%0A                                                                 final Collection%3CMarker%3E visited) %7B%0A
         final or
@@ -3763,92 +3763,209 @@
     
-// kind of hope nobody uses
+if (visited.contains(next)) %7B%0A                    LOGGER.warn(%22Found a
  cycle
-s
  in 
-their Markers. I mean, why would you do that?%0A
+Marker %5B%7B%7D%5D. Cycle will be broken.%22, next.getName());%0A                %7D else %7B%0A                    visited.add(next);%0A   
     
@@ -3976,16 +3976,17 @@
         
+ 
 marker.a
@@ -4013,19 +4013,46 @@
 ker(next
-));
+, visited));%0A                %7D
 %0A       
@@ -4199,20 +4199,28 @@
 @return 
+%7B@code 
 true
+%7D
  if the 
@@ -4233,22 +4233,30 @@
  exists,
+ %7B@code
  false
+%7D
  otherwi
@@ -4520,21 +4520,29 @@
 @return 
+%7B@code 
 false
+%7D
 %0A     */
@@ -4801,16 +4801,47 @@
  @return
+ The named Marker (unmodified).
 %0A     */
@@ -4904,32 +4904,143 @@
  String name) %7B%0A
+        LOGGER.warn(%22Log4j does not support detached Markers. Returned Marker %5B%7B%7D%5D will be unchanged.%22, name);%0A
         return g

Fix potential infinite loop in Marker cycles.