package risk.messagetool;

import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JTextArea;
import java.awt.BorderLayout;
import javax.swing.JScrollPane;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.Color;
import java.awt.Dimension;
import java.util.Locale;
import javax.swing.JButton;
import javax.swing.Box;
import javax.swing.JOptionPane;
import javax.swing.JEditorPane;
import javax.swing.JToggleButton;
import javax.swing.ButtonGroup;
import javax.swing.JToolBar;
import javax.swing.JTextField;
import java.awt.Insets;
import java.awt.Component;
import javax.swing.event.DocumentListener;
import javax.swing.event.DocumentEvent;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.AbstractButton;
import javax.swing.undo.UndoManager;
import javax.swing.text.Document;
import javax.swing.AbstractAction;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.KeyStroke;
import javax.swing.event.UndoableEditListener;
import javax.swing.event.UndoableEditEvent;

public class YuraTextEditor extends JPanel implements ActionListener,DocumentListener {

	private JLabel label;
	private JTextArea text;
	private JEditorPane preview;

	private JScrollPane scroll;
	private JToggleButton editb;
	private JToolBar tools;
	private TableSize pop;

	private String org;
	private Box toolbar;
	private UndoManager undo;

	public YuraTextEditor() {

		setLayout( new BorderLayout() );

		label = new JLabel();
		text = new JTextArea();
		preview = new JEditorPane("text/html","");

		Dimension size = new Dimension(80,20);

		label.setMaximumSize(size);
		label.setMinimumSize(size);
		label.setPreferredSize(size);

		preview.setEditable(false);

		text.getDocument().addDocumentListener(this);

		text.setWrapStyleWord(true);

		text.setOpaque(false);

		toolbar = Box.createHorizontalBox();

		JToggleButton previewb = new JToggleButton("Preview");
		previewb.setActionCommand("preview");
		previewb.addActionListener(this);

		editb = new JToggleButton("   Edit   ");
		editb.setActionCommand("edit");
		editb.addActionListener(this);

		Insets insets = new Insets(0,10,0,10);

		previewb.setMargin(insets);
		editb.setMargin(insets);

		ButtonGroup bg = new ButtonGroup();
		bg.add(previewb);
		bg.add(editb);

		toolbar.add( label);

		toolbar.add( editb );
		toolbar.add( previewb );

		toolbar.add( Box.createHorizontalGlue() );



		add(toolbar, BorderLayout.NORTH);

		scroll = new JScrollPane( text );

		JPanel tmp = new JPanel( new BorderLayout() );

		tools = new JToolBar();

		tools.setRollover(true);

		addSqButton("bold"	,"<html><b>B</b></html>");
		addSqButton("strike"	,"<html><s>S</s></html>");
		addSqButton("underline"	,"<html><u>U</u></html>");
		addSqButton("italic"	,"<html><i>I</i></html>");
		addSqButton("highlight"	,"<html><font style=\"background-color:yellow\">&nbsp;H&nbsp;</font></html>");
		addSqButton("color"	,"<html><font color=\"red\">F</font></html>");

		tools.addSeparator();

		addSqButton("bullet"	,"•");
		addSqButton("list"	,"1.");

		tools.addSeparator();

		addSqButton("heading"	,"H1");
		addSqButton("heading2"	,"H2");
		addSqButton("link"	,"<html><a href=\"bob\">lnk</a></html>");
		addSqButton("image"	,new ImageIcon( this.getClass().getResource("img.gif") ) );

		tools.addSeparator();

		JButton b = addButton("table"	,"table");

		tools.addSeparator();

		addSqButton("param","{0}");


		pop = new TableSize();
		pop.addActionListener(this);

		tmp.add(tools,BorderLayout.NORTH);

		tmp.setBorder( BorderFactory.createLoweredBevelBorder() );

		tmp.add(scroll);

		scroll.setBorder(null);

		add( tmp );







    undo = new UndoManager();
    Document doc = text.getDocument();
    
    // Listen for undo and redo events
    doc.addUndoableEditListener(new UndoableEditListener() {
        public void undoableEditHappened(UndoableEditEvent evt) {
            undo.addEdit(evt.getEdit());
        }
    });
    
    // Create an undo action and add it to the text component
    text.getActionMap().put("Undo",
        new AbstractAction("Undo") {
            public void actionPerformed(ActionEvent evt) {
                try {
                    if (undo.canUndo()) {
                        undo.undo();
                    }
                } catch (CannotUndoException e) {
                }
            }
       });
    
    // Bind the undo action to ctl-Z
    text.getInputMap().put(KeyStroke.getKeyStroke("control Z"), "Undo");
    
    // Create a redo action and add it to the text component
    text.getActionMap().put("Redo",
        new AbstractAction("Redo") {
            public void actionPerformed(ActionEvent evt) {
                try {
                    if (undo.canRedo()) {
                        undo.redo();
                    }
                } catch (CannotRedoException e) {
                }
            }
        });
    
    // Bind the redo action to ctl-Y
    text.getInputMap().put(KeyStroke.getKeyStroke("control Y"), "Redo");







	}

