/*
** FILE:   xt_StyleFrame.java
**
** (c) 1998 Steve Withall.
**
** HISTORY:
**    14Jun98  stevew  Created, based on xt_SimpleEditFrame.
*/
package xt;

//import xs.xs_StyleException;
import xs.xs_StyleThread;
import xs.xs_XslEngine;

import xe.xe_XmlEngine;

import xm.xm_DocumentModel;
import xm.xm_FileLoader;
import xm.xm_StatusBar;

import eh.eh_Debug;

import com.sun.java.swing.plaf.metal.MetalLookAndFeel;

import com.sun.java.swing.preview.filechooser.*;      //TEMP
import com.sun.java.swing.preview.*;                  //TEMP

import com.sun.java.swing.text.BadLocationException;
import com.sun.java.swing.text.DefaultStyledDocument;
import com.sun.java.swing.text.Document;

//TEMP The next line is present to allow running under either swing-1.0.2 or
//TEMP swing-1.1beta - to cater for the moving of JFileChooser from preview.
//import com.sun.java.swing.*;          //TEMP

import com.sun.java.swing.Action;
import com.sun.java.swing.Box;
import com.sun.java.swing.JButton;
import com.sun.java.swing.JEditorPane;
import com.sun.java.swing.JFrame;
import com.sun.java.swing.JInternalFrame;
import com.sun.java.swing.JLabel;
import com.sun.java.swing.JOptionPane;
import com.sun.java.swing.JPanel;
import com.sun.java.swing.JScrollPane;
import com.sun.java.swing.JTabbedPane;
import com.sun.java.swing.JTextArea;
import com.sun.java.swing.JTextField;  //TEMP
import com.sun.java.swing.JViewport;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.FileDialog;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;

import java.io.File;
import java.io.FileWriter;
import java.io.StringWriter;

//*****************************************************************************
/** <p>xt_StyleFrame is an internal frame to provide a range of document style
 *  functions: to load, view and edit a stylesheet, to apply that stylesheet to
 *  the main current document, and to view and save the results after the
 *  stylesheet has been applied to the document.</p>
 *
 *  <p>To visually accomplish this wide range of functions, the frame uses
 *  several tab panes.</p>
 */
public class xt_StyleFrame extends xt_DocumentFrame
{
    /** The XML engine, responsible for XML processing. */
    xe_XmlEngine      TheXmlEngine            = null;

    /** The XSL stylesheet document (model) currently being operated upon. */
    xm_DocumentModel  StylesheetDocumentModel = null;

    /** Parent's status bar, for the display of details of what's going on
     *  - and anything that's wrong. */
    xm_StatusBar      MainStatusBar;

    /** This class's main frame. */
    JFrame            ParentFrame;

    /** The pathname of the XSL stylesheet file currently being used. */
    String            FilePathnameString      = new String();

    /** Dialog box for selecting which XSL file to open. */
    FileDialog        SelectFileDialog        = null;

    // Attributes relating to identifying which stylesheet to use.
    JLabel         StylesheetNameLabel     = new JLabel("Stylesheet");
    JTextField     StylesheetNameTextField = new JTextField(25);

    // Buttons.
    JButton        SelectButton      = new JButton("Select");
    JButton        ApplyButton       = new JButton("Apply");
    JButton        SaveResultsButton = new JButton("Save results");

    /** Tabbed pane for the display of the various aspects of displaying a
     *  stylesheet and its results. */
    JTabbedPane    StyleTabbedPane       = null;

    // Attributes relating to the XSL source of the stylesheet.
    /** Panel for the display of the source of the current stylesheet. */
    JPanel         StylesheetSourceTab   = null;

    /** The XSL source edit area itself. */
    JTextArea      SourceTextArea        = new JTextArea();

    // Attributes relating to the XSL tree of the stylesheet. */
    /** Panel for the display of the tree of the current stylesheet. */
    JPanel         StylesheetTreeTab     = null;

    // Attributes relating to the source of the results generated by applying
    // the stylesheet to the current document. */
    /** Panel for the display of the source of the results. */
    JPanel         ResultsSourceTab      = null;

    /** The document into which the results of applying the XSL stylesheet to
     *  the XML document are placed. */
    DefaultStyledDocument  ResultsDocument = new DefaultStyledDocument();

    /** The results source display area itself. */
    JTextArea      ResultsSourceTextArea = new JTextArea(ResultsDocument);

    // Attributes relating to the display of HTML generated by applying the
    // stylesheet to the current document. */
    /** Panel for the display of HTML results. */
    JPanel         ResultsHtmlTab        = null;

    /** The HTML results display area itself. */
    JEditorPane    HtmlViewPane          = new JEditorPane();

