package com.dbxml.db.admin.components;

/*
 * dbXML - Native XML Database
 * Copyright (C) 1999-2004  The dbXML Group, L.L.C.
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Id: XSLTViewer.java,v 1.7 2004/03/30 20:51:53 bradford Exp $
 */

import java.awt.*;
import javax.swing.*;

import com.dbxml.db.admin.Admin;
import com.dbxml.db.admin.DocWrapper;
import com.dbxml.db.admin.TabbedNodeEditor;
import com.dbxml.db.admin.swing.JLabelListCellRenderer;
import com.dbxml.db.admin.swing.SyntaxTextArea;
import com.dbxml.xml.dom.DOMHelper;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.io.StringWriter;
import java.net.URL;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
 * XSLTViewer
 */

public class XSLTViewer extends JPanel implements TabbedNodeEditor {
   private TransformerFactory tf = TransformerFactory.newInstance();
   private DocWrapper styleSheet;
   private boolean active;
   private boolean reset;
   private DocWrapper doc;
   private String text;

   private JLabel lblXSLTBrowse = new JLabel();
   private BorderLayout layoutPnlXSLTBrowse = new BorderLayout();
   private JComboBox cmbContent = new JComboBox();
   private JPanel pnlXSLTBrowse = new JPanel();
   private JButton btnXSLTBrowse = new JButton();
   private BorderLayout thisLayout = new BorderLayout();
   private JPanel pnlXSLTView = new JPanel();
   private CardLayout layoutPnlXSLTView = new CardLayout();
   private JScrollPane scrollHTML = new JScrollPane();
   private JEditorPane htmlXSLT = new JEditorPane();
   private SyntaxTextArea xmlXSLT = new SyntaxTextArea();
   private ImageIcon imgHTMLView;
   private ImageIcon imgXMLView;
   private ImageIcon imgTextView;

   public XSLTViewer() {
      try {
         jbInit();

         cmbContent.setRenderer(JLabelListCellRenderer.getInstance());
         cmbContent.addItem(new JLabel("text/html", imgHTMLView, SwingConstants.LEFT));
         cmbContent.addItem(new JLabel("text/xml", imgXMLView, SwingConstants.LEFT));
         cmbContent.addItem(new JLabel("text/plain", imgTextView, SwingConstants.LEFT));
         cmbContent.setSelectedIndex(0);
         layoutPnlXSLTView.show(pnlXSLTView, "text/html");
      }
      catch ( Exception e ) {
         Admin.getInstance().addMessage(e.toString());
      }
   }

