package gd.module;


import java.util.Random;

import y.base.Edge;
import y.base.EdgeCursor;
import y.base.Node;
import y.layout.BufferedLayouter;
import y.layout.random.RandomLayouter;
import y.module.YModule;
import y.option.OptionHandler;
import y.view.Arrow;
import y.view.Graph2D;


/**
 * This class implements a module for the generation of branching
 * alkane molekules C_j H_{2j+2}.
 */
public class AlkaneGeneratorModule extends YModule
{
	public AlkaneGeneratorModule()
	{
		super("Alkane Generator",
			"Krists Boitmanis",
			"Creates a graph representing an alkane of the form C_j H_{2j+2}.");
	}

	
	/**
	 * This method is the main entry point of this module.
	 */
	protected void mainrun()
	{
		Graph2D graph = this.getGraph2D();

		// Remove existing nodes and edges.
		graph.clear();

		// Create the structure of a random alkane.
		this.generateAlkane();

		// Draw the graph.
		new BufferedLayouter(new RandomLayouter()).doLayout(graph);
		
		// The graph is supposed to be undirected,
		// so we don't show the arrow heads of edges.
		
		for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next())
		{
			Edge edge = ec.edge();
			graph.getRealizer(edge).setArrow(Arrow.NONE);
		}
		
		// Center the graph in the view.
		
		graph.updateViews();
		this.fitGraph2DView();
	}
	
	
	/**
	 * This method creates an option handler for interactive
	 * specification of the number of carbon atoms.
	 */
	public OptionHandler createOptionHandler()
	{
		OptionHandler handler = new OptionHandler(this.getModuleName());
		
		handler.addInt(NUMBER_OF_CARBON_ATOMS,
			DEFAULT_NUMBER_OF_CARBON_ATOMS,
			MIN_NUMBER_OF_CARBON_ATOMS,
			MAX_NUMBER_OF_CARBON_ATOMS);
		
		return handler;
	}
	
	
	/**
	 * This method generates a random alkane. 
	 */
	private void generateAlkane()
	{
		Graph2D graph = this.getGraph2D();
		
		// Ask for the number of carbon atoms.
		
		int numberOfCarbonAtoms =
			this.getOptionHandler().getInt(NUMBER_OF_CARBON_ATOMS);
		
		// First create the carbon atoms.
		
		Node[] carbonAtoms = new Node[numberOfCarbonAtoms];
		
		for (int i = 0; i < numberOfCarbonAtoms; i++)
		{
			carbonAtoms[i] = graph.createNode();
			
			// Connect the atom to one of the already created atoms, if any.
			
			if (i >= 1)
			{
				// Choose an arbitrary neighbor with a free bond. 
				
				Node neighbor;
				
				do
				{
					neighbor = carbonAtoms[this.random.nextInt(i)];
				}
				while (neighbor.degree() >= 4);

				// Establish the bond.
				graph.createEdge(carbonAtoms[i], neighbor);
			}
		}

		// Now create the hydrogen atoms and connect each of them to
		// one of the carbon atoms.

		for (int i = 0; i < 2 * numberOfCarbonAtoms + 2; i++)
		{
			Node hydrogenAtom = graph.createNode();
			Node carbonAtom;
			
			do
			{
				carbonAtom = carbonAtoms[this.random.nextInt(numberOfCarbonAtoms)];
			}
			while (carbonAtom.degree() >= 4);
			
			graph.createEdge(hydrogenAtom, carbonAtom);
		}
	}
	
	
	private Random random = new Random();
	
	private static final String NUMBER_OF_CARBON_ATOMS = "Number of carbon atoms";
	private static final int DEFAULT_NUMBER_OF_CARBON_ATOMS = 10;
	private static final int MIN_NUMBER_OF_CARBON_ATOMS = 1;
	private static final int MAX_NUMBER_OF_CARBON_ATOMS = 100;
}