    //*****************************************************************************
    /** Constructor.
      */
    public xt_StyleFrame(xm_DocumentModel  InputDocumentModel,
                         String            InputFrameTitle,
                         xe_XmlEngine      InputXmlEngine,
                         xm_StatusBar      InputStatusBar,
                         JFrame            InputParent)
    {
        super(InputDocumentModel, InputFrameTitle);
//	    eh_Debug.add(7, "xt_StyleFrame:");  //TEMP
        TheXmlEngine  = InputXmlEngine;
        MainStatusBar = InputStatusBar;
        ParentFrame   = InputParent;

        ensureClassesRegistered();  // Make the XSL element classes known

        StylesheetDocumentModel = new xm_DocumentModel(TheXmlEngine);
        StylesheetDocumentModel.setStatusBar(InputStatusBar);

	    Container  EditContentPane = getContentPane();
	    EditContentPane.setLayout(new BorderLayout());

        initTopPanel();

        // Set up the tabbed pane where all the real work is done.
        StyleTabbedPane = new JTabbedPane();
        StyleTabbedPane.setBackground(Color.lightGray);
        addTabs();  // Added all required tabs
    	EditContentPane.add("Center", StyleTabbedPane);
    }

    //*****************************************************************************
    /** Ensure the XSL-related element classes are registered.
     */
    static public void ensureClassesRegistered()
    {
        xs_XslEngine.ensureClassesRegistered();
    }

    //*****************************************************************************
    /** Initialise the input/control panel at the top of the frame.
     */
    private void initTopPanel()
    {
//        eh_Debug.add(7, "xt_StyleFrame.InitTopPanel");
        JPanel  TopPanel = new JPanel();

        GridBagLayout      TopPanelLayout      = new GridBagLayout();
        GridBagConstraints TopPanelConstraints = new GridBagConstraints();
        TopPanel.setLayout(TopPanelLayout);
        TopPanelConstraints.gridwidth = 1;

        // Stylesheet name.
        TopPanelConstraints.insets    = new Insets(4, 4, 4, 4);
        TopPanelConstraints.anchor    = GridBagConstraints.WEST;
        TopPanel.add(StylesheetNameLabel);

        TopPanelLayout.setConstraints(StylesheetNameTextField, TopPanelConstraints);
        TopPanel.add(StylesheetNameTextField);

        TopPanelConstraints.insets    = new Insets(4, 0, 4, 4);
        TopPanelLayout.setConstraints(SelectButton, TopPanelConstraints);
        TopPanel.add(SelectButton);

        // The remaining buttons.
        TopPanelConstraints.insets    = new Insets(4, 16, 4, 2);
        TopPanelLayout.setConstraints(ApplyButton, TopPanelConstraints);
        TopPanel.add(ApplyButton);

        TopPanelConstraints.insets    = new Insets(4, 0, 4, 4);
        TopPanelConstraints.gridwidth = GridBagConstraints.REMAINDER;
        TopPanelLayout.setConstraints(SaveResultsButton, TopPanelConstraints);
        TopPanel.add(SaveResultsButton);

    	SelectButton.addActionListener(new SelectButtonListener() );
    	ApplyButton.addActionListener(new ApplyButtonListener() );
    	SaveResultsButton.addActionListener(new SaveButtonListener() );

	    getContentPane().add("North", TopPanel);
    }

    //*****************************************************************************
    /** We have been notified that the look-and-feel has changed.
     */
    public void updateUI()
    {
        super.updateUI();
	    setEditFont();
        setResultsFont();
    }

    //*****************************************************************************
    /** Add all required tabs.
     */
    public void addTabs()
    {
        addStylesheetSourceTab();
        addStylesheetTreeTab();
        addResultsSourceTab();
//        addResultsHtmlTab();
    }

    //*****************************************************************************
    /** Add 'Stylesheet source' tab to display the XML (XSL) source of the current
     *  stylesheet.
     */
    public void addStylesheetSourceTab()
    {
//	    eh_Debug.add(7, "xt_StyleFrame.addStylesheetSourceTab:"); //TEMP
        StylesheetSourceTab = new JPanel();
        StyleTabbedPane.addTab("Stylesheet source", StylesheetSourceTab);
	    StylesheetSourceTab.setLayout(new BorderLayout());

	    // Initialise the stylesheet source edit JTextArea.
	    setEditFont();
	    SourceTextArea.setTabSize(4);
	    SourceTextArea.setDocument(StylesheetDocumentModel);
	    SourceTextArea.setBorder(null);

        // Scroller.
    	JScrollPane  EditScrollPane = new JScrollPane();
    	JViewport    EditViewport   = EditScrollPane.getViewport();
    	EditViewport.add(SourceTextArea);
   	    EditViewport.setBackingStoreEnabled(false);

    	JPanel       EditPanel = new JPanel();
    	EditPanel.setLayout(new BorderLayout());
    	EditPanel.add("Center", EditScrollPane);
        StylesheetSourceTab.add(EditPanel, BorderLayout.CENTER);
    }

