package lu.tudor.santec.gecamed.formeditor.gui.view;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;

import lu.tudor.santec.gecamed.core.ejb.entity.beans.XSLTemplate;
import lu.tudor.santec.gecamed.core.gui.GECAMedIconNames;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.utils.xslfo.TransFOmer;
import lu.tudor.santec.gecamed.core.gui.utils.xslfo.TransFOmer.FileType;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl;
import lu.tudor.santec.gecamed.formeditor.ejb.entity.beans.FormTemplate;
import lu.tudor.santec.gecamed.formeditor.gui.FormEditorModule;
import lu.tudor.santec.gecamed.formeditor.gui.controller.converter.FormDataConverter;
import lu.tudor.santec.gecamed.formeditor.gui.model.FormModel;
import lu.tudor.santec.i18n.Translatrix;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rtextarea.RTextArea;
import org.fife.ui.rtextarea.RTextScrollPane;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.transform.XSLTransformer;

public class XMLEditDialog extends GECAMedBaseDialogImpl
{
	/* ======================================== */
	// 		FINAL MEMBERS
	/* ======================================== */
	private static final long serialVersionUID = 1L;
	
	
	/* ---------------------------------------- */
	// 		EMPTY XSL-TEMPLATE 
	/* ---------------------------------------- */
	
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(XMLEditDialog.class.getName());
	
	private static final String CURSOR_START_TAG = "</html>";
	
	
	
	/* ======================================== */
	// 		MEMBERS
	/* ======================================== */

	private static String foTemplate;
	
	private static String htmlTemplate;
	
	private static String xslTemplate;
	
	
	private RSyntaxTextArea editor;
	
	private String 			xml;
	
	private FormTemplate 	formTemplate;
	
	
	
	/* ======================================== */
	// 		CONSTRUCTOR
	/* ======================================== */
	
	public XMLEditDialog (JFrame frame, boolean addExampleButton)
	{
		super(frame, "", OK_CANCEL_APPLY_BUTTON_MODE, new JPanel(new BorderLayout()));
		init(addExampleButton);
	}
	
	public XMLEditDialog (JDialog dialog, boolean addExampleButton)
	{
		super(dialog, "", OK_CANCEL_APPLY_BUTTON_MODE, new JPanel(new BorderLayout()));
		init(addExampleButton);
	}
		
	private void init (boolean addExampleButton)
	{
		setDialogActionListener(this);
		
		if (addExampleButton)
		{
			super.addButton(new JButton(new AbstractAction(
					Translatrix.getTranslationString("formeditor.preview"), 
					GECAMedModule.getSmallIcon(GECAMedIconNames.TEMPLATE))
			{
				private static final long serialVersionUID = 1L;
	
				public void actionPerformed(ActionEvent e)
				{
					showXmlDataExample(formTemplate, editor.getText());
				}
			}));
		}
		
		editor = new RSyntaxTextArea();
		editor.setSyntaxEditingStyle(RSyntaxTextArea.SYNTAX_STYLE_HTML);
		editor.setMarkOccurrences(true);
		editor.setTabSize(4);
		
		RTextScrollPane scrollPane = new RTextScrollPane(editor);
		scrollPane.setLineNumbersEnabled(true);
		
		mainPanel.add(scrollPane, BorderLayout.CENTER);
		
		JPanel optionPanel = new JPanel();
		optionPanel.setOpaque(false);
		
		// TODO: add buttons
		
		mainPanel.add(optionPanel, BorderLayout.NORTH);
		
		this.setSize(800, 600);
	}
	
	
	
	/* ======================================== */
	// 		METHODS
	/* ======================================== */
	
