/*
 * @(#)MainApplet.java	1.0 11-Apr-07
 *
 * IIT Bombay, 
 * Licensed under a Creative Commons Attribution-Noncommercial-Share Alike 2.5 License.
 */
package classes.main;

import interfaces.IAppletGUIBuilder;
import interfaces.IColorFactory;
import interfaces.ICommandMediator;
import interfaces.IShape;
import interfaces.IShapeAbstractFactory;
import interfaces.IShapeContainerState;
import interfaces.IShapeDrawer;
import interfaces.IShapeFactory;
import interfaces.ShapeDecorator;

import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;

import types.Bounds;
import types.Command;
import types.ShapeCoordinates;
import classes.container.ShapeContainer;
import classes.container.ShapeContainerContext;
import classes.container.ShapeContainerCreator;
import classes.container.state.ShapeContainerEmptyState;
import classes.main.AppletControls;
import classes.main.components.ButtonBuilder;
import classes.main.components.ListBuilder;
import classes.shapes.CircleShape;
import classes.shapes.ColorShapeFactory;
import classes.shapes.RectangleShape;
import classes.shapes.ShapeFactory;
import classes.shapes.commands.CommandContainer;
import classes.shapes.commands.ShapeDrawCommands;
import classes.shapes.commands.ShapeGraphicsDrawer;
import classes.shapes.decorators.ColorDecorator;
import classes.shapes.decorators.ColorFactory;


/**
 * Main applet class coordinates all the operations 
 *
 * @author  Prathab, Mukesh
 * @version 1.0, 21-Mar-07
 */
public class MainApplet extends Applet implements ActionListener, MouseListener{
	ShapeContainer shapeContainer;
	ShapeContainerContext shapeContainerContext;
	ICommandMediator commandMediator;
	IShape lastCreatedShape;
	IShape selectedShape;
	IShape circleShape;
	Color lastCreatedColor = Color.white;
	
	Memento memento = new Memento();
	boolean isUndoOperation;
	
	//configuring the command processinf objects
	ShapeCoordinates containerCoordinates;
	ShapeCoordinates bufferShapeCoordinates;
	ShapeCoordinates defaultShapeCoordinates;
	ShapeCoordinates colorBufferCoordinates;
	
	IShapeDrawer shapeGraphicsDrawer = new ShapeGraphicsDrawer();
	ShapeDrawCommands shapeDrawCommands = new ShapeDrawCommands(shapeGraphicsDrawer);
	CommandContainer commandContainer = new CommandContainer();
	AppletPainter appletPainter = new AppletPainter(shapeDrawCommands, commandContainer);
	
	//Set the Controls type
	AppletControls uiControls = new AppletControls();

	Command msgCmd = new Command();
	
	public void init() {
		
		//Creating the container
		containerCoordinates = new ShapeCoordinates(20,20,200,200);
		commandMediator = commandContainer;
		shapeContainer = ShapeContainerCreator.createContainer(containerCoordinates,commandMediator);
		IShapeContainerState shapeContainerState = ShapeContainerEmptyState.getInstance(commandMediator);
		shapeContainerContext = new ShapeContainerContext(shapeContainer,shapeContainerState);
		shapeContainer.isPermanentShape = true;
		shapeContainer.drawShape();
		
		//Creating the buffer space shape
		bufferShapeCoordinates = new ShapeCoordinates(containerCoordinates.x + containerCoordinates.width + 100,
				containerCoordinates.y,containerCoordinates.height/2,containerCoordinates.width/2);
		IShape bufferShape = new RectangleShape(bufferShapeCoordinates,commandMediator);
		commandMediator.addObject(bufferShape);
		bufferShape.setAsPermanentShape(true);
		bufferShape.drawShape();
		
		defaultShapeCoordinates = new ShapeCoordinates(bufferShapeCoordinates.x + 15,
				 bufferShapeCoordinates.y +15, bufferShapeCoordinates.height - 30, bufferShapeCoordinates.width - 30);
		
		msgCmd.methodName = new String("MessageBoard");
		msgCmd.args = new String[1];
		
		//Creating a buffer space for color
		colorBufferCoordinates = new ShapeCoordinates(bufferShapeCoordinates.x + bufferShapeCoordinates.width + 10,
				bufferShapeCoordinates.y,20,20);
		circleShape = new CircleShape(colorBufferCoordinates,commandMediator);
		commandMediator.addObject(circleShape);
		circleShape.setAsPermanentShape(true);
		circleShape.drawShape();
		
	
		//Creating the controls
		setLayout(null);
		int x = bufferShapeCoordinates.x + bufferShapeCoordinates.width + 50;
		int y = bufferShapeCoordinates.y;
		
		IAppletGUIBuilder appletGUIBuilder= new ButtonBuilder();
		Bounds bounds = new Bounds(bufferShapeCoordinates.x - 15, 
				bufferShapeCoordinates.y + bufferShapeCoordinates.height + 15, 130, 30);
		appletGUIBuilder.build(bounds,uiControls.addToContainerButton,this,null);
		
		bounds = new Bounds(x,y,100, 25);
		ArrayList listOptions = new ArrayList();
		listOptions.add("Rectangle");
		listOptions.add("Circle");
		listOptions.add("Triangle");
		appletGUIBuilder = new ListBuilder();
		appletGUIBuilder.build(bounds,uiControls.shapeList,this,listOptions);

		listOptions.clear();
		listOptions.add("Black");
		listOptions.add("Blue");
		listOptions.add("Cyan");
		listOptions.add("Green");
		listOptions.add("Magenta");
		listOptions.add("Orange");
		listOptions.add("Pink");
		listOptions.add("Red");
		listOptions.add("Yellow");
		bounds = new Bounds(x+115,y,100,25);
		appletGUIBuilder = new ListBuilder();
		appletGUIBuilder.build(bounds,uiControls.colorList,this,listOptions);
		
		y+=35;
		bounds = new Bounds(x,y,100,30);
		appletGUIBuilder= new ButtonBuilder();
		appletGUIBuilder.build(bounds,uiControls.getShapeButton,this, null);
		bounds = new Bounds(x+115,y,100,30);
		appletGUIBuilder.build(bounds,uiControls.getColorButton,this, null);
		
		y+=35;
		bounds = new Bounds(x+30,y,150,30);
		appletGUIBuilder.build(bounds,uiControls.getColoredShapeButton,this,null);

		y+=45;
		appletGUIBuilder = new ListBuilder();
		bounds = new Bounds(x,y,100,25);
		listOptions.clear();
		listOptions.add("Fill color");
		appletGUIBuilder.build(bounds,uiControls.decoratorList,this,listOptions);

		y+=30;
		bounds = new Bounds(x,y,100,30);
		appletGUIBuilder= new ButtonBuilder();
		appletGUIBuilder.build(bounds,uiControls.decorateButton,this, null);
		
		y+=35;
		bounds = new Bounds(x,y,220,30);
		appletGUIBuilder.build(bounds,uiControls.cloneButton,this, null);
		y+=35;
		bounds = new Bounds(x,y,220,30);
		appletGUIBuilder.build(bounds,uiControls.undoButton,this, null);

		bounds = new Bounds(containerCoordinates.x + 30, 
				containerCoordinates.y + containerCoordinates.height + 15,150,30);
		appletGUIBuilder.build(bounds,uiControls.removeFromContainerButton,this,null);
		
		addMouseListener(this); 
	}
	
    public void paint(Graphics g){
    	shapeGraphicsDrawer.setGraphicsObject(g);
  		appletPainter.collectCommands();
    	appletPainter.paint();
	}
    