	public Component add(AbstractButton comp) {

		comp.addActionListener(this);
		return toolbar.add( comp );
	}

	private JButton addButton(String a, Object s) {

		JButton b;

		if (s instanceof Icon) {

			b = new JButton((Icon)s);

		}
		else {

			b = new JButton( s.toString() );

		}

		b.setToolTipText(a);

		b.setActionCommand("format "+a);
		b.addActionListener(this);

		Dimension size = new Dimension(50,25);
		b.setMinimumSize(size);
		b.setPreferredSize(size);
		b.setMaximumSize(size);

		b.setMargin( new Insets(0,0,0,0) );

		tools.add(b);

		return b;
	}

	private JButton addSqButton(String a,Object s) {

		JButton b = addButton(a,s);

		Dimension size = new Dimension(25,25);
		b.setMinimumSize(size);
		b.setPreferredSize(size);
		b.setMaximumSize(size);

		return b;
	}

	public void insertUpdate(DocumentEvent e) { aChange(); }
	public void removeUpdate(DocumentEvent e) { aChange(); }
	public void changedUpdate(DocumentEvent e) { }

	private void aChange() {

		if (!text.isOpaque()) { text.setOpaque(true); text.repaint(); }

		boolean changed = checkChange();

		if ( changed && (text.getBackground().equals(Color.WHITE)) ) { text.setBackground( Color.PINK ); text.repaint(); }

		if ( !changed && (text.getBackground().equals(Color.PINK)) ) { text.setBackground( Color.WHITE ); text.repaint(); }

	}


	public boolean checkChange() {

		return (

			(org==null && text.isOpaque()) ||
			(org!=null && !(text.getText().equals( org )) )

		);

	}


	private ActionListener myActionListener;
	public void addActionListener(ActionListener l) {
		myActionListener = l;
	}

	public void actionPerformed(ActionEvent ae) {

		if (ae.getActionCommand().equals("preview")) {

			tools.setVisible(false);

			String thetext = text.getText();

			preview.setText( thetext );

			scroll.setViewportView(preview);

		}
		else if (ae.getActionCommand().equals("edit")) {

			tools.setVisible(true);

			scroll.setViewportView(text);

		}
		else if (ae.getActionCommand().equals("format bold")) {

			format("<b>","</b>");

		}
		else if (ae.getActionCommand().equals("format strike")) {

			format("<s>","</s>");

		}
		else if (ae.getActionCommand().equals("format underline")) {

			format("<u>","</u>");

		}
		else if (ae.getActionCommand().equals("format italic")) {

			format("<i>","</i>");

		}
		else if (ae.getActionCommand().equals("format highlight")) {

			format("<font style=\"background-color: yellow\">","</font>");

		}
		else if (ae.getActionCommand().equals("format color")) {

			// {colour:red} color {colour}

			String a = JOptionPane.showInputDialog(this,"colour:");

			if (a!=null) {

				format("<font color=\""+a+"\">","</font>");

			}

		}
		else if (ae.getActionCommand().equals("format bullet")) {

			// bullet point // add * to start of line
			lineformatHTML("ul","li");

		}
		else if (ae.getActionCommand().equals("format list")) {

			// num list // add 1. to start of line
			lineformatHTML("ol","li");

		}
		else if (ae.getActionCommand().equals("format heading")) {

			// 1 headings 11, 111, 1111
			format("<h1>","</h1>");

		}
		else if (ae.getActionCommand().equals("format heading2")) {

			// 1 headings 11, 111, 1111
			format("<h2>","</h2>");

		}
		else if (ae.getActionCommand().equals("format link")) {

			Object[] message = new Object[4];
			message[0] = "label:";
			message[1] = new JTextField( text.getSelectedText() );
			message[2] = "URL:";
			message[3] = new JTextField();

			String[] options = {
			    "OK", 
			    "cancel"
			}; 

			int result = JOptionPane.showOptionDialog( 
			    null,                             // the parent that the dialog blocks 
			    message,                                    // the dialog message array 
			    "insert link", // the title of the dialog window 
			    JOptionPane.OK_CANCEL_OPTION,                 // option type 
			    JOptionPane.QUESTION_MESSAGE,            // message type 
			    null,                                       // optional icon, use null to use the default icon 
			    options,                                    // options string array, will be made into buttons 
			    options[0]                                  // option that should be made into a default button 
			);

			if (result == JOptionPane.OK_OPTION ) {

				String s1 = ((JTextField)message[1]).getText();
				String s2 = ((JTextField)message[3]).getText();

				// insert link [name>url]
				// if name blank [url]
				insert( "<a href=\""+s2+"\">"+((s1.equals(""))?(s2):(s1))+"</a>" );
			}

		}
		else if (ae.getActionCommand().equals("format image")) {

			Object[] message = new Object[4];
			message[0] = "alt text:";
			message[1] = new JTextField( text.getSelectedText() );
			message[2] = "URL:";
			message[3] = new JTextField();

			String[] options = {
			    "OK", 
			    "cancel"
			}; 

			int result = JOptionPane.showOptionDialog( 
			    null,                             // the parent that the dialog blocks 
			    message,                                    // the dialog message array 
			    "insert image", // the title of the dialog window 
			    JOptionPane.OK_CANCEL_OPTION,                 // option type 
			    JOptionPane.QUESTION_MESSAGE,            // message type 
			    null,                                       // optional icon, use null to use the default icon 
			    options,                                    // options string array, will be made into buttons 
			    options[0]                                  // option that should be made into a default button 
			);

			if (result == JOptionPane.OK_OPTION ) {

				String s1 = ((JTextField)message[1]).getText();
				String s2 = ((JTextField)message[3]).getText();

				// {image:/images/rhr_logo.gif}
				// {image:/images/rhr_logo.gif|This is a load of dingo's kidneys}

				insert("<img src=\""+s2+"\" alt=\""+s1+"\">");
			}

		}
		else if (ae.getActionCommand().equals("format param")) {

			String a = JOptionPane.showInputDialog(this,"number:");

			if (a!=null) { insert( "{"+a+"}" ); }

		}
		else if (ae.getActionCommand().equals("format table")) {

			java.awt.Component component = (java.awt.Component)ae.getSource();

			java.awt.Point point = component.getLocationOnScreen();

			pop.setSize(100,100);

			pop.setLocation( point.x, point.y+component.getHeight() );

			pop.showPopup();



		}
		else if (ae.getActionCommand().equals("yuratable")) {

			Dimension d = ((TableSize)ae.getSource()).getTableSize();

			String st = text.getSelectedText(); if (st==null) { st=""; }

			StringBuffer sb = new StringBuffer();

			sb.append("<table>\n");

			for (int y=0;y<d.height;y++) {

				sb.append("  <tr>\n");

				for (int x=0;x<d.width;x++) {

					sb.append("    <td>");

					if (x==0 && y==0) { sb.append( st ); }

					sb.append("</td>\n");

				}

				sb.append("  </tr>\n");
			}
			sb.append("</table>");

			insert( sb.toString() );

		}
		else {

			//if (ae.getActionCommand().equals("revert")) {
			//	revert();
			//}

			myActionListener.actionPerformed(
				new ActionEvent(this, ae.getID(), ae.getActionCommand(), ae.getWhen(), ae.getModifiers() )
			);
			//System.out.println( ae.getActionCommand() );

		}

	}

