package sim.lib.wires;

import java.awt.*;

import sim.*;
import sim.engine.*;

public class Junction extends WrapperPainted implements NodeModule
{
/* ==================================================================
	Creation Part
	================================================================= */
	public Image getIcon()
	{
		return null;
	}
	
	public Wrapper createWrapper()
	{
		return null;
	}
	
	public Wrapper createWrapper(Point gridPosition)
	{
		return null;
	}
	
	public String getBubbleHelp()
	{
		return null;
	}
	
/* ==================================================================
	GUI part
	================================================================= */
	public Junction(int nodes)
	{
		super();
		this.setNumberOfNodes(nodes);
		this.setVisible(false);
	}
	
	public void initializeGridSize()
	{
		this.gridSize.width = 0;
		this.gridSize.height = 0;
		this.setSize(Wire.THICKNESS, Wire.THICKNESS);
	}
	
	public void setGridLocation(int x, int y)
	{
		this.gridLocation.x = x;
		this.gridLocation.y = y;
		int increment = Wire.THICKNESS / 2;
		
		int size = CentralPanel.ACTIVE_GRID.getCurrentGridGap();
		
		this.setLocation(x * size - increment, y * size - increment);
	}
	
	public void setGridSize(int gridWidth, int gridHeight)
	{
		this.gridSize.width = 0;
		this.gridSize.height = 0;
		this.setSize(Wire.THICKNESS, Wire.THICKNESS);
	}

	public void paint(Graphics g)
	{	
		// draw if visible
		if(this.isVisible())
		{
			g.setColor(this.brush);
			
			if(this.getNumberOfNodes() == 1)
			{
				g.fillRect(2, 1 , 3, 5);
				g.fillRect(1, 2 , 5, 3);
			}
			else
			{
				g.fillRect(1, 0 , 5, 7);
				g.fillRect(0, 1 , 7, 5);
			}
		}
	}
	
/* ==================================================================
	Maintanance Part
	================================================================= */
	private Wire up = null;
	private Wire down = null;
	private Wire left = null;
	private Wire right = null;
	private int wires = 0;
	private int pins = 0;
	
	private int numberOfNodes = 0;
	
	public int getNumberOfNodes()
	{
		return this.numberOfNodes;
	}
	
	private void setNumberOfNodes(int value)
	{
		this.numberOfNodes = value;
	}
	
	public boolean isFull()
	{
		return (this.wires == 4);
	}
	
	public boolean wireOnRight()
	{
		return (this.right != null);
	}
	
	public boolean wireOnLeft()
	{
		return (this.left != null);
	}
	
	public boolean wireAbove()
	{
		return (this.up != null);
	}
	
	public boolean wireBelow()
	{
		return (this.down != null);
	}
	
	public void configure()
	{
		if(this.wires + this.pins > 2)
		{
			this.setVisible(true);
			CentralPanel.ACTIVE_GRID.paintComponent(this);
		}
		else
		{
			CentralPanel.ACTIVE_GRID.eraseComponent(this);
			this.setVisible(false);
		}
	}
	
	public void setWireAbove(Wire w)
	{
		if(this.up == null)
			this.wires++;
		this.up = w;
	}
	
	public void setWireBelow(Wire w)
	{
		if(this.down == null)
			this.wires++;
		this.down = w;
	}
	
	public void setWireOnRight(Wire w)
	{
		if(this.right == null)
			this.wires++;
		this.right = w;
	}
	
	public void setWireOnLeft(Wire w)
	{
		if(this.left == null)
			this.wires++;
		this.left = w;
	}
	
	public void resetWireAbove()
	{
		if(this.up != null)
			this.wires--;
		this.up = null;
	}
	
	public void resetWireBelow()
	{
		if(this.down != null)
			this.wires--;
		this.down = null;
	}
	
	public void resetWireOnRight()
	{
		if(this.right != null)
			this.wires--;
		this.right = null;
	}
	
	public void resetWireOnLeft()
	{
		if(this.left != null)
			this.wires--;
		this.left = null;
	}
	
	public Wire getWireOnLeft()
	{
		return this.left;
	}
	
	public Wire getWireAbove()
	{
		return this.up;
	}
	
	public Wire getWireBelow()
	{
		return this.down;
	}
	
	public Wire getWireOnRight()
	{
		return this.right;
	}
	
	public void addPin()
	{
		this.pins++;
	}
	
	public void removePin()
	{
		this.pins--;
	}
	
	public void check()	// after removing component or adding wire check whether to remove junction
	{
		if(this.pins == 0)
		{
			if(this.wires == 0)
				CentralPanel.ACTIVE_GRID.removeModule(this);
			else if((this.wires == 2) && (this.up == this.down))
			{
				this.left.mergeWith(this.right);
				this.left = null;
				this.right = null;
				CentralPanel.ACTIVE_GRID.removeModule(this);
			}
			else if((this.left == this.right) && (this.wires == 2))
			{
				this.up.mergeWith(this.down);
				this.up = null;
				this.down = null;
				CentralPanel.ACTIVE_GRID.removeModule(this);
			}
			else
				this.configure();
		}
		else
			this.configure();
	}
	
