content: /**
   * Copyright 2020 Alexander Herzog
   *
   * 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 ui.modeleditor.templates;
  
  import java.awt.Point;
  import java.io.ByteArrayInputStream;
  import java.io.ByteArrayOutputStream;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.stream.Collectors;
  
  import ui.modeleditor.ModelSurface;
  import ui.modeleditor.coreelements.ModelElement;
  import ui.modeleditor.coreelements.ModelElementEdgeMultiIn;
  import ui.modeleditor.coreelements.ModelElementEdgeMultiOut;
  import ui.modeleditor.coreelements.ModelElementEdgeOut;
  import ui.modeleditor.elements.ModelElementEdge;
  
  /**
   * Diese Klasse stellt statische Hilfsroutinen zum Umgang mit den Elementenvorlagen
   * bereit. Diese Klasse kann nicht instanziert werden.
   * @author Alexander Herzog
   * @see UserTemplate
   */
  public class UserTemplateTools {
  	/**
  	 * Konstruktor der Klasse.<br>
  	 * Kann nicht aufgerufen werden. Diese Klasse stellt nur statische Methoden bereit.
  	 */
  	private UserTemplateTools() {
  	}
  
  	/**
  	 * Fgt mehrere Kanten zu einer Elementenliste hinzu (sofern diese in der Liste noch nicht enthalten sind)
  	 * @param edges	Hinzuzufgende Kanten
  	 * @param elements	Liste mit Elementen
  	 */
  	private static void addEdges(final ModelElementEdge[] edges, final List<ModelElement> elements) {
  		for (ModelElementEdge edge: edges) addEdge(edge,elements);
  	}
  
  	/**
  	 * Fgt eine Kante zu einer Elementenliste hinzu (sofern sie in dieser noch nicht enthalten ist)
  	 * @param edge	Hinzuzufgende Kante
  	 * @param elements	Liste mit Elementen
  	 */
  	private static void addEdge(final ModelElementEdge edge, final List<ModelElement> elements) {
  		if (!elements.contains(edge)) elements.add(edge);
  	}
  
  	/**
  	 * Speichert eine Anzahl an Elementen in einem Stream
  	 * @param surface	Zeichenoberflche aus der ggf. weitere Kanten entnommen werden
  	 * @param copyElements	Elemente der Zeichenflche (direkt, keine Clone), die kopiert werden sollen
  	 * @return	Stream bestehend aus den zu kopierenden Elementen
  	 */
  	public static ByteArrayInputStream getElements(final ModelSurface surface, final List<ModelElement> copyElements) {
  		/* Kanten ergnzen */
  		final List<ModelElement> elements1=new ArrayList<>();
  		for (ModelElement element: copyElements) {
  			if (elements1.contains(element)) continue;
  			elements1.add(element);
  			if (element instanceof ModelElementEdgeMultiIn) addEdges(((ModelElementEdgeMultiIn)element).getEdgesIn(),elements1);
  			if (element instanceof ModelElementEdgeMultiOut) addEdges(((ModelElementEdgeMultiOut)element).getEdgesOut(),elements1);
  			if (element instanceof ModelElementEdgeOut) addEdge(((ModelElementEdgeOut)element).getEdgeOut(),elements1);
  		}
  
  		/* Kanten entfernen, die nicht zwischen zwei enthaltenen Elementen sind */
  		final List<ModelElement> elements2=new ArrayList<>();
  		final List<Integer> ids=elements1.stream().map(element->element.getId()).collect(Collectors.toList());
  		for (ModelElement element: elements1) {
  			if (element instanceof ModelElementEdge) {
  				final ModelElementEdge edge=(ModelElementEdge)element;
  				if (edge.getConnectionStart()==null || !ids.contains(edge.getConnectionStart().getId())) continue;
  				if (edge.getConnectionEnd()==null || !ids.contains(edge.getConnectionEnd().getId())) continue;
  			}
  			elements2.add(element);
  		}
  
  		/* Elemente in Stream kopieren */
  		final ByteArrayOutputStream outputStream=surface.getTransferData(elements2);
  		return new ByteArrayInputStream(outputStream.toByteArray());
  	}
  
  	/**
  	 * Fgt die Elemente aus einem Stream in die Zeichenflche ein
  	 * @param inputStream	Stream, der die Elemente enthlt
  	 * @param surface	Zeichenflche auf der die Elemente eingefgt werden sollen
  	 */
  	public static void copyToSurface(final ByteArrayInputStream inputStream, final ModelSurface surface) {
  		surface.setTransferData(inputStream,new Point(50,50),1.0);
  	}
  
  	/**
  	 * bertrgt eine Reihe von Elementen aus einer Zeichenoberflche in ein Vorlageelement
  	 * @param surface	Ausgangszeichenflche
  	 * @param copyElements	Liste der zu bertragenden Elemente (keine Kopien, sondern die Elemente, die in <code>surface</code> enthalten sind)
  	 * @param template	Vorlage in die die Elemente als Kopien bertragen werden sollen
  	 */
  	public static void copyToTemplate(final ModelSurface surface, final List<ModelElement> copyElements, final UserTemplate template) {
  		final ByteArrayInputStream inputStream=getElements(surface,copyElements);
  		copyToTemplate(inputStream,template);
  	}
  
  	/**
  	 * bertrgt eine Reihe von Elementen aus einem Stream in ein Vorlageelement
  	 * @param inputStream	Stream, aus dem die Elemente geladen werden sollen
  	 * @param template	Vorlage in die die Elemente bertragen werden sollen
  	 */
  	public static void copyToTemplate(final ByteArrayInputStream inputStream, final UserTemplate template) {
  		final ModelSurface templateSurface=template.getSurface();
  		copyToSurface(inputStream,templateSurface);
  	}
  
  	/**
  	 * Liefert die Elemente einer Zeichenoberflche in einer Form, in der sie in die reale Zeichenflche eingefgt werden knnen.
  	 * @param surface	Zeichenoberflche deren Elemente bertragen werden sollen
  	 * @return	Element im Zwischenablagenformat
  	 */
  	public static ByteArrayInputStream getAllElements(final ModelSurface surface) {
  		surface.setSelectedAreaAll();
  		final ByteArrayOutputStream outputStream=surface.getTransferData();
  		return new ByteArrayInputStream(outputStream.toByteArray());
  	}
  
  	/**
  	 * Liefert die Elemente einer Vorlage in einer Form, in der sie in die reale Zeichenflche eingefgt werden knnen.
  	 * @param template	Vorlage deren Elemente in die reale Zeichenflche eingetragen werden sollen
  	 * @return	Element im Zwischenablagenformat
  	 */
  	public static ByteArrayInputStream getAllElements(final UserTemplate template) {
  		final ModelSurface templateSurface=template.getSurface();
  		return getAllElements(templateSurface);
  	}
  }