import javax.swing.JFrame;
import javax.swing.JTabbedPane;
import javax.swing.JPanel;
import javax.swing.JMenuItem;
import javax.swing.JFileChooser;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Color;
import java.awt.Point;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentListener;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.awt.Robot;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.AWTException;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.awt.print.PageFormat;

/**
 * This is the control class where everything comes together. The menubar, 
 * tabbed pane, the color box and the color pallettes are all created here.
 * Special fields are kept here to keep track of whats going on.
 **/
public class ControlClass extends JFrame implements ActionListener, ComponentListener
{
	public static int fileCount, currentFile, xCoord, yCoord, extraY, numFiles;
	public static SubToolBox sBox;
	public static ArrayList canvas;
	private GridBagLayout layout;
	private GridBagConstraints c;
	private File file;
	private ColorPanel colorPanel;
	private ColorBox pallette;
	private JPaintLayoutManager layoutManager;
	private JPaintFileChooser fileChooser; 
	private MainMenu mainMenu;
	private TabbedPanel tabbedCanvasHolder;
	private ToolBar tBar;
	
	/** 
	 * Default ControlClass constructor.
	 * Calls run(), which initializes all necessay objects in the ControlClass
	 **/
	public ControlClass()
	{
		setExtendedState(JFrame.MAXIMIZED_BOTH);
		run();
	}
	
	/**	
	 * Calls initAll(), and creates a new BufferedStrategy for the DrawingCanvas 
	 * with two buffers.
	 **/
	public void run()
	{
		initAll();
		((DrawingCanvas)canvas.get(0)).createBufferStrategy(2);
		extraY = 71;
		((DrawingCanvas)canvas.get(0)).checkScreenSize();
		setXY();
	}
	
	/**	
	 * Instantiates JPaints custom layout manager.
	 * Places the toolBox on the left side of the window
	 * and strecthes it vertically.
	 * Places the colorPallete at the bottom of the window and 
	 * stretches it horizontally.
	 * Places the subToolBox inside the toolBox near the top.
	 * Places the tabbedCanvasHolder in all the space left over
	 * and places the DrawingCanvas inside the tabbedCanvasHolder, filling
	 * all avaialbe space 
	 **/
	public void initLayout()
	{
		layoutManager = new JPaintLayoutManager();
		layoutManager.setComponent(sBox, 0,1, 1, 0, 100, 0, 0,0, GridBagConstraints.VERTICAL);
		getContentPane().add(sBox);
		layoutManager.setComponent(tBar, 0,0, 1,0, 100,0, 0,0, GridBagConstraints.VERTICAL);
		layoutManager.setAnchor(GridBagConstraints.LINE_START);
		getContentPane().add(tBar);
		layoutManager.setComponent(tabbedCanvasHolder, 1 ,0, GridBagConstraints.REMAINDER,GridBagConstraints.RELATIVE, 800,600, 1, 1, GridBagConstraints.HORIZONTAL);
		getContentPane().add(tabbedCanvasHolder);
  		layoutManager.setComponent(pallette, 1, 1, GridBagConstraints.REMAINDER,1, 350, 100, 0,0,  GridBagConstraints.HORIZONTAL);
		layoutManager.setAnchor(GridBagConstraints.LAST_LINE_START);
		getContentPane().add(pallette);		
	}	
	
	/** Instantiates the fileChooser **/
	public void initFileChooser()
	{
		fileChooser = new JPaintFileChooser(this);
	}
	
	/** Instantiates the tool bar **/
	public void initToolBar()
	{
		tBar = new ToolBar();
		tBar.setSize(200, 200);
		tBar.setBackground(Color.WHITE);
	}
	
	/** Instantiates the subToolBox **/
	public void initSubToolBox()
	{
		sBox = new SubToolBox();
		sBox.setBackground(Color.WHITE);
	}
	
	/** Instantiates the layoutManager **/
	public void initLayoutManager()
	{
		layout = new GridBagLayout();
		c = new GridBagConstraints();
	 
	 	getContentPane().setLayout(layout);
		getContentPane().add(tabbedCanvasHolder);
	}
	
	/** 
	 * Instantiates the tabbedCanvasHolder with one tab.
	 * Tabs are positioned at the Top. Calls initFirstCanvas(). Then adds
	 * the canvas to the tabbedCanvasHolder 
	 **/
	public void initTabbedCanvasHolder()
	{
		initFirstCanvas();

		// instantiate the canvasHolder and add the initial canvas to it
		tabbedCanvasHolder = new TabbedPanel(JTabbedPane.TOP);
		tabbedCanvasHolder.add((DrawingCanvas)canvas.get(0));
	}
	