    public void actionPerformed(ActionEvent evt) 
    {
         if (evt.getSource() == uiControls.addToContainerButton){
        	 if(lastCreatedShape != null) {
        		 lastCreatedShape.setAsPermanentShape(false);
        		 repaint();
        		 lastCreatedShape.setAsPermanentShape(true);
        		 if(shapeContainerContext.addShape(lastCreatedShape)) lastCreatedShape = null;
        	 }
        	 else {
        		 msgCmd.methodName = new String("ErrorBoard");
        		 msgCmd.args[0] = new String("Buffer Space is empty. Get a shape and then add.");
        		 commandMediator.sendCommand(msgCmd, false);
        	 }
        	 repaint();
         }
         else if(evt.getSource() == uiControls.removeFromContainerButton){
        	 if(selectedShape != null) {
        		 commandMediator.removeObject(selectedShape);
        		 shapeContainerContext.removeShape(selectedShape);
        		 selectedShape = null;
        	 }
        	 else {
        		 msgCmd.methodName = new String("ErrorBoard");
        		 msgCmd.args[0] = new String("No shape is selcted. Select a shape from the container" +
        		 		" to remove");
        		 commandMediator.sendCommand(msgCmd, false);
        	 }
        	 repaint();
         }
         else if(evt.getSource() == uiControls.getShapeButton){
        	 IShape shape = getSelectedShape();
        	 if(shape != null) {
        		 shape.setAsPermanentShape(true);
        		 memento.setState(lastCreatedShape);
        		 if(lastCreatedShape != null) {
        			 commandMediator.removeObject(lastCreatedShape);
        		 }
        		 lastCreatedShape = shape;
        		 commandMediator.addObject(lastCreatedShape);
        		 repaint();
        	 }
         }
         else if(evt.getSource() == uiControls.getColorButton){
        	 lastCreatedColor = getSelectedColor();
        	 ShapeDecorator colorDecorator = new ColorDecorator(circleShape, lastCreatedColor);
        	 colorDecorator.setAsPermanentShape(true);
        	 commandMediator.removeObject(circleShape);
        	 commandMediator.addObject(colorDecorator);
        	 repaint();
         }
         else if(evt.getSource() == uiControls.getColoredShapeButton){
        	 String shapeName = uiControls.shapeList.getSelectedItem();
        	 String colorName = uiControls.colorList.getSelectedItem();
        	 IShapeAbstractFactory shapeAbstractFactory = new ColorShapeFactory();
        	 IShape shape = shapeAbstractFactory.getAbstractShape(shapeName,colorName,
        			 getDefaultCoordinates(),commandMediator);
        	 if(shape != null) {
        		 memento.setState(lastCreatedShape);
        		 if(lastCreatedShape != null) {
        			 commandMediator.removeObject(lastCreatedShape);
        		 }
        		 shape.setAsPermanentShape(true);
            	 lastCreatedShape = shape;
            	 commandMediator.addObject(lastCreatedShape);
        		 repaint();
        	 }
         }
         else if(evt.getSource() == uiControls.decorateButton){
        	 if(lastCreatedShape != null) {
        		 ShapeDecorator colorDecorator = new ColorDecorator(lastCreatedShape,lastCreatedColor);
            	 colorDecorator.setAsPermanentShape(true);
            	 memento.setState(lastCreatedShape);
            	 commandMediator.removeObject(lastCreatedShape);
            	 lastCreatedShape = colorDecorator;
            	 commandMediator.addObject(lastCreatedShape);
        	 }
        	 else {
        		 msgCmd.methodName = new String("ErrorBoard");
        		 msgCmd.args[0] = new String("Buffer Space is empty. Get a shape and then decorate.");
        		 commandMediator.sendCommand(msgCmd, false);
        	 }
        	 repaint();
         }
         else if(evt.getSource() == uiControls.cloneButton){
        	 if(selectedShape != null) {
        		 IShape cloneShape = (IShape) selectedShape.clone();
        		 cloneShape.changeShapeXYCoordinates(bufferShapeCoordinates.x + 15,
        				 bufferShapeCoordinates.y +15);
        		 memento.setState(lastCreatedShape);
        		 if(lastCreatedShape != null) commandMediator.removeObject(lastCreatedShape);
        		 lastCreatedShape = cloneShape;
        		 commandMediator.addObject(lastCreatedShape);
        	 }
        	 else {
        		 msgCmd.methodName = new String("ErrorBoard");
        		 msgCmd.args[0] = new String("No shape is selcted. Select a shape to clone");
        		 commandMediator.sendCommand(msgCmd, false);
        	 }
        	 repaint();
        	 
         }
         else if(evt.getSource() == uiControls.undoButton){
        	//isUndoOperation = true;
        	if(lastCreatedShape != null) commandMediator.removeObject(lastCreatedShape);
        	lastCreatedShape = memento.getState();
        	if(lastCreatedShape != null) commandMediator.addObject(lastCreatedShape);
        	repaint();
         }
    }
    
