/**************************************************************************
 OmegaT - Computer Assisted Translation (CAT) tool 
          with fuzzy matching, translation memory, keyword search, 
          glossaries, and translation leveraging into updated projects.

 Copyright (C) 2018 Thomas Cordonnier
               Home page: http://www.omegat.org/
               Support center: http://groups.yahoo.com/group/OmegaT/

 This file is part of OmegaT.

 OmegaT 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 3 of the License, or
 (at your option) any later version.

 OmegaT 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, see <http://www.gnu.org/licenses/>.
 **************************************************************************/

package org.omegat.util.gui;

import org.omegat.gui.editor.mark.TransparentHighlightPainter;

import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Highlighter;
import javax.swing.text.DefaultHighlighter.DefaultHighlightPainter;
import javax.swing.text.JTextComponent;
import javax.swing.text.Document;

import java.util.regex.Pattern;
import java.util.regex.Matcher;

/**
 * This class adds to a Swing text component the syntax highlighting for regular expressions
 * 
 * @author Thomas Cordonnier
 */
@SuppressWarnings("serial")
public class RegexHighlightListener implements DocumentListener {

	// This set of constants enable to create a bit-field integer to decide what to highlight or not
	public static final int FLAG_ESCAPE_SEQUENCE = 0x01;
	public static final int FLAG_PTN_META_CHARACTER = 0x02;
	public static final int FLAG_JOKER_CHARACTER = 0x04;
	public static final int FLAG_REPLACE_VARIABLE = 0x08;
	public static final int FLAG_REPLACE_CASE = 0x10;
	public static final int FLAG_TEMPLATE_VAR = 0x20;

	// This set of constants define modes using combination of previous ones
	public static final int MODE_REGEX_FIND = FLAG_ESCAPE_SEQUENCE + FLAG_PTN_META_CHARACTER;
	public static final int MODE_REGEX_REPLACE = FLAG_REPLACE_VARIABLE + FLAG_REPLACE_CASE;
	public static final int MODE_NON_REGEX = FLAG_JOKER_CHARACTER;
	public static final int MODE_TEMPLATE_ML = FLAG_TEMPLATE_VAR;
	

	private final Highlighter h;
	private final Document doc;
	private final int mode;

    public RegexHighlightListener(JTextComponent comp, int mode) {
		this.doc = comp.getDocument(); this.h = comp.getHighlighter(); this.mode = mode; recalculate();
	}

    public void changedUpdate(DocumentEvent e) {
    }

    public void insertUpdate(DocumentEvent e) {
		recalculate();
    }

    public void removeUpdate(DocumentEvent e) {
		recalculate();
    }

	public static final Pattern PTN_ESCAPE_SEQUENCE = Pattern.compile("(?<!\\\\)\\\\.");
	public static final Pattern PTN_META_CHAR = Pattern.compile(
	     "(?<!\\\\)[\\+\\*\\?\\(\\)\\[\\]\\|\\.\\{\\}]"    // meta-character non-preceeded by \
	     + "((?<=\\()\\?<?[:=!])?"     // also accept lookaround sequences if meta-character was (
	     + "((?<=\\[)\\^)?");          // also accept ^ if meta-character was [
	public static final Pattern PTN_JOKER_CHAR = Pattern.compile("[\\*\\?]"); // cannot be escaped via backslash!
	public static final Pattern PTN_REPLACE_VARIABLE = Pattern.compile("(?<!\\\\)\\$(\\d+)"); 
	public static final Pattern PTN_REPLACE_CASE = Pattern.compile("(?<!\\\\)\\\\[LlUuE\\\\$]");
	public static final Pattern PTN_TEMPLATE_VARIABLE = Pattern.compile("(?<!\\\\)\\$\\{[\\w\\-]+\\}"); 
	
	public static final java.util.Map<Pattern,Highlighter.HighlightPainter> PAINTERS = new java.util.HashMap<>();
	static {
		PAINTERS.put (PTN_ESCAPE_SEQUENCE, new DefaultHighlightPainter(java.awt.Color.CYAN));
		PAINTERS.put (PTN_META_CHAR, new DefaultHighlightPainter(java.awt.Color.ORANGE));
		PAINTERS.put (PTN_JOKER_CHAR, new DefaultHighlightPainter(java.awt.Color.ORANGE));
		PAINTERS.put (PTN_REPLACE_VARIABLE, new DefaultHighlightPainter(java.awt.Color.GREEN));
		PAINTERS.put (PTN_REPLACE_CASE, new DefaultHighlightPainter(java.awt.Color.CYAN));		
		PAINTERS.put (PTN_TEMPLATE_VARIABLE, new DefaultHighlightPainter(java.awt.Color.GREEN));
	}
	
	
	private void recalculate() {
		h.removeAllHighlights();
		try {
			String text = doc.getText(0, doc.getLength());
			
			int flag = 1;
			for (Pattern ptn: new Pattern[] { PTN_ESCAPE_SEQUENCE, PTN_META_CHAR, PTN_JOKER_CHAR, PTN_REPLACE_VARIABLE, PTN_REPLACE_CASE, PTN_TEMPLATE_VARIABLE }) {
				if ((flag & this.mode) == 0) { flag *= 2; continue; } else flag *= 2;
				Matcher m = ptn.matcher(text);
				while (m.find()) 
					h.addHighlight (m.start(), m.end(), PAINTERS.get(ptn));				
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
