/**
 *#########################################################################
 *
 * 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.
 *
 * Copyright (C) 2024 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.gui;

import org.fife.ui.rsyntaxtextarea.SyntaxConstants;

import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.Dictionary;
import org.greenstone.gatherer.Gatherer;
import org.greenstone.gatherer.util.StaticStrings;
import org.greenstone.gatherer.util.Utility;
import org.greenstone.gatherer.util.XMLTools;

import org.w3c.dom.*;

import java.io.File;
import java.io.IOException;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;


public class XMLFileEditor extends TextFileEditor 
    implements ActionListener, DocumentListener
{
    protected JTextArea editor_msgarea;

  /** Optional - User can add some complex elements by clcking a button */
  /** Needs to be set up in sub class */
  protected boolean add_elements_enabled = false;
  protected String elements_xml_file;
  protected Document elements_available_for_insertion;
  protected JComboBox chooseElementComboBox;
  protected GLIButton addElementButton;
  protected JPanel add_elements_panel;

  protected String[] nonEscapingTagNames = {};
  
    public XMLFileEditor(File xml_file) {
	
      super(xml_file, SyntaxConstants.SYNTAX_STYLE_XML);

	this.add_elements_enabled = addElementsEnabled();
        this.elements_xml_file = getElementsXMLFileString();
        
	// Most of the validation_msg_panel code is from Format4gs3Manager.java
	JPanel validation_msg_panel = new JPanel();
	JLabel validation_label = new JLabel(Dictionary.get("CDM.FormatManager.MessageBox"));
	validation_label.setBorder(new EmptyBorder(10,10,10,10)); // add some margin
	editor_msgarea = new JTextArea();
	
	editor_msgarea.setCaretPosition(0);
	editor_msgarea.setLineWrap(true);
	editor_msgarea.setRows(3);
	editor_msgarea.setWrapStyleWord(false);
	editor_msgarea.setEditable(false);
	editor_msgarea.setToolTipText(Dictionary.get("CDM.FormatManager.MessageBox_Tooltip"));
	validation_msg_panel.setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0));
	validation_msg_panel.setLayout(new BorderLayout(5, 0));
	validation_msg_panel.add(validation_label, BorderLayout.WEST);
	validation_msg_panel.add(new JScrollPane(editor_msgarea), BorderLayout.CENTER);


        // if we have some predefined elements to add
        if (add_elements_enabled) {
          JLabel addElementLabel = new JLabel(Dictionary.get("XMLFileEditor.Add_Element_Label"));

          Enum[] element_options = getElementOptions();
          if (element_options != null) {
            chooseElementComboBox = new JComboBox(element_options);
            addElementButton = new GLIButton(Dictionary.get("XMLFileEditor.Add_Label"), Dictionary.get("XMLFileEditor.Add_Element_Tooltip"));
            elements_available_for_insertion = XMLTools.parseXMLFile(this.elements_xml_file, true);
            
            addElementButton.addActionListener(this);

            // Elements can't be added if gli/classes/xml/elementsForInsertion.xml file
            // does not exist or can't be parsed
            if(elements_available_for_insertion == null) {
              add_elements_enabled = false;
              addElementButton.setEnabled(false);
            }
          }
        
          // LAYOUT
          add_elements_panel = new JPanel(new FlowLayout());
          add_elements_panel.setComponentOrientation(Dictionary.getOrientation());
          add_elements_panel.add(addElementLabel);
          add_elements_panel.add(chooseElementComboBox);
          add_elements_panel.add(addElementButton);

          toolbars_panel.add(add_elements_panel, BorderLayout.CENTER); 
        }

	content_pane.add(validation_msg_panel, BorderLayout.NORTH);

        setFileXMLInEditor();
        editor.setCaretPosition(0);
		
    }

  // this is called by TextFileEditor constructor.
  // override this to do nothing, as we need to wait until all out own components are set up
  // before parsing the file contents
  protected void setFileTextInEditor() {
  }

  // this is where we parse and add the xml content
  protected void setFileXMLInEditor() {

    // NOW WE CAN PREPARE THE ACTUAL CONTENT TO GO INTO THE XML EDITOR TEXTAREA
    String xml_str = Utility.readUTF8File(config_file);
    if (!xml_str.equals("")) {
      // re-parse to get error msg to display in validation field
      
      // but first get rid of the preprocessing instruction, as this will fail parsing
      String processingInstruction = getProcessingInstruction(xml_str);
      xml_str = xml_str.replace(processingInstruction, "").trim(); // also trim newline at start
    }
    if(!xml_str.equals("")) {
      
      String msg = XMLTools.parse(xml_str); // re-parse
      editor_msgarea.setBackground(Color.red);
      editor_msgarea.setText(msg); // display the parsing error
      save_button.setEnabled(false);
      if (add_elements_enabled) {
        // why??
        //addElementButton.setEnabled(false);
      }
      editor.setText(xml_str); // display the xml contents with error and all		
      
    } else {
      editor.setText("");
      editor_msgarea.setText("");
    }	  
  }
  /** implement this if you want pre defined elements to add */
  protected Enum[] getElementOptions() {
    return null;
  }

  protected void saveFile() {
    // write out the XML to the file, then do any custom action
    // eg for collectionCOnfig.xml, we need to close then reopen the collection
    
    // already know the xml in the textarea is valid, else the save_button would have been inactive
    Document xml_file_doc = XMLTools.getDOM(editor.getText());
    // This code from FormatConversionDialog.dispose() 
    // saves the XML, prepending the processing instruction (<?xml ... ?>)
    //String[] nonEscapingTagNames = { StaticStrings.FORMAT_STR, StaticStrings.DISPLAYITEM_STR };
    XMLTools.writeXMLFile(this.config_file, xml_file_doc, nonEscapingTagNames);


  }
  
    public void actionPerformed(ActionEvent e) {
	
	if(e.getSource() == addElementButton) {

          addElementToFile();
	}
        else {
          super.actionPerformed(e);
        }
        
    }

  protected boolean addElementsEnabled() {
    return false;
  }
  protected String getElementsXMLFileString() {
    return null;
  }
  
  //sub class to implement if needed
  protected void addElementToFile() {

  }

    // This method returns a proper processing instruction (starts with <?xml and ends with ?>)
    // else the empty string is returned
    public String getProcessingInstruction(String xmlStr) {
	String processingInstruction = "";

	xmlStr = xmlStr.trim();
	if(xmlStr.startsWith("<?xml")) {
	    int endIndex = xmlStr.indexOf("?>"); // end of processing instruction
	    
	    if(endIndex != -1) {
		endIndex += 2;
		processingInstruction = xmlStr.substring(0, endIndex);
	    }
	}	
	return processingInstruction;
    }

    public void update()
    {
	
	String xml_str = editor.getText();

	// Processing instructions "<?xml...?>" are no longer displayed in the editor (but
	// they are written out to the file on save) so we don't need to deal with them here.
	
	// can't parse with processing instruction <?xml...?>, so remove that
	///String processingInstruction = getProcessingInstruction(xml_str);
	///xml_str = xml_str.replace(processingInstruction, "");	
	// now can parse the XML portion without the processing instruction,
	// while the original XML remains unchanged in the editor area	
	// If the processing instruction was incomplete, then xml_str would still
	// include the incomplete processing instruction, and parsing below will catch the error.
	
	String msg = XMLTools.parse(xml_str);
	editor_msgarea.setText(msg);
	
	if (msg.startsWith(XMLTools.WELLFORMED))
	    {		   
		editor_msgarea.setBackground(Color.white);
		save_button.setEnabled(true);
	    }
	else
	    {		 
		editor_msgarea.setBackground(Color.red);
		save_button.setEnabled(false);
                if (add_elements_enabled) {
                  addElementButton.setEnabled(false);
                }
            }
    }
 
}