    /** Gets the user selected shape option
     * 
     * @return created <tt>IShape</tt> object
     */
    public IShape getSelectedShape() {
    	 String shapeName = uiControls.shapeList.getSelectedItem();
    	 IShapeFactory shapeFactory = new ShapeFactory();
    	 return shapeFactory.getShape(shapeName, getDefaultCoordinates(), commandMediator);
    }
    
    /**
     * Returns the default coordiantes for the shape object
     * @return new <tt>ShapeCoordinates</tt> object
     */
    public ShapeCoordinates getDefaultCoordinates() {
    	return new ShapeCoordinates(bufferShapeCoordinates.x + 15,
				 bufferShapeCoordinates.y +15, bufferShapeCoordinates.height - 30, bufferShapeCoordinates.width - 30);
    }
    
    /**
     * Gets the user selected color option
     * @return new <tt>Color</tt> object
     */
    public Color getSelectedColor() {
    	 String colorName = uiControls.colorList.getSelectedItem();
    	 IColorFactory colorFactory = new ColorFactory();
    	 return colorFactory.getColor(colorName);
	   	 
    }
    
    /**
     * Mouse action listener events
     */
    public void mouseClicked (MouseEvent event) {
    	  int xpos = event.getX();
    	  int ypos = event.getY();
    	  int widthInc = containerCoordinates.width/shapeContainer.NO_OF_COLS;
    	  int heightInc = containerCoordinates.height/shapeContainer.NO_OF_ROWS;
    	  //int xIndex = shapeContainer.NO_OF_ROWS - 1;
    	  int yIndex = shapeContainer.NO_OF_COLS - 1;
    	  
    	  selectedShape = null;
    	  for(int i=0, yw=0; i< shapeContainer.NO_OF_COLS; i++, yw+=heightInc)
    		  for(int j=0, xw=0; j< shapeContainer.NO_OF_ROWS;j++, xw+=widthInc) {
    			  if (xpos > containerCoordinates.x + xw && xpos < containerCoordinates.x + xw + widthInc 
    	    			  && ypos > containerCoordinates.y + yw && ypos < containerCoordinates.y + yw + heightInc) {
    	    		  selectedShape = shapeContainer.getShape((i* yIndex ) +(i+j));
    	    		  if(selectedShape != null) {
    	    			  msgCmd.methodName = new String("MessageBoard");
    	    			  msgCmd.args[0] = new String("The shape at " + (i+1) + " row and " + (j+1) + " column is selected");
    	    			  commandMediator.sendCommand(msgCmd, false);
    	    		  }
    	     		 repaint();
    	     		 break;
    	    	  }
    		  }
    } 
    public void mouseEntered(MouseEvent event) {
    }
    public void mouseExited(MouseEvent event) {
    }
    public void mousePressed(MouseEvent event) {
    }
    public void mouseReleased(MouseEvent event) {
    }
}