	/** 
	 * Instantiates the DrawingCanvas.
	 * Sets its name to "untitled"+ fileCount, a static int which is also 
	 * incremented by one in this method. 
	 **/
	public void initFirstCanvas()
	{
		canvas = new ArrayList();
		DrawingCanvas tempCanvas = new DrawingCanvas();
		tempCanvas.setName("untitled-"+fileCount);
	  	tempCanvas.setBackground(Color.WHITE);
		canvas.add(tempCanvas);
	  	fileCount++;
		numFiles++;
	}
	
	/** Instantiates the colorBox **/
	public void initPallette()
	{
		pallette = new ColorBox();
	}	
	
	/** Instantiates the colorPanel **/
	public void initColorPanel()
	{
		colorPanel = new ColorPanel();
	}
	
	/** Instantiates the MainMenu, which is JPaints menu bar. **/
	public void initMenuBar()
	{
		mainMenu = new MainMenu();
		mainMenu.addActionListener(this);
		setJMenuBar(mainMenu);
	}
	
	/** 
	 * Initializes the frame by setting its title, size, location, listeners, 
	 * and other default attributes.
	 **/
	public void initFrame()
	{
		setTitle(".: JPaint :.");
		getContentPane().setLayout(layoutManager);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setSize(300, 600);
		setLocation(0,0);
		addComponentListener(this);
		setVisible(true);
		setXY();
	}
	
	/**
	 * This code checks sets the X and Y coords of where the drawing canvas
	 * begins.
	 **/
	public void setXY()
	{
		xCoord = tBar.getWidth() + 6;
    	yCoord = extraY;
	}
	
	/** Calls all instantiating methods thereby instantiating all objects. **/
	public void initAll()
	{
		initTabbedCanvasHolder();
		initToolBar();
		initSubToolBox();
		initColorPanel();
		initPallette();
		initLayout();
		initFileChooser();
		initMenuBar();
		initFrame();
	}
		
	/** 
	 * Reveals the fileOpen dialog. 
	 * Retrieves the pathname of the selected file and calls openOperation(path) 
	 * to display the image to th current canvas.
	 **/	
	public void showFileOpen()
	{
		int returnVal = fileChooser.showOpenDialog(this);
		if(returnVal == JFileChooser.APPROVE_OPTION)
		{
			String path = fileChooser.getSelectedFile().getPath();
			((DrawingCanvas)canvas.get(currentFile)).openOperation(path);
			}
		}

	/** Allows user to print the image on the screen through any available printer. **/
	public void printImage()
	{
		((DrawingCanvas)canvas.get(currentFile)).saveImageForPrinting();
		PrinterJob printJob = PrinterJob.getPrinterJob();
		PageFormat pf = printJob.pageDialog(printJob.defaultPage());
		printJob.setPrintable(((DrawingCanvas)canvas.get(currentFile)));
		if(printJob.printDialog()) 
			try{printJob.print();}catch(PrinterException pe){ pe.printStackTrace();}
	}
	
	/** 
	 * Saves the image on the current canvas to a user specified path with 
	 * the .png extension if the image has not previously been saved.
	 * Otherwise, updates the current file.
	 **/
	public void saveImage()
	{
		try
		{
			DrawingCanvas dc = ((DrawingCanvas)canvas.get(currentFile));
			BufferedImage screenCapture = new Robot().createScreenCapture(
		    new Rectangle(xCoord,yCoord,dc.getWidth(),dc.getHeight()));
		    
		    String title = tabbedCanvasHolder.getTitleAt(currentFile);
		    if(title.indexOf("untitled-") != -1)
		    	saveImageAs();
		    else
		    	try{
		    		ImageIO.write(screenCapture, "png", file);
		    	}catch(IOException ioe){}
	    }catch(AWTException awte){}	
	}
	
	/**	
	 * Saves the image on the current canvas to a user specified path with 
	 * the .png extension
	 **/
	public void saveImageAs()
	{
		try{
			DrawingCanvas dc = ((DrawingCanvas)canvas.get(currentFile));
			BufferedImage screenCapture = new Robot().createScreenCapture(
	       	new Rectangle(xCoord,yCoord,dc.getWidth(),dc.getHeight()));
	    	
			int returnVal = fileChooser.showSaveDialog(this);
	    	if(returnVal == JFileChooser.APPROVE_OPTION)
	    	{
	    		String path = fileChooser.getSelectedFile().getPath();
				if(path.indexOf(".png") == -1)
					path+=".png";
				try
				{
					file = new File(path);
					tabbedCanvasHolder.setTitleAt(currentFile,fileChooser.getName(file));
					ImageIO.write(screenCapture, "png", file);
				}catch(IOException ioe){}
			}
		}catch(AWTException awte){}	
	}
	