    //*****************************************************************************
    /** Set the font used for editing. The size of the font is determined from that
     *  of the current metal user text font.
     */
    public void setEditFont()
    {
        Font  UserTextFont = MetalLookAndFeel.getUserTextFont();
        if (SourceTextArea != null)
	        SourceTextArea.setFont(new Font("Monospaced", Font.PLAIN, UserTextFont.getSize() ));
    }

    //*****************************************************************************
    /** Add 'Stylesheet source' tab to display the XML (XSL) source of the current
     *  stylesheet.
     */
    public void addStylesheetTreeTab()
    {
//	    eh_Debug.add(7, "xt_StyleFrame.addStylesheetTreeTab:"); //TEMP
        StylesheetTreeTab = new JPanel();
	    StylesheetTreeTab.setLayout(new BorderLayout());
        StyleTabbedPane.addTab("Stylesheet tree", StylesheetTreeTab);

        xt_DocumentTreeSplitPane  DocumentSplitPane
                         = new xt_DocumentTreeSplitPane(StylesheetDocumentModel);
        StylesheetTreeTab.add(DocumentSplitPane, BorderLayout.CENTER);
    }

    //*****************************************************************************
    /** Add 'Results source' tab to display the source of the results generated by
     *  applying the stylesheet to the current document.
     */
    public void addResultsSourceTab()
    {
//	    eh_Debug.add(7, "xt_StyleFrame.addResultsSourceTab:"); //TEMP
        ResultsSourceTab = new JPanel();
	    ResultsSourceTab.setLayout(new BorderLayout());
        StyleTabbedPane.addTab("Results source", ResultsSourceTab);

	    // Initialise the source edit JTextArea.
	    setResultsFont();
	    ResultsSourceTextArea.setTabSize(4);
//	    ResultsSourceTextArea.setDocument(TheDocumentModel);
	    ResultsSourceTextArea.setBorder(null);
        ResultsSourceTextArea.setBackground(Color.lightGray);

        // Scroller.
    	JScrollPane  ResultsScrollPane = new JScrollPane();
    	JViewport    ResultsViewport   = ResultsScrollPane.getViewport();
    	ResultsViewport.add(ResultsSourceTextArea);
   	    ResultsViewport.setBackingStoreEnabled(false);

    	JPanel       ResultsPanel = new JPanel();
    	ResultsPanel.setLayout(new BorderLayout());
    	ResultsPanel.add("Center", ResultsScrollPane);
        ResultsSourceTab.add(ResultsPanel, BorderLayout.CENTER);
    }

    //*****************************************************************************
    /** Set the font used for displaying the results. The size of the font is
     *  determined from that of the current metal user text font.
     */
    public void setResultsFont()
    {
        Font  UserTextFont = MetalLookAndFeel.getUserTextFont();
        if (ResultsSourceTextArea != null)
	        ResultsSourceTextArea.setFont(new Font("Monospaced", Font.PLAIN, UserTextFont.getSize() ));
    }

    //*****************************************************************************
    /** Add 'Results HTML' tab to display as HTML the results generated by
     *  applying the stylesheet to the current document.
     */
    public void addResultsHtmlTab()
    {
//	    eh_Debug.add(7, "xt_StyleFrame.addResultsHtmlTab:"); //TEMP
        ResultsHtmlTab = new JPanel();
	    ResultsHtmlTab.setLayout(new BorderLayout());
        StyleTabbedPane.addTab("Results HTML", ResultsHtmlTab);

	    // Initialise the source edit JTextArea.
    	HtmlViewPane.setContentType("text/html");
	    HtmlViewPane.setDocument(ResultsDocument);
    	HtmlViewPane.setEditable(false);
//    	HtmlViewPane.addHyperlinkListener(this);
        HtmlViewPane.requestFocus();
	    HtmlViewPane.setBorder(null);

        // Scroller.
    	JScrollPane  HtmlScrollPane = new JScrollPane();
    	JViewport    HtmlViewport   = HtmlScrollPane.getViewport();
    	HtmlViewport.add(HtmlViewPane);
   	    HtmlViewport.setBackingStoreEnabled(false);

    	JPanel       HtmlPanel = new JPanel();
    	HtmlPanel.setLayout(new BorderLayout());
    	HtmlPanel.add("Center", HtmlScrollPane);
        ResultsHtmlTab.add(HtmlPanel, BorderLayout.CENTER);
    }

    //*****************************************************************************
    /** Get the results from the last XSL generation in the form of a string.
     *
     *  @return  A string representation of the results
     */
    public String getResultsString()
    {
        String  ResultsString = null;
        try
        {
            ResultsString = ResultsDocument.getText(ResultsDocument.getStartPosition().getOffset(),
                                                    ResultsDocument.getLength() );
        }
        catch (BadLocationException  InputException)
        {
	        eh_Debug.add(2, "xt_StyleFrame.getSourceString: Results document not initialised: "
	                               + InputException);
        }
        return ResultsString;
    }