	public boolean canDrop()
	{
		return true;
	}
	
	public void dropedOnWire(Wire w)
	{
		w.breakAt(this);
		
		if(w.isHorizontal())
		{
			w = w.getOverlapedVerticalWire(this.gridLocation);
			
			if(w != null)
				w.breakAt(this);
		}
		else
		{
			w = w.getOverlapedHorizontalWire(this.gridLocation);
			if(w != null)
				w.breakAt(this);
		}
		
		this.setVisible(true);
		CentralPanel.ACTIVE_GRID.addModule(this, true);
	}
	
	public void droped()
	{
		CentralPanel.ACTIVE_GRID.addModule(this, false);
	}
	
	public void selected()
	{
	}
	
	public void checkAfterSelected()
	{
	}
	
/* ==================================================================
	Simulation part
	================================================================= */
	private NodeList peer = null;
	
	public void createNode(NodeList nodes)
	{
		Node created;
		int loop;
		
		if(this.peer == null)
		{
			this.peer = new NodeList();
			
			for(loop = 0; loop < this.numberOfNodes; loop++)
			{
				created = new Node();
				created.addJunction(this);
				this.peer.insertItem(created);
				nodes.insertItem(created);
			}
			
			if(this.up != null)
			{
				for(loop = 0; loop < this.numberOfNodes; loop++)
					this.peer.getItemAt(loop).addWire(this.up);
				
				this.up.getStart().propogate(this.peer, this.up);
			}
		
			if(this.down != null)
			{
				for(loop = 0; loop < this.numberOfNodes; loop++)
					this.peer.getItemAt(loop).addWire(this.down);
				
				this.down.getEnd().propogate(this.peer, this.down);
			}
		
			if(this.left != null)
			{
				for(loop = 0; loop < this.numberOfNodes; loop++)
					this.peer.getItemAt(loop).addWire(this.left);
				
				this.left.getStart().propogate(this.peer, this.left);
			}
		
			if(this.right != null)
			{
				for(loop = 0; loop < this.numberOfNodes; loop++)
					this.peer.getItemAt(loop).addWire(this.right);
				
				this.right.getEnd().propogate(this.peer, this.right);
			}
		}
	}
	
	private void propogate(NodeList n, Wire source)
	{
		int loop;
		
		if(this.peer == null)
		{
			this.peer = n;
			
			for(loop = 0; loop < this.numberOfNodes; loop++)
				this.peer.getItemAt(loop).addJunction(this);
			
			if(this.up != null)
				if(this.up != source)
				{
					for(loop = 0; loop < this.numberOfNodes; loop++)
						this.peer.getItemAt(loop).addWire(this.up);
					
					this.up.getStart().propogate(n, this.up);
				}
			
			if(this.down != null)
				if(this.down != source)
				{
					for(loop = 0; loop < this.numberOfNodes; loop++)
						this.peer.getItemAt(loop).addWire(this.down);
					
					this.down.getEnd().propogate(n, this.down);
				}
			
			if(this.left != null)
				if(this.left != source)
				{
					for(loop = 0; loop < this.numberOfNodes; loop++)
						this.peer.getItemAt(loop).addWire(this.left);
					
					this.left.getStart().propogate(n, this.left);
				}
			
			if(this.right != null)
				if(this.right != source)
				{
					for(loop = 0; loop < this.numberOfNodes; loop++)
						this.peer.getItemAt(loop).addWire(this.right);
					
					this.right.getEnd().propogate(n, this.right);	
				}
		}
	}
	
	public void propogate(NodeList n)
	{
		int loop;
		
		if(this.peer == null)
		{
			this.peer = n;		
			if(this.up != null)
			{
				for(loop = 0; loop < this.numberOfNodes; loop++)
					this.peer.getItemAt(loop).addWire(this.up);
				
				this.up.getStart().propogate(n, this.up);
			}
			
			if(this.down != null)
			{
				for(loop = 0; loop < this.numberOfNodes; loop++)
					this.peer.getItemAt(loop).addWire(this.down);
				
				this.down.getEnd().propogate(n, this.down);
			}
			
			if(this.left != null)
			{
				for(loop = 0; loop < this.numberOfNodes; loop++)
					this.peer.getItemAt(loop).addWire(this.left);
				
				this.left.getStart().propogate(n, this.left);
			}
			
			if(this.right != null)
			{
				for(loop = 0; loop < this.numberOfNodes; loop++)
					this.peer.getItemAt(loop).addWire(this.right);
				
				this.right.getEnd().propogate(n, this.right);	
			}
		}
	}
	
	public void reset()
	{
		this.peer = null;
	}
	
	public NodeList getNodes()
	{
		return this.peer;
	}
	
	public void setNodes(NodeList nl){
		this.peer = nl;
	}
/* ==================================================================
	Storage Part
	================================================================= */
	public String getSpecificParameters()
	{
		return null;
	}
	
	public void loadWrapper(String[] specificParameters) throws SimException
	{
	}
	
	public int getNumberOfSpecificParameters()
	{
		return 0;
	}
}