   private void jbInit() throws Exception {
      imgHTMLView = new ImageIcon(XSLTViewer.class.getResource("xslt_view.gif"));
      imgXMLView = new ImageIcon(XSLTViewer.class.getResource("text_view.gif"));
      imgTextView = new ImageIcon(XSLTViewer.class.getResource("plain_view.gif"));

      lblXSLTBrowse.setFont(new Font("Dialog", 0, 12));
      lblXSLTBrowse.setForeground(Color.black);
      lblXSLTBrowse.setHorizontalAlignment(SwingConstants.RIGHT);
      lblXSLTBrowse.setText("(No Stylesheet Selected)");
      layoutPnlXSLTBrowse.setHgap(5);
      cmbContent.setOpaque(true);
      cmbContent.addItemListener(new ItemListener() {
         public void itemStateChanged(ItemEvent e) {
            cmbContent_itemStateChanged(e);
         }
      });
      cmbContent.setFont(new Font("Dialog", 0, 12));
      pnlXSLTBrowse.setLayout(layoutPnlXSLTBrowse);
      btnXSLTBrowse.setFont(new Font("Dialog", 0, 12));
      btnXSLTBrowse.setText("Browse...");
      btnXSLTBrowse.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            btnXSLTBrowse_actionPerformed(e);
         }
      });
      this.setLayout(thisLayout);
      pnlXSLTView.setLayout(layoutPnlXSLTView);
      htmlXSLT.setMargin(new Insets(1, 1, 1, 1));
      htmlXSLT.setEditable(false);
      htmlXSLT.setContentType("text/html");
      htmlXSLT.addHyperlinkListener(new HyperlinkListener() {
         public void hyperlinkUpdate(HyperlinkEvent e) {
            htmlXSLT_hyperlinkUpdate(e);
         }
      });
      thisLayout.setHgap(2);
      thisLayout.setVgap(2);
      pnlXSLTBrowse.add(lblXSLTBrowse, BorderLayout.CENTER);
      pnlXSLTBrowse.add(btnXSLTBrowse, BorderLayout.EAST);
      pnlXSLTBrowse.add(cmbContent, BorderLayout.WEST);
      this.add(pnlXSLTView, BorderLayout.CENTER);
      pnlXSLTView.add(scrollHTML, "text/html");
      scrollHTML.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
      scrollHTML.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
      scrollHTML.getViewport().add(htmlXSLT);
      this.add(pnlXSLTBrowse, BorderLayout.SOUTH);
      xmlXSLT.setEditable(false);
      pnlXSLTView.add(xmlXSLT, "text/xml");
   }

   public void requestFocus() {
      switch ( cmbContent.getSelectedIndex() ) {
         case 0:
            htmlXSLT.requestFocus();
            break;

         case 1:
         case 2:
            xmlXSLT.requestFocus();
            break;
      }
   }

   public void setStylesheet(String name, DocWrapper styleSheet) {
      this.styleSheet = styleSheet;
      lblXSLTBrowse.setText(name);
      if ( doc != null ) {
         if ( active ) {
            Admin admin = Admin.getInstance();
            admin.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
            text = transform(doc.getNode());
            setXSLTText(text);
            admin.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
         }
         else
            reset = true;
      }
   }

   public void setSelectedIndex(int index) {
      cmbContent.setSelectedIndex(index);
   }

   public void setXSLTText(String xml) {
      switch ( cmbContent.getSelectedIndex() ) {
         case 0:
            htmlXSLT.setText(xml);
            htmlXSLT.setCaretPosition(0);
            htmlXSLT.scrollRectToVisible(new Rectangle(0, 0, 0, 0));
            break;
         case 1:
         case 2:
            xmlXSLT.setText(xml);
            xmlXSLT.setHighlighting(cmbContent.getSelectedIndex() == 1);
            xmlXSLT.setCaretPosition(0);
            break;
      }
   }

   public String transform(Node node) {
      try {
         String systemID = null;

         File f = styleSheet.getFile();
         if ( f != null ) {
            f = new File(f, styleSheet.getName());
            systemID = f.getAbsolutePath();
         }

         Transformer t = tf.newTransformer(new DOMSource(styleSheet.getNode(), systemID));
         StringWriter sw = new StringWriter();
         StreamResult sr = new StreamResult(sw);
         t.transform(new DOMSource(node), sr);
         return sw.toString();
      }
      catch ( Exception e ) {
         Admin.getInstance().addMessage(e.toString());
         return null;
      }
   }

   public boolean isModified() {
      return false;
   }

   public void reset() {
      reset = true;
   }

   public void setDocWrapper(DocWrapper doc) {
      reset = this.doc != doc;
      this.doc = doc;
   }

   public DocWrapper getDocWrapper() {
      return doc;
   }

   public void activate(boolean readOnly) {
      active = true;
      if ( styleSheet != null && reset ) {
         Admin admin = Admin.getInstance();
         admin.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
         text = transform(doc.getNode());
         setXSLTText(text);
         admin.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
      }
   }

   public boolean isCutEnabled() {
      return false;
   }

   public void cut() {
      /** @todo This */
   }

   public boolean isCopyEnabled() {
      return true;
   }

   public void copy() {
      switch ( cmbContent.getSelectedIndex() ) {
         case 0:
            htmlXSLT.copy();
            break;

         case 1:
         case 2:
            xmlXSLT.copy();
            break;
      }
   }

   public boolean isPasteEnabled() {
      return false;
   }

   public void paste() {
      /** @todo This */
   }

   public boolean isUndoEnabled() {
      return false;
   }

   public void undo() {
      /** @todo This */
   }

   public void find() {
      /** @todo This */
   }

   public void findNext() {
      /** @todo This */
   }

   public boolean isBeautifyEnabled() {
      return false;
   }

   public void beautify() {
      /** @todo This */
   }

   public boolean deactivate() {
      active = false;
      return true;
   }

   public void cmbContent_itemStateChanged(ItemEvent e) {
      if ( doc != null && styleSheet != null )
         setXSLTText("");

      switch ( cmbContent.getSelectedIndex() ) {
         case 0:
            layoutPnlXSLTView.show(pnlXSLTView, "text/html");
            break;

         case 1:
         case 2:
            layoutPnlXSLTView.show(pnlXSLTView, "text/xml");
            xmlXSLT.setHighlighting(cmbContent.getSelectedIndex() == 1);
            break;
      }

      if ( doc != null && styleSheet != null )
         setXSLTText(text);
   }

   public void btnXSLTBrowse_actionPerformed(ActionEvent e) {
      JFileChooser fc = new JFileChooser();
      fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
      fc.setMultiSelectionEnabled(false);
      int result = fc.showDialog(this, "Select");
      if ( result == JFileChooser.APPROVE_OPTION ) {
         try {
            File f = fc.getSelectedFile();
            Document doc = DOMHelper.parse(f);
            setStylesheet(f.getAbsolutePath(), new DocWrapper(doc, null, f.getParentFile(), f.getName(), false));
         }
         catch ( Exception ex ) {
         }
      }
   }

   public void htmlXSLT_hyperlinkUpdate(final HyperlinkEvent e) {
      URL url = e.getURL();
      String urlString;
      if ( url == null )
         urlString = e.getDescription();
      else
         urlString = url.toString();

      if ( e.getEventType() == HyperlinkEvent.EventType.ENTERED )
         Admin.getInstance().setStatus("Hyperlink to " + urlString);
      else if ( e.getEventType() == HyperlinkEvent.EventType.EXITED )
         Admin.getInstance().setStatus("");
   }
}

