package de.visone.nlpext.deprecated;

import y.base.Edge;
import y.base.Node;
import y.base.NodeCursor;
import y.view.Graph2D;
import y.view.NodeLabel;
import de.visone.attributes.AttributeInterface;
import de.visone.attributes.AttributeStructure.AttributeScope;
import de.visone.attributes.AttributeStructure.AttributeType;
import de.visone.base.Network;
import de.visone.gui.tabs.DefaultAttributeFactory;
import de.visone.util.Helper4Tasks;
import de.visone.util.LayoutUtils;
import de.visone.visualization.layout.stress2.interfaces.StressMajorizationLayouter;
import de.visone.visualization.layout.stress2.interfaces.StressMajorizationLayouter.ChangingStabilities;
import de.visone.visualization.layout.stress2.interfaces.StressMajorizationLayouter.LinkScheme;

/**
 * Utilities for graph layout.
 * 
 * @author <a href="mailto:endele@inf.uni-konstanz.de">Simon Endele</a>
 * @author matthias
 */
public class LayoutUtil extends de.visone.ext.NetworkUtil {
	private LayoutUtil() {
	}

	/**
	 * Scales the width and height of all nodes so that their area represent
	 * their centrality value.
	 */
	public static void scaleNodes(final Network network,
			final String centralityName, final double factor) {
		final AttributeInterface<Node> centrality = network
				.getNodeAttributeManager().getAttribute(centralityName);
		for (final NodeCursor nc = network.getGraph2D().nodes(); nc.ok(); nc
				.next()) {
			final Node node = nc.node();
			final double size = Math.max(1.0,
					Math.sqrt(centrality.getDouble(node)) * factor);
			network.getGraph2D().getRealizer(node).setSize(size, size);
		}
	}

	/**
	 * Stress majorization with the given target length.
	 * 
	 * @param majoX
	 *            define X coordinate
	 * @param majoX
	 *            define Y coordinate
	 * @param length
	 *            target edge length
	 */
	public static Layout getStressMajorization(final boolean majoX,
			final boolean majoY, final double length) {
		return new StressMajorization(majoX, majoY, null, false, length, -1);
	}

	/**
	 * Stress majorization with the target edge length given by an attribute,
	 * interpolating between min and max.
	 * 
	 * @param majoX
	 *            define X coordinate
	 * @param majoX
	 *            define Y coordinate
	 * @param attribute
	 *            target edge length attribute
	 * @param min
	 *            length of shortest edge (smallest attribute value)
	 * @param max
	 *            length of longest edge (largest attribute value)
	 */
	public static Layout getStressMajorization(final boolean majoX,
			final boolean majoY, final String attribute, final double min,
			final double max) {
		return new StressMajorization(majoX, majoY, attribute, true, min, max);
	}

	/**
	 * Stress majorization with the target edge length directly given by an
	 * attribute, which shouldn't contain negative values.
	 * 
	 * @param majoX
	 *            define X coordinate
	 * @param majoX
	 *            define Y coordinate
	 * @param attribute
	 *            target edge length attribute
	 */
	public static Layout getStressMajorization(final boolean majoX,
			final boolean majoY, final String attribute) {
		return new StressMajorization(majoX, majoY, attribute, false, -1, -1);
	}

	/** Default (quick) layout. */
	public static Layout getDefault() {
		return new Layout() {
			@Override
			public void layout(final Network network) {
				LayoutUtils.doDefaultLayout(network);
			}
		};
	}

	public static abstract class Layout {
		public abstract void layout(final Network network);
	}

	private static class StressMajorization extends Layout {
		private final StressMajorizationLayouter algorithm;

		private StressMajorization(final boolean majoX, final boolean majoY,
				final String attribute, final boolean interp, final double min,
				final double max) {
			algorithm = new StressMajorizationLayouter();
			algorithm.setLayoutComponentsSeparately(true);
			algorithm.setProcrustes(false);
			algorithm.setStability(0, 0, ChangingStabilities.NONE);
			algorithm.setHold(false, false);
			if (attribute != null) {
				algorithm.setLinkLengthScheme(LinkScheme.ATTRIBUTE_VALUE, -1,
						new DefaultAttributeFactory<AttributeInterface<Edge>>(
								attribute, AttributeType.Decimal,
								AttributeScope.EDGE));
				algorithm.setInterpolateEdgeLengths(interp, min, max);
			} else {
				algorithm.setLinkLengthScheme(LinkScheme.UNIFORM, min, null);
				algorithm.setInterpolateEdgeLengths(false, 0, 0);
			}
			algorithm.setKeep(!majoX, !majoY);
		}

		@Override
		public void layout(final Network network) {
			algorithm.setNetwork(network);
			algorithm.doLayout(network.getGraph2D());
		}
	}

	/** Place each node label in the center of its node. */
	public static void centerLabels(final Network network) {
		for (final NodeCursor nc = network.getGraph2D().nodes(); nc.ok(); nc
				.next()) {
			final Node node = nc.node();
			network.getGraph2D().getRealizer(node).getLabel()
					.setModel(NodeLabel.INTERNAL);
			network.getGraph2D().getRealizer(node).getLabel()
					.setPosition(NodeLabel.CENTER);
		}
	}
}