	private void format(String s) {

		format(s,s);

	}

	private void format(String s,String a) {

		String st = text.getSelectedText(); if (st==null) { st=""; }
		text.replaceSelection( s+st+a );
		text.setCaretPosition( text.getCaretPosition() -a.length() -st.length() );
		text.moveCaretPosition( text.getCaretPosition() +st.length() );
		text.grabFocus();

	}

	private void lineformat(String s) {

		try {

			int sline = text.getLineOfOffset( text.getSelectionStart() );
			int fline = text.getLineOfOffset( text.getSelectionEnd() );

			for (int a=sline; a<=fline;a++) {

				text.insert(s+" ", text.getLineStartOffset( a ) );

			}

			text.grabFocus();
		}
		catch(Exception e) {}

	}

	private void lineformatHTML(String s,String b) {

		try {

			int sline = text.getLineOfOffset( text.getSelectionStart() );
			int fline = text.getLineOfOffset( text.getSelectionEnd() );
			int num = text.getLineCount()-1;

			for (int a=sline; a<=fline;a++) {

				text.insert("  <"+b+">", text.getLineStartOffset( a ) );

				int c = text.getLineEndOffset( a );
				if (a!=num) { c--; }

				text.insert("</"+b+">", c );

			}

			int c = text.getLineEndOffset( fline );
			if (fline!=num) { c--; }

			text.insert("\n</"+s+">", c );
			text.insert("<"+s+">\n", text.getLineStartOffset( sline ) );

			text.grabFocus();
		}
		catch(Exception e) {}

	}

	private void insert(String a) {

		text.replaceSelection( a );
		text.grabFocus();

	}

	public void setText(String b) {

		org = b;

		text.setBackground( Color.WHITE );

		text.setText(b);

		text.setOpaque( b!=null );

		text.repaint();

		editb.doClick();

		undo.discardAllEdits();

	}

	public String getText() {

		return text.getText();

	}

	public void revert() {

		setText(org);

	}

	public void setLabel(String a) {

		label.setText( a );

		label.repaint();

	}

	public void setWrap(boolean a) {

		text.setLineWrap(a);

	}

}