    //*****************************************************************************
    /** Retrieve the document model associated with this frame. This overrides the
     *  method in xt_DocumentFrame - so while we do still use the main document,
     *  all actions relating to this frame affect the stylesheet document only.
     *
     *  @return  The document model about which this frame displays information
     */
    public xm_DocumentModel getDocumentModel()
    {
	    return StylesheetDocumentModel;
    }
    //*****************************************************************************
    /** Retrieve the text area in which the source is displayed and edited.
     *
     *  @return  The edit source text area
     */
    public JTextArea getSourceTextArea()
    {
	    return SourceTextArea;
    }

    //*****************************************************************************
    /** Retrieve the text area in which the source is displayed and edited.
     *
     *  @return  An array of the actions supported by this class
     */
    static public Action[] getActions()
    {
        JTextArea  TempTextArea = new JTextArea();
	    return(TempTextArea.getActions() );
    }


    //*****************************************************************************
    // Button listener inner classes.
    //*****************************************************************************
    /** Handle pressing of the "Select" button. Pop up a file select dialog to
     *  choose a stylesheet file, the load this file.
     */
    class SelectButtonListener implements ActionListener
    {
        public void actionPerformed(ActionEvent  InputEvent)
        {
//            eh_Debug.add(7, "SelectButtonListener.actionPerformed:");
	        if (SelectFileDialog == null)
    	        SelectFileDialog = new FileDialog(ParentFrame,
    	                                          "Select stylesheet XSL file",
    	                                          FileDialog.LOAD);
    	    SelectFileDialog.show();

    	    String  FileNameDirectoryString = SelectFileDialog.getDirectory();
    	    String  FileNameString          = SelectFileDialog.getFile();
    	    FilePathnameString              = FileNameDirectoryString + FileNameString;
    	    if (FileNameString == null)
    	    {
                eh_Debug.add(4, "Null file name selected");
        		return;
    	    }

    	    validate();

    	    StylesheetDocumentModel.clear();

    	    // Put the name of this file in the frame title.
//    	    setTitle(BasicFrameTitle + " - " + FilePathnameString);

           	Thread  SourceFileLoader = new xm_FileLoader(FilePathnameString,
    	                                                 StylesheetDocumentModel,
           	                                             MainStatusBar);
           	SourceFileLoader.start();
        }
    }

    //*****************************************************************************
    /** Handle pressing of the "Apply" button. Apply the current stylesheet to the
     *  current document.
     */
    class ApplyButtonListener implements ActionListener
    {
        public void actionPerformed(ActionEvent  InputEvent)
        {
            Thread  StyleThread = new xs_StyleThread(StylesheetDocumentModel.getCurrentDocument(),
                                                     TheDocumentModel.getCurrentDocument(),
                                                     ResultsDocument,
                                                     MainStatusBar);
            StyleThread.start();
        }
    }

    //*****************************************************************************
    /** Handle pressing of the "Save results" button. Apply the current stylesheet
     *  to the current document.
     */
    class SaveButtonListener implements ActionListener
    {
        public void actionPerformed(ActionEvent  InputEvent)
        {
//            eh_Debug.add(7, "SelectButtonListener.actionPerformed:");
		    JFileChooser  SaveFileChooser = new JFileChooser(FilePathnameString);
//		    SaveFileChooser.addChoosableFileFilter(new FileFilter() );
		    int  ChooseState = SaveFileChooser.showSaveDialog(ParentFrame);
		    if (ChooseState == JFileChooser.APPROVE_OPTION)
		    {
			    File  SaveFile = SaveFileChooser.getSelectedFile();
			    if (SaveFile == null)
		            JOptionPane.showMessageDialog(ParentFrame,
		                                          "No file chosen - no save performed");
			    else
			    {
			        FilePathnameString = SaveFile.getPath();
                    String  ResultsString = getResultsString();
                    if (ResultsString == null)
                        MainStatusBar.setText("No results to save");
                    else
                    {
                        try
                        {
                            MainStatusBar.setText("Saving results to file "
                                                     + FilePathnameString);
                            FileWriter  SaveFileWriter = new FileWriter(FilePathnameString);
                            SaveFileWriter.write(ResultsString);
                            SaveFileWriter.close();
                            MainStatusBar.setText("Saved results to file "
                                                     + FilePathnameString);
                        }
                        catch (Exception  InputException)
                        {
                            MainStatusBar.setText(2, "Error writing results file "
                                                        + FilePathnameString
                                                        + ". Exception = "
                                                        + InputException);
                        }
                    }
			    }
		    }
        }
    }
}

//*****************************************************************************