	/** Clears the current canvas of any images **/
	public void clearImage()
	{
		((DrawingCanvas)canvas.get(currentFile)).clearImage();
	}
	
	/** Allows the user to set the visible state of the tool box. **/
	public void viewToolBoxEvent()
	{
		tBar.setVisible(!tBar.isVisible());
	}
	
	/** Allows the user to set the visible state **/ 
	public void viewColorBoxEvent()
	{
		pallette.setVisible(!pallette.isVisible());
	}
	
	/** Displays the help dialog. **/
	public void helpAboutEvent()
	{
		HelpDialog help = new HelpDialog();
	}
	
	/** Exits JPaint. **/
	public void fileExitEvent()
	{
		System.exit(0);
	}
	
	/** 
	 * Creates a new DrawingCanvas and names it "untitled" + fileCount, a 
	 * static variable which is incremented in this method.
	 **/
	public void fileNewEvent()
	{
		DrawingCanvas nextCanvas = new DrawingCanvas();
		nextCanvas.setBackground(Color.BLACK);
		nextCanvas.setName("untitled-"+fileCount);
		tabbedCanvasHolder.add(nextCanvas);
		canvas.add(nextCanvas);
		nextCanvas.createBufferStrategy(2);
		fileCount++;
		numFiles++;
	}
	
	/** Handles all MenuBar events. **/
	public void actionPerformed(ActionEvent e)
	{		
		JMenuItem hit = (JMenuItem)e.getSource();
		if(hit.equals(mainMenu.getJMenuItem("fileNew")))
			fileNewEvent();
		else if(hit.equals(mainMenu.getJMenuItem("fileExit")))
			fileExitEvent();
		else if(hit.equals(mainMenu.getJMenuItem("helpAbout")))
			helpAboutEvent();
		else if(hit.equals(mainMenu.getJMenuItem("viewColorBox")))
			viewColorBoxEvent();
		else if(hit.equals(mainMenu.getJMenuItem("viewToolBox")))
			viewToolBoxEvent();
		else if(hit.equals(mainMenu.getJMenuItem("fileOpen")))
			showFileOpen();
		else if(hit.equals(mainMenu.getJMenuItem("fileSave")))
			saveImage();
		else if(hit.equals(mainMenu.getJMenuItem("fileSaveAs")))
			saveImageAs();
		else if(hit.equals(mainMenu.getJMenuItem("fileClose")))
        	closeProject();
		else if(hit.equals(mainMenu.getJMenuItem("filePrint")))
			printImage();
		else if(hit.equals(mainMenu.getJMenuItem("imageClear")))
			clearImage();
		else if(hit.equals(mainMenu.getJMenuItem("imageRotate")))
			((DrawingCanvas)canvas.get(currentFile)).rotateOperation();
		else if(hit.equals(mainMenu.getJMenuItem("editCut")))
			((DrawingCanvas)canvas.get(currentFile)).cutOperation();
		else if(hit.equals(mainMenu.getJMenuItem("editPaste")))
			((DrawingCanvas)canvas.get(currentFile)).pasteOperation();
		else if(hit.equals(mainMenu.getJMenuItem("editCopy")))
			((DrawingCanvas)canvas.get(currentFile)).copyOperation();
	}	

	/** Closes an open project. **/
	public void closeProject()
	{
        if(numFiles>1)
		{
            tabbedCanvasHolder.remove(currentFile);
            tabbedCanvasHolder.setSelectedIndex(0);
        	numFiles--;
    	}
	}
   
   	/** Handles a componentMoved event **/
	public void componentMoved(ComponentEvent e)
	{
	    Point p = getLocation(); 
	    xCoord = (int)p.getX() + tBar.getWidth() + 6;
	    yCoord = (int)p.getY() + extraY;
	}
	    
	/** Handles a componentHidden event **/
	public void componentHidden(ComponentEvent e){}
	/** Handles a componentResized event **/
	public void componentResized(ComponentEvent e){} 
	/** Handles a componentShown event **/
	public void componentShown(ComponentEvent e){}
} 