/**
 *#########################################################################
 *
 * A component of the Gatherer application, part of the Greenstone digital
 * library suite from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * Author: Katherine Don, Greenstone Digital Library, University of Waikato
 *
 * Copyright (C) 2006 New Zealand Digital Library Project
 *
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *########################################################################
 */
package org.greenstone.gatherer.cdm;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.undo.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.DebugStream;
import org.greenstone.gatherer.Dictionary;
import org.greenstone.gatherer.Gatherer;
import org.greenstone.gatherer.collection.CollectionManager;
import org.greenstone.gatherer.gui.DesignPaneHeader;
import org.greenstone.gatherer.gui.GLIButton;
import org.greenstone.gatherer.remote.RemoteGreenstoneServer;


public class MacrosManager {

    /** The controls used to modify the general options. */
    private Control controls;
    /** Constructor. */
    public MacrosManager() {
    }


    /** Destructor. */
    public void destroy() {
	if (controls != null) {
	    controls.destroy();
	    controls = null;
	}
    }

    public void loseFocus() {
    }

    public void gainFocus() {

    }
    /** This class is resposible for generating the controls for the editing of general options.
     * @return the Control for editing the general options
     */
    public Control getControls() {
	if (controls == null) {
	    controls = new MacrosControl();
	}
	return controls;
    }
    

    /** Called when the detail mode has changed which in turn may cause several design elements to be available/hidden
     * @param mode the new mode as an int
     */
    public void modeChanged(int mode) {

    }


    private class MacrosControl
	extends JPanel
	implements Control, WindowFocusListener {

	JTextArea macros_textarea = null;
	JButton undo_button = null;
	JButton redo_button = null;
	private final UndoManager undo = new UndoManager();
	private boolean macros_changed = false;
	public MacrosControl() {
	    super();
            this.setComponentOrientation(Dictionary.getOrientation());
            
	    JPanel header_pane = new DesignPaneHeader("CDM.GUI.Macros", "collectionspecificmacros");	    
	    JPanel main_pane = new JPanel();
	    main_pane.setComponentOrientation(Dictionary.getOrientation());
            main_pane.setLayout(new BorderLayout());
	    macros_textarea = new JTextArea();
            macros_textarea.setComponentOrientation(Dictionary.getOrientation());
	    macros_textarea.setBackground(Configuration.getColor("coloring.editable_background", false));
	    macros_textarea.setLineWrap(false);
	    macros_textarea.setWrapStyleWord(false);
	    macros_textarea.setToolTipText(Dictionary.get("CDM.MacrosManager.Editor_Tooltip"));
	    readMacroFile(); // load in the original contents
	    macros_textarea.getDocument().addDocumentListener(new EditorListener());

	    // Listen for undo and redo events
	    macros_textarea.getDocument().addUndoableEditListener(new UndoableEditListener() {
		    public void undoableEditHappened(UndoableEditEvent evt) {
			undo.addEdit(evt.getEdit());
		    }
		});
	    macros_textarea.setCaretPosition(0);
	    
	    JPanel macros_pane = new JPanel();
            macros_pane.setComponentOrientation(Dictionary.getOrientation());
	    macros_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
	    macros_pane.setLayout(new BorderLayout());
	    macros_pane.add(new JScrollPane(macros_textarea), BorderLayout.CENTER);
	    undo_button = new GLIButton(Dictionary.get("General.Undo"), Dictionary.get("General.Undo_Tooltip"));
	    undo_button.setEnabled(false);
	    undo_button.addActionListener(new UndoListener());

	    redo_button = new GLIButton(Dictionary.get("General.Redo"), Dictionary.get("General.Redo_Tooltip"));
	    redo_button.setEnabled(false);
	    redo_button.addActionListener(new RedoListener());
	    
	    JPanel button_pane = new JPanel();
            button_pane.setComponentOrientation(Dictionary.getOrientation());
            button_pane.setLayout(new GridLayout(1,2));
	    button_pane.add(undo_button);
	    button_pane.add(redo_button);

	    main_pane.add(macros_pane, BorderLayout.CENTER);
	    main_pane.add(button_pane, BorderLayout.SOUTH);

	    setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
	    setLayout(new BorderLayout());
	    add(header_pane, BorderLayout.NORTH);
	    add(main_pane, BorderLayout.CENTER);
	    Gatherer.g_man.addWindowFocusListener(this);
	}

	public void destroy() {
	}

	public void loseFocus() {
	    if (macros_changed) {
		writeMacroFile();
		macros_changed = false;
	    }
	}

	public void gainFocus() {
	    macros_textarea.grabFocus();
	}
	
	public void windowGainedFocus(WindowEvent e) {
	}
	
	public void windowLostFocus(WindowEvent e) {
	    if (macros_changed) {
		writeMacroFile();
		macros_changed = false;
	    }	    
	}

	private void readMacroFile() {
	    macros_textarea.setText("");
	    File extra_dm = new File(CollectionManager.getLoadedCollectionMacrosDirectoryPath() + "extra.dm");
	    
	    if (extra_dm.exists()) {
		try {
		    BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(extra_dm), "UTF-8"));
		
		    String line;
		    while ((line = br.readLine()) != null) {
			macros_textarea.append(line+"\n");
		    }

		    br.close();
		}
		catch (Exception exception) {
		    DebugStream.printStackTrace(exception);
		}
	    }
	}
	
	private void writeMacroFile() {
	    File extra_dm_file = new File(CollectionManager.getLoadedCollectionMacrosDirectoryPath() + "extra.dm");
	    try {
		if (!extra_dm_file.exists()) {
		    File parent_dir = extra_dm_file.getParentFile();
		    parent_dir.mkdirs();
		    extra_dm_file.createNewFile();
		}
		
		BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(extra_dm_file), "UTF-8"));
		String text = macros_textarea.getText();
		out.write(text, 0, text.length());
		out.newLine();
		out.flush();
		out.close();

		// If we're using a remote Greenstone server, upload the new extra.dm file
		// This will return immediately, since we're on the event dispatch thread
		// Users need to wait until the upload has finished before pressing Preview Collection!
		if (Gatherer.isGsdlRemote) {
		    Gatherer.remoteGreenstoneServer.uploadCollectionFile(CollectionManager.getLoadedCollectionName(), extra_dm_file);
		}
	    }
	    catch (Exception exception) {
		DebugStream.printStackTrace(exception);
	    }
	}

	private class EditorListener
	    implements DocumentListener {
	    public void changedUpdate(DocumentEvent e) {
		macros_changed = true;
		undo_button.setEnabled(true);
	    }
          
	    public void insertUpdate(DocumentEvent e) {
		macros_changed = true;
		undo_button.setEnabled(true);
	    }
          
	    public void removeUpdate(DocumentEvent e) {
		macros_changed = true;
		undo_button.setEnabled(true);
	    }

	}

	private class UndoListener
	    implements ActionListener {
	    
	    public void actionPerformed(ActionEvent event) {
		try {
                    if (undo.canUndo()) {
                        int pos = macros_textarea.getCaretPosition();
                        undo.undo();
			macros_textarea.setCaretPosition(pos-1);
			macros_textarea.grabFocus();
			redo_button.setEnabled(true); 
			
                    }
                    if (!undo.canUndo()){
			undo_button.setEnabled(false);
		    }
		    else{
                      	undo_button.setEnabled(true); 
		    }   
                }
		catch (Exception exception) {
		    DebugStream.printStackTrace(exception);
                }           
	    }
	}
    

	private class RedoListener
	    implements ActionListener {
	   
	    public void actionPerformed(ActionEvent evt) {
		try {
		    if (undo.canRedo()) {
			int pos = macros_textarea.getCaretPosition();
			undo.redo();
			macros_textarea.setCaretPosition(pos+1); 
			macros_textarea.grabFocus();
		    }
		    if (!undo.canRedo()){
			redo_button.setEnabled(false);
		    }
		    else{
			redo_button.setEnabled(true); 
		    }
		}
		catch (Exception exception) {
		    DebugStream.printStackTrace(exception);
		}
	    }
	}
    }
}
