/*
 *  Draco Econometrics
 *  Copyright (C) 2006-2007 Approximatrix, LLC
 *  http://www.approximatrix.com
 *  
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
package com.approximatrix.draco.general.ui;

import javax.swing.JEditorPane;
import java.awt.BorderLayout;

import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JPanel;
import javax.swing.JMenuItem;

import java.awt.Component;
import java.awt.Dimension;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.File;

import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.text.DefaultEditorKit;

import com.approximatrix.draco.application.ApplicationManager;
import com.approximatrix.draco.application.ChildFrame;
import com.approximatrix.draco.io.PlainTextUtilities;
import com.approximatrix.draco.main.ui.DynamicMainMenuBar;
import com.approximatrix.draco.main.ui.DynamicToolbar;


/**
 * 
 * @author Jeffrey Armstrong
 *
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class InfoWindow extends ChildFrame {
	
	/** The default editor name */
	private static final String DIALOG_NAME = "Info";
	
	/** The string for requesting topical help */
	private static final String HELP_KEY = "infowindow";
	
	/** The icon to be displayed for this child window */
	private static final String PATH_TO_ICON = "/com/approximatrix/draco/main/ui/images/icons/pencil.png";
	
	/** The default behaviour */
	private static final String DEFAULT_TYPE = "text/plain";
	
	private static final int DEFAULT_WIDTH = 600;
	private static final int DEFAULT_HEIGHT = 350;
	
	private JPanel jPanel = null;
	private JScrollPane jScrollPane = null;
	private JEditorPane textarea = null;
	
	private StringBuffer text_buffer;
	
	private JMenuItem m_cut = null;
	private JMenuItem m_copy = null;
	private JMenuItem m_paste = null;
	
	/** The content type to display */
	private String content_type = null; //DEFAULT_TYPE;
	
	/**
	 * This constructor opens a blank editor window.
	 */
	public InfoWindow() {
		super(DIALOG_NAME, 
				true, //resizable
				true, //closable
				true, //maximizable
				true);
		initialize(true);
		//this.setVisible(true);
	}
	
	/** Creates an InfoWindow containing the specified text.  The new window can be editable
	 * if specified.
	 * 
	 * @param text the text to display
	 * @param editable true to allow editing, false otherwise
	 */
	public InfoWindow(String text, boolean editable) {
		super(DIALOG_NAME, 
				true, //resizable
				true, //closable
				true, //maximizable
				true);
		initialize(editable);
		if(text != null) {
			textarea.setText(text);
			textarea.setCaretPosition(0);
		}
		text_buffer = new StringBuffer(text);

		//this.setVisible(true);
	}
	
	/** Creates an InfoWindow containing the specified text, labeling the window with the 
	 * specified title.  The new window can be editable if specified.
	 * 
	 * @param title the title for the new window
	 * @param text the text to display
	 * @param editable true to allow editing, false otherwise
	 */
	public InfoWindow(String title, String text, boolean editable) {
		super(title, 
				true, //resizable
				true, //closable
				true, //maximizable
				true);
		text_buffer = new StringBuffer(text);
		initialize(editable);
		if(text != null) {
			textarea.setText(text);
			textarea.setCaretPosition(0);
		}
		//this.setVisible(true);
	}
	
	/** Creates an InfoWindow containing the specified text, labeling the window with the 
	 * specified title.  The new window can be editable if specified.
	 * 
	 * @param title the title for the new window
	 * @param text the text to display
	 * @param editable true to allow editing, false otherwise
	 * @param ishtml true if text has HTML tags, false otherwise
	 */
	public InfoWindow(String title, String text, boolean editable, boolean ishtml) {
		this(title,text,editable,(ishtml ? "text/html":"text/plain"));
	}
	
	/** Creates an InfoWindow containing the specified text, labeling the window with the 
	 * specified title.  The new window can be editable if specified.
	 * 
	 * @param title the title for the new window
	 * @param text the text to display
	 * @param editable true to allow editing, false otherwise
	 * @param content_type String defining the content type ("text/plain" or "text/html")
	 */
	public InfoWindow(String title, String text, boolean editable, String content_type) {
		super(title, 
				true, //resizable
				true, //closable
				true, //maximizable
				true);
		
		// Set the content type
		this.setContentType(content_type);
		text_buffer = new StringBuffer(text);
		initialize(editable);
		if(text != null) {
			textarea.setText(text);
			textarea.setCaretPosition(0);
		}

		//this.setVisible(true);
	}
	
	/** Creates an InfoWindow containing the specified text.  The new window can be 
	 * editable if specified.  This constructor allows the size of the window to be 
	 * specified.
	 * 
	 * @param text the text to display
	 * @param editable true to allow editing, false otherwise
	 * @param xsize window width
	 * @param ysize window height
	 */
	public InfoWindow(String text, boolean editable, int xsize, int ysize) {
		super(DIALOG_NAME, 
				true, //resizable
				true, //closable
				true, //maximizable
				true);
		text_buffer = new StringBuffer(text);
		initialize(xsize, ysize, editable);
		if(text != null) {
			textarea.setText(text);
			textarea.setCaretPosition(0);
		}
		//this.setVisible(true);
	}
	
	/** Creates an InfoWindow containing the specified text, labeling the window with the 
	 * specified title.  The new window can be editable if specified.  This constructor
	 * allows the size of the window to be specified.
	 * 
	 * @param title the title for the new window
	 * @param text the text to display
	 * @param editable true to allow editing, false otherwise
	 * @param xsize window width
	 * @param ysize window height
	 */
	public InfoWindow(String title, String text, boolean editable, int xsize, int ysize) {
		super(title, 
				true, //resizable
				true, //closable
				true, //maximizable
				true);
		text_buffer = new StringBuffer(text);
		initialize(xsize, ysize, editable);
		if(text != null) {
			textarea.setText(text);
			textarea.setCaretPosition(0);
		}
		//this.setVisible(true);
	}
	
	/** Creates an InfoWindow containing the specified text.  The new window can be 
	 * editable if specified.  This constructor allows the size of the window to be 
	 * specified.
	 * 
	 * @param text the text to display
	 * @param editable true to allow editing, false otherwise
	 * @param size a valid Dimension object for sizing the window
	 */
	public InfoWindow(String text, boolean editable, Dimension size) {
		this(text,editable,size.width,size.height);
	}
	
	/** Creates an InfoWindow containing the specified text.  The new window can be 
	 * editable if specified.  This constructor allows the size of the window to be 
	 * specified.
	 * 
	 * @param title the title for the new window
	 * @param text the text to display
	 * @param editable true to allow editing, false otherwise
	 * @param size a valid Dimension object for sizing the window
	 * @param content_type String defining the content type ("text/plain" or "text/html")
	 */
	public InfoWindow(String title, String text, boolean editable, Dimension size,  String content_type) {
		//this(text,editable,size.width,size.height);
		this(title,text,editable,content_type);
		this.setSize(size);
	}
	
	/** Creates an InfoWindow containing the specified text, labeling the window with the 
	 * specified title.  The new window can be editable if specified.  This constructor
	 * allows the size of the window to be specified.
	 * 
	 * @param title the title for the new window
	 * @param text the text to display
	 * @param editable true to allow editing, false otherwise
	 * @param size a valid Dimension object for sizing the window
	 */
	public InfoWindow(String title, String text, boolean editable, Dimension size) {
		this(title,text,editable,size.width,size.height);
	}
	
	/** Creates an InfoWindow using a StringBuffer as input.  
	 * 
	 * @param textin_buffer the text to display
	 * @param editable true to allow editing, false otherwise
	 */
	public InfoWindow(StringBuffer textin_buffer, boolean editable) {
		super(DIALOG_NAME, 
				true, //resizable
				true, //closable
				true, //maximizable
				true);
		text_buffer = textin_buffer;
		initialize(editable);
		if(textin_buffer.length() > 0) {
			textarea.setText(textin_buffer.toString());
			textarea.setCaretPosition(0);
		}
		
		//this.setVisible(true);
	}
	
	/** Creates an InfoWindow using a StringBuffer as input.  This constructor
	 * allows the size of the window to be specified. 
	 * 
	 * @param textin_buffer the text to display
	 * @param editable true to allow editing, false otherwise
	 * @param xsize window width
	 * @param ysize window height
	 */
	public InfoWindow(StringBuffer textin_buffer, boolean editable, int xsize, int ysize) {
		super(DIALOG_NAME, 
				true, //resizable
				true, //closable
				true, //maximizable
				true);
		text_buffer = textin_buffer;
		initialize(xsize, ysize, editable);
		
		if(textin_buffer.length() > 0) {
			textarea.setText(textin_buffer.toString());
			textarea.setCaretPosition(0);
		}
		
	}
	
	/** Creates an InfoWindow and fills the window with the contents of a specified
	 * file.
	 * 
	 * @param to_read a valid File object to read the contents for display
	 * @param editable true to allow editing, false otherwise
	 */
	public InfoWindow(File to_read, boolean editable) {
		super(to_read.getName(), 
				true, //resizable
				true, //closable
				true, //maximizable
				true);
		initialize(editable);
		
		loadFile(to_read);
	}
	
	/** Initializes the GUI components.
	 * 
	 * @return void
	 */
	private void initialize(boolean editable) {
		this.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
		this.universal_initialize(editable);
		//this.setVisible(true);
	}
	private void initialize(int xsize, int ysize, boolean editable) {
		this.setSize(xsize, ysize);
		this.universal_initialize(editable);
		//this.setVisible(true);
	}
	private void initialize(Dimension size, boolean editable) {
		this.setSize(size);
		this.universal_initialize(editable);
		//this.setVisible(true);
	}
	
	private void universal_initialize(boolean editable) {
		this.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
		this.setName("info_window");
		//this.setTitle(DIALOG_NAME);
		this.setContentPane(getJPanel());
		
		this.getTextarea().setEditable(editable);
		this.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter() { 
			public void internalFrameClosed(javax.swing.event.InternalFrameEvent e) {
				if(text_buffer != null) {
					text_buffer.delete(0,text_buffer.length());
					text_buffer.append(getTextarea().getText());
				}
				//dispose();
			}
		});
		
		super.setIcon(PATH_TO_ICON);
		
		this.buildToolbar(editable);
	}
	
	/**
	 * This method initializes jPanel	
	 * 	
	 * @return javax.swing.JPanel	
	 */    
	private JPanel getJPanel() {
		if (jPanel == null) {
			jPanel = new JPanel();
			jPanel.setLayout(new BorderLayout());
			jPanel.add(getJScrollPane(), java.awt.BorderLayout.CENTER);
		}
		return jPanel;
	}

	/**
	 * This method initializes jScrollPane	
	 * 	
	 * @return javax.swing.JScrollPane	
	 */    
	private JScrollPane getJScrollPane() {
		if (jScrollPane == null) {
			jScrollPane = new JScrollPane();
			jScrollPane.setViewportView(getTextarea());
		}
		return jScrollPane;
	}
	/**
	 * This method initializes jTextArea	
	 * 	
	 * @return javax.swing.JTextArea	
	 */    
	private JEditorPane getTextarea() {
		if (textarea == null) {
			textarea = new JEditorPane();
			textarea.setEditable(false);
			
			// Obsolete - not necessary
			//the_textarea.setLineWrap(true);
			if(content_type == null)
				textarea.setFont(new java.awt.Font("Monospaced", java.awt.Font.PLAIN, 12));
			else {
				if(content_type == null && text_buffer != null) {
					String start_text = text_buffer.toString().trim().substring(0, 6);
					if(start_text.compareToIgnoreCase("<html>") == 0)
						content_type = "text/html";
					else
						content_type = "text/plain";
				} else if(content_type.compareToIgnoreCase("text/plain")==0)
					textarea.setFont(new java.awt.Font("Monospaced", java.awt.Font.PLAIN, 12));
				textarea.setContentType(content_type);
			}
			
		}
		return textarea;
	}
	
	private void loadFile(File toload) {
		String ret = null;
		try {
			ret = PlainTextUtilities.LoadText(toload);
		} catch(FileNotFoundException fnfe) {
			// pass 
		}
		
		if(ret != null) {
			getTextarea().setText(ret);
			textarea.setCaretPosition(0);
		}	
	}
	
	/** Returns the text contents of this InfoWindow
	 * 
	 * @return the text contents of the window
	 */
	public String getText() {
		return this.getTextarea().getText();
	}
	
	/** Returns the editable state of this InfoWindow
	 * 
	 * @return true if the text can be edited, false otherwise
	 */
	public boolean isEditable() {
		return this.getTextarea().isEditable();
	}
	
	private void buildToolbar(boolean editable) {
		
		ArrayList<Component> buttons = new ArrayList<Component>();
		
		if(editable) {
			// New button for the control toolbar
			JButton button = new JButton();
			button.setToolTipText("New file");
			button.setIcon(ApplicationManager.GetIcon("NEW"));
			button.setBackground(java.awt.Color.YELLOW);
			button.addMouseListener(new java.awt.event.MouseAdapter() { 
				public void mouseClicked(java.awt.event.MouseEvent e) { 
					textarea.setText(null);
				}
			});
			//getJControlBar().add(button);
			
			// New button for the control toolbar
			button = new JButton();
			button.setToolTipText("Load a text file from disk");
			button.setIcon(ApplicationManager.GetIcon("OPEN"));
			button.setBackground(java.awt.Color.YELLOW);
			button.addMouseListener(new java.awt.event.MouseAdapter() { 
				public void mouseClicked(java.awt.event.MouseEvent e) { 
					// First get a filename
					JFileChooser chooser = new JFileChooser();
					chooser.setDialogTitle("Load Text...");
				    if (chooser.showOpenDialog(chooser) == JFileChooser.APPROVE_OPTION) {
				    	loadFile(chooser.getSelectedFile());
				    }
				}
			});
			buttons.add(button);
		}
		
		// Save button for the control toolbar
		JButton button = new JButton();
		button.setToolTipText("Save to a text file");
		button.setIcon(ApplicationManager.GetIcon("SAVEAS"));
		button.setBackground(java.awt.Color.YELLOW);
		button.addMouseListener(new java.awt.event.MouseAdapter() { 
			public void mouseClicked(java.awt.event.MouseEvent e) { 
				// First get a filename
				JFileChooser chooser = new JFileChooser();
				chooser.setDialogTitle("Save Text As...");
				chooser.setDialogType(JFileChooser.SAVE_DIALOG);
			    if (chooser.showOpenDialog(chooser) == JFileChooser.APPROVE_OPTION) {
			    	
			    	// Write the file if everything is ok
			    	PrintWriter data;
					try {  // Create the input stream.
			            data = new PrintWriter(new FileWriter(chooser.getSelectedFile()));
			            data.print(textarea.getText());
			            data.close();
			        }
			        catch (IOException the_exception) {
			        	JOptionPane.showMessageDialog(null,"Problem opening file: "+
			        			chooser.getSelectedFile().toString(),
			                    "Error",JOptionPane.ERROR_MESSAGE);
			        }
			    }
			}
		});
		buttons.add(button);
		
		
		if(isEditable()) {
		    button = new JButton(new DefaultEditorKit.CutAction());
		    button.setText(null);
		    button.setToolTipText("Cut selection");
		    button.setIcon(ApplicationManager.GetIcon("EDITCUT"));
    		buttons.add(button);
    	}
    		
	    button = new JButton(new DefaultEditorKit.CopyAction());
        button.setText(null);
	    button.setToolTipText("Copy selection");
	    button.setIcon(ApplicationManager.GetIcon("EDITCOPY"));
   		buttons.add(button);

    	if(isEditable()) {
		    button = new JButton(new DefaultEditorKit.PasteAction());
		    button.setText(null);
		    button.setToolTipText("Paste from clipboard");
		    button.setIcon(ApplicationManager.GetIcon("EDITPASTE"));
    		buttons.add(button);
        }
        		
		toolbarButtons = new Component[buttons.size()];
		buttons.toArray(toolbarButtons);
	}

	/** For now, no menu items are necessary (everything is performed through the toolbar
	 * 
	 * @return null since there are no applicable menu items
	 * @see com.approximatrix.draco.application.ChildFrame#getMenuItems()
	 */
	public JMenu[] getMenuItems() {
	    if(menuItems == null) {
	        
	        menuItems = new JMenu[1];
	        
            menuItems[0] = DynamicMainMenuBar.GetGenericEditMenu();
			
			if(isEditable()) {
    			m_cut = new JMenuItem(new DefaultEditorKit.CutAction());
    			m_cut.setText("Cut");
	    		menuItems[0].add(m_cut);	    
			}
			
			m_copy = new JMenuItem(new DefaultEditorKit.CopyAction());
			m_copy.setText("Copy");
			menuItems[0].add(m_copy);
			
			if(isEditable()) {
    			m_paste = new JMenuItem(new DefaultEditorKit.PasteAction());
    			m_paste.setText("Paste");
	    		menuItems[0].add(m_paste);
	    	}
				        
	    }
		return menuItems;
	}

	/** Generates the toolbar buttons for the info window
	 * 
	 * @return an array of buttons for the toolbar
	 * @see com.approximatrix.draco.application.ChildFrame#getToolbarButtons()
	 */
	public Component[] getToolbarButtons() {
		if(toolbarButtons == null) {
			this.buildToolbar(true); //Default...
		}
		return toolbarButtons;
	}

	/** All informational windows should be renamable
	 * 
	 * @return true
	 * @see com.approximatrix.draco.application.ChildFrame#isRenameable()
	 */
	@Override
	public boolean isRenameable() {
		return true;
	}
	
	/** Returns the help key for the About window
	 * 
	 * @return the proper help key, defined by HELP_KEY
	 * @see #HELP_KEY
	 * @see com.approximatrix.draco.application.ChildFrame#getHelpKey()
	 */
	public String getHelpKey() {
		return HELP_KEY;
	}
	
	/** Returns the content type ("text/plain" or "text/html") of the
	 * window.
	 * 
	 * @return a String defining the content type
	 */
	public String getContentType() {
		return this.content_type;
	}
	
	/** Sets the content type for the document, using some error checking
	 * to avoid problems.
	 * 
	 * @param type the possible content type string to be set
	 */
	private void setContentType(String type) {
		if(type == null)
			this.content_type = DEFAULT_TYPE;
		else
			this.content_type = type;
	}
	
 }  //  @jve:decl-index=0:visual-constraint="30,10"