	public String editXml (XSLTemplate xslTemplate, FormTemplate formTemplate)
	{
		this.xml 			= xslTemplate.getData();
		this.formTemplate 	= formTemplate;
		
		if (xml == null || xml.trim().length() == 0)
			 editor.setText(getTemplate(xslTemplate.getFileNameExtension()));
		else editor.setText(xml);
		
		int pos = editor.getText().indexOf(CURSOR_START_TAG) - 1;
		editor.setCaretPosition(pos >= 0 && pos < editor.getText().length() ? pos : 0);
		
		setTitle(formTemplate.getName() + " - " + xslTemplate.getName());
		setLocationRelativeTo(getOwner());
		setVisible(true);
		
		return this.xml;
	}
	
	
	public void showXmlDataExample (FormTemplate template, String xslTemplate)
	{
		try
		{
			// create example data
			FormModel 	model 	= new FormModel(FormModel.TYPE_PREVIEW);
			model.loadTemplate(template, null, false);
			Element 	xmlData = FormDataConverter.createXmlOfModel(model, 
												FormDataConverter.TYPE_EDIT 	+ "/" + 
												FormDataConverter.TYPE_HISTORY 	+ "/" + 
												FormDataConverter.TYPE_PRINT);
			Document xmlDoc = new Document(xmlData);
			
			// prepare the text (XML or HTML)
			if (xslTemplate != null)
			{
				StringReader 	reader 		= new StringReader(xslTemplate);
				SAXBuilder 		builder 	= new SAXBuilder();
				Document 		stylesheet 	= builder.build(reader);
				XSLTransformer 	transformer = new XSLTransformer(stylesheet);
				xmlDoc = transformer.transform(xmlDoc);
			}
			String text = FormDataConverter.writeDocument(xmlDoc);
			
			// prepare the text area 
			JPanel 			mainPanel 	= new JPanel(new BorderLayout());
			RSyntaxTextArea xmlTextArea = new RSyntaxTextArea();
			JPopupMenu 		popupMenu 	= new JPopupMenu();
			
			popupMenu.add((RTextArea.getAction(RTextArea.SELECT_ALL_ACTION)));
			popupMenu.add((RTextArea.getAction(RTextArea.COPY_ACTION)));
			
			xmlTextArea.setText(text);
			xmlTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);
			xmlTextArea.setEditable(false);
			xmlTextArea.setLineWrap(false);
			xmlTextArea.setPopupMenu(popupMenu);
			
			if (xslTemplate == null)
				mainPanel.add(new JScrollPane(xmlTextArea), BorderLayout.CENTER);
			else
			{
				JEditorPane htmlPane = new JEditorPane();
				htmlPane.setContentType("text/html");
				int pos = text.indexOf("<html>");
				text = text.substring(pos > 0 ? pos : 0);
				htmlPane.setText(text);
				htmlPane.setOpaque(true);
				
				JTabbedPane tabbedPane = new JTabbedPane();
				tabbedPane.addTab(
						Translatrix.getTranslationString("XML"), 
						new JScrollPane(xmlTextArea));
				tabbedPane.addTab(
						Translatrix.getTranslationString("HTML"), 
						new JScrollPane(htmlPane));
				mainPanel.add(tabbedPane, BorderLayout.CENTER);
			}
			
			// prepare & show the dialog
			GECAMedBaseDialog dialog 	= new GECAMedBaseDialogImpl(this, 
					getTitle(), GECAMedBaseDialogImpl.OK_BUTTON_MODE, mainPanel);
			dialog.pack();
			Dimension 	dimension 	= dialog.getSize();
			JFrame 		mainFrame 	= MainFrame.getInstance();
			int 		maxWidth 	= mainFrame.getWidth()  - 150;
			int 		maxHeight 	= mainFrame.getHeight() - 150;
			
			dialog.setModal(false);
			
			if (dialog.getWidth() > maxWidth)
				dimension.width = maxWidth;
			if (dialog.getHeight() > maxHeight)
				dimension.height = maxHeight;
			dialog.setSize(dimension);
			
			dialog.setLocationRelativeTo(dialog.getOwner());
			dialog.setVisible(true);
		} 
		catch (Exception e)
		{
			logger.log(Level.ERROR, e.getMessage(), e);
		}
	}
	
	
	@Override
	public void okActionCalled()
	{
		/* ---------------------------------------- */
		// 		THIS IS THE OK BUTTON
		/* ---------------------------------------- */
		// save the edited text and close the editor
		this.xml = editor.getText();
		super.okActionCalled();
	}
	
	@Override
	public void applyActionCalled()
	{
		/* ---------------------------------------- */
		// 		THIS IS THE APPLY BUTTON
		/* ---------------------------------------- */
		// just save the edited text
		this.xml = editor.getText();
		super.applyActionCalled();
	}
	
	
	public static String getTemplate (String extension)
	{
		String template = null;
		
		if (extension == null || extension.length() == 0)
			return "";
		
		extension = extension.toLowerCase();
		
		if (extension.equals(TransFOmer.HTML_FORMAT))
			template = getHtmlTemplate();
		else 
		{
			FileType[] fileTypes = TransFOmer.SUPPORTED_OUTPUT_TYPES_FOR_TEXT;
			for (FileType fileType : fileTypes)
			{
				if (fileType.getExtension().equals(extension))
				{
					template = getFoTemplate();
					break;
				}
			}
			if (template == null)
				template = getXslTemplate();
		}
		
		return template;	
	}
	
	
	public static String getFoTemplate ()
	{
		if (foTemplate == null)
			foTemplate = loadStringFromResource("fo_template.xsl");
		
		return foTemplate;
	}
	

	public static String getHtmlTemplate ()
	{
		if (htmlTemplate == null)
			htmlTemplate = loadStringFromResource("html_template.xsl");
		
		return htmlTemplate;
	}
	
	
	public static String getXslTemplate ()
	{
		if (xslTemplate == null)
			xslTemplate = loadStringFromResource("xsl_template.xsl");
		
		return xslTemplate;
	}
	
	
	private static String loadStringFromResource (String resourceName)
	{
		InputStream is = null;
		String 		result;
		
		try
		{
			is 		= FormEditorModule.class.getResourceAsStream("resources/"+resourceName);
			result 	= IOUtils.toString(is, "UTF-8");
		} 
		catch (IOException e)
		{
			logger.log(Level.ERROR, e.getMessage(), e);
			result 	= "";
		}
		finally
		{
			try
			{
				if (is != null)
					is.close();
			} 
			catch (IOException e)
			{
				logger.log(Level.ERROR, e.getMessage(), e);
			}
		}
		
		return result;
	}
}
