/*******************************************************************************
 * Copyright (c) 2001, 2006 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.wst.xml.ui.internal.validation.core.errorinfo;

import java.util.List;
import com.ibm.icu.util.StringTokenizer;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.wst.xml.core.internal.validation.core.ValidationMessage;
import org.eclipse.wst.xml.ui.internal.validation.XMLValidationUIMessages;


public class ReferencedFileErrorDialog extends Dialog {
	protected TaskListTableViewer tableViewer;
	protected List errorList;
	protected String markedUpDetailsMessage;
	protected String contextFile;
	protected String referencedFile;
	protected StyledText styledText;
	protected Text fullFileNameField;

	public ReferencedFileErrorDialog(Shell parentShell, List errorList, String contextFile, String referencedFile) {
		super(parentShell);

		int styleBits = getShellStyle() | SWT.RESIZE;
		styleBits &= ~SWT.APPLICATION_MODAL;

		setShellStyle(styleBits);
		this.errorList = errorList;

		this.referencedFile = referencedFile;
		this.contextFile = contextFile;
		this.markedUpDetailsMessage = getMarkedUpDetailsMessage();
	}

	public int createAndOpen() {
		create();
		getShell().setText(XMLValidationUIMessages._UI_REF_FILE_ERROR_DETAILS);

		setBlockOnOpen(false);
		return open();
	}


	protected Control createButtonBar(Composite parent) {
		Composite composite = new Composite(parent, SWT.NONE);
		composite.setLayout(new GridLayout(2, false));
		composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

		fullFileNameField = new Text(composite, SWT.NONE);
		fullFileNameField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		fullFileNameField.setBackground(parent.getBackground());
		fullFileNameField.setEditable(false);

		super.createButtonBar(composite);

		return composite;
	}

	protected Control createDialogArea(Composite parent) {
		Composite dialogArea = (Composite) super.createDialogArea(parent);
		dialogArea.setLayout(new GridLayout());

		Composite c = new Composite(dialogArea, SWT.NONE);
		c.setLayout(new GridLayout());
		c.setLayoutData(createGridData(true, -1, 200));

		styledText = new StyledText(c, SWT.MULTI | SWT.WRAP);
		styledText.setBackground(c.getBackground());
		setStyledText(styledText, markedUpDetailsMessage);
		styledText.setEditable(false);
		styledText.setLayoutData(createGridData(false, 650, -1));

		MouseListener mouseListener = new MouseListener();
		styledText.addMouseMoveListener(mouseListener);

		tableViewer = new TaskListTableViewer(c, 10);
		tableViewer.setInput(errorList);
		tableViewer.addSelectionChangedListener(new InternalSelectionListener());
		tableViewer.getControl().setLayoutData(createGridData(true, 700, -1));
		return dialogArea;
	}

	String getFullURI(int offset) {
		String uri = ""; //$NON-NLS-1$
		int index = getIndex(offset);
		if (index != -1) {
			if ((index == 0) || (index == 2) || (index == 3)) {
				uri = referencedFile;
			}
			else {
				uri = contextFile;
			}
		}
		return uri;
	}

	private int getIndex(int offset) {
		int result = -1;
		StyleRange[] range = styledText.getStyleRanges();
		for (int i = 0; i < range.length; i++) {
			int l = range[i].start;
			int r = l + range[i].length;
			if ((l <= offset) && (r >= offset)) {
				result = i;
				break;
			}
		}
		return result;
	}

	class MouseListener implements MouseMoveListener {
		public void mouseMove(MouseEvent event) {
			String toolTipText = ""; //$NON-NLS-1$
			try {

				int offset = styledText.getOffsetAtLocation(new Point(event.x, event.y));
				toolTipText = getFullURI(offset);

			}
			catch (Exception e) {
				// Do nothing.
			}
			styledText.setToolTipText(toolTipText);
			if ((toolTipText != null) && (toolTipText.length() > 0)) {
				fullFileNameField.setText(toolTipText);
			}
		}
	}

	private String getMarkedUpDetailsMessage() {
		String detailsMessage = ""; //$NON-NLS-1$
		// TODO... need to move '_UI_REF_FILE_ERROR_DESCRIPTION' to this
		// plugin's properties file
		//			
		String string = XMLValidationUIMessages._UI_REF_FILE_ERROR_DESCRIPTION;
		// TODO... need to edit the properties file to remove "'" characters
		// from the string
		// I'm using these characters to markup the bold font. It's safer if I
		// add these programtically.
		//
		string = removePattern(string, "'"); //$NON-NLS-1$

		String c = "'" + getLastSegment(contextFile) + "'"; //$NON-NLS-1$ //$NON-NLS-2$
		String r = "'" + getLastSegment(referencedFile) + "'"; //$NON-NLS-1$ //$NON-NLS-2$

		detailsMessage = NLS.bind(string, new Object[]{r, c, r, c});
		return detailsMessage;
	}

	private String removePattern(String string, String pattern) {
		while (true) {
			int index = string.indexOf(pattern);
			if (index != -1) {
				string = string.substring(0, index) + string.substring(index + pattern.length());
			}
			else {
				break;
			}
		}
		return string;
	}

	private void setStyledText(StyledText styledText, String text) {
		String visibleMessage = ""; //$NON-NLS-1$
		for (StringTokenizer st = new StringTokenizer(markedUpDetailsMessage, "'", false); st.hasMoreTokens();) //$NON-NLS-1$
		{
			String token = st.nextToken();
			visibleMessage += token;
		}

		styledText.setText(visibleMessage);
		// dw Font font = styledText.getFont();

		boolean inQuote = false;
		int position = 0;
		for (StringTokenizer st = new StringTokenizer(markedUpDetailsMessage, "'", true); st.hasMoreTokens();) //$NON-NLS-1$
		{
			String token = st.nextToken();

			if (token.equals("'")) //$NON-NLS-1$
			{
				inQuote = !inQuote;
			}
			else {
				if (inQuote) {
					try {

						StyleRange style = new StyleRange(position, token.length(), styledText.getForeground(), styledText.getBackground(), SWT.BOLD);
						styledText.setStyleRange(style);
					}
					catch (Exception e) {
						e.printStackTrace();
					}
				}
				position = position + token.length();
			}
		}
	}

	private static GridData createGridData(boolean fillBoth, int w, int h) {
		GridData gd = new GridData(fillBoth ? GridData.FILL_BOTH : GridData.FILL_HORIZONTAL);
		gd.widthHint = w;
		gd.heightHint = h;
		return gd;
	}

	private static String getLastSegment(String uri) {
		String result = uri;
		int index = Math.max(uri.lastIndexOf("/"), uri.lastIndexOf("\\")); //$NON-NLS-1$ //$NON-NLS-2$
		if (index != -1) {
			result = uri.substring(index + 1);
		}
		return result;
	}

	protected class InternalSelectionListener implements ISelectionChangedListener {
		public void selectionChanged(SelectionChangedEvent event) {
			ISelection selection = event.getSelection();
			if (selection instanceof StructuredSelection) {
				ValidationMessage validationMessage = (ValidationMessage) ((StructuredSelection) selection).getFirstElement();
				if (validationMessage != null) {
					String uristring = validationMessage.getUri();
					ReferencedFileErrorUtility.openEditorAndGotoError(uristring, validationMessage.getLineNumber(), validationMessage.getColumnNumber());
				}
			}
		}
	}
}
