/*
 * Copyright 2016 Deutsche Nationalbibliothek
 *
 * 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.culturegraph.mf.stream.pipe;

import org.culturegraph.mf.framework.DefaultStreamPipe;
import org.culturegraph.mf.framework.StreamReceiver;
import org.culturegraph.mf.framework.annotations.Description;
import org.culturegraph.mf.framework.annotations.FluxCommand;
import org.culturegraph.mf.framework.annotations.In;
import org.culturegraph.mf.framework.annotations.Out;
import org.culturegraph.mf.stream.sink.EntityPathTracker;

/**
 * Flattens all entities in a stream by prefixing the literals with the entity
 * paths. The stream emitted by this module is guaranteed to not contain any
 * <i>start-entity</i> and <i>end-entity</i> events.
 *
 * <p>For example, take the following sequence of events:
 * <pre>{@literal
 * start-record "1"
 * literal "toplevel": literal-value
 * start-entity "entity"
 * literal "nested": literal-value
 * end-entity
 * end-record
 * }</pre>
 *
 * These events are transformed by the {@code StreamFlattener} into the
 * following sequence of events:
 * <pre>{@literal
 * start-record "1"
 * literal "toplevel": literal-value
 * literal "entity.nested": literal-value
 * end-record
 * }</pre>
 *
 * @author Christoph Böhme (rewrite)
 * @author Markus Michael Geipel
 * @see EntityPathTracker
 *
 */
@Description("flattens out entities in a stream by introducing dots in literal names")
@In(StreamReceiver.class)
@Out(StreamReceiver.class)
@FluxCommand("flatten")
public final class StreamFlattener extends DefaultStreamPipe<StreamReceiver> {

	public static final String DEFAULT_ENTITY_MARKER = ".";

	private static final String ENTITIES_NOT_BALANCED =
			"Entity starts and ends are not balanced";

	private final EntityPathTracker pathTracker = new EntityPathTracker();

	public StreamFlattener() {
		setEntityMarker(DEFAULT_ENTITY_MARKER);
	}

	public String getEntityMarker() {
		return pathTracker.getEntitySeparator();
	}

	public void setEntityMarker(final String entityMarker) {
		pathTracker.setEntitySeparator(entityMarker);
	}

	@Override
	public void startRecord(final String identifier) {
		assert !isClosed();
		pathTracker.startRecord(identifier);
		getReceiver().startRecord(identifier);
	}

	@Override
	public void endRecord() {
		assert !isClosed();
		if (pathTracker.getCurrentEntityName() != null) {
			// TODO: Remove this check in 4.0.0. We assume well-formedness
			throw new IllegalStateException(ENTITIES_NOT_BALANCED);
		}
		pathTracker.endRecord();
		getReceiver().endRecord();
	}

	@Override
	public void startEntity(final String name) {
		assert !isClosed();
		pathTracker.startEntity(name);
	}

	@Override
	public void endEntity() {
		assert !isClosed();
		if (pathTracker.getCurrentEntityName() == null) {
			// TODO: Remove this check in 4.0.0. We assume well-formedness
			throw new IllegalStateException(ENTITIES_NOT_BALANCED);
		}
		pathTracker.endEntity();
	}

	@Override
	public void literal(final String name, final String value) {
		assert !isClosed();
		getReceiver().literal(pathTracker.getCurrentPathWith(name), value);
	}

	public String getCurrentEntityName() {
		return pathTracker.getCurrentEntityName();
	}

	public String getCurrentPath() {
		return pathTracker.getCurrentPath();
	}

}

@@ -602,17 +602,16 @@
 se.%0A */%0A
-%0A
 package 
@@ -1262,15 +1262,16 @@
 .%0A *
+ %3Cp%3E
 %0A * 
-%3Cp%3E
 For 
@@ -1363,32 +1363,33 @@
 %0A * literal %22top
+-
 level%22: literal-
@@ -1654,16 +1654,17 @@
 ral %22top
+-
 level%22: 
@@ -2156,108 +2156,8 @@
 %22;%0A%0A
-%09private static final String ENTITIES_NOT_BALANCED =%0A%09%09%09%22Entity starts and ends are not balanced%22;%0A%0A
 %09pri
@@ -2724,189 +2724,8 @@
 ();%0A
-%09%09if (pathTracker.getCurrentEntityName() != null) %7B%0A%09%09%09// TODO: Remove this check in 4.0.0. We assume well-formedness%0A%09%09%09throw new IllegalStateException(ENTITIES_NOT_BALANCED);%0A%09%09%7D%0A
 %09%09pa
@@ -2960,189 +2960,8 @@
 ();%0A
-%09%09if (pathTracker.getCurrentEntityName() == null) %7B%0A%09%09%09// TODO: Remove this check in 4.0.0. We assume well-formedness%0A%09%09%09throw new IllegalStateException(ENTITIES_NOT_BALANCED);%0A%09%09%7D%0A
 %09%09pa

Remove balanced entities check