/*******************************************************************************
 * Copyright (c) 2007, 2009 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * IBM Corporation - Initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.internal.ui.language;

import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.Map.Entry;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.content.IContentTypeManager;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.AccessibleAdapter;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.LanguageManager;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;

import org.eclipse.cdt.internal.ui.preferences.PreferencesMessages;
import org.eclipse.cdt.internal.ui.util.Messages;

public class ProjectLanguageMappingWidget extends LanguageMappingWidget {

	static final String CONTENT_TYPE_KEY_DELIMITER = "::"; //$NON-NLS-1$

	private static final String ALL_CONFIGURATIONS = ""; //$NON-NLS-1$

	private static final int CONFIGURATION_COLUMN = 0;

	private static final int CONTENT_TYPE_COLUMN = 1;

	private static final int LANGUAGE_COLUMN = 2;
	
	private Map<String, Map<String, String>> fConfigurationContentTypeMappings;

	public void setMappings(Map<String, Map<String, String>> contentTypeMappings) {
		fConfigurationContentTypeMappings = contentTypeMappings;
	}

	public Map<String, Map<String, String>> getContentTypeMappings() {
		return fConfigurationContentTypeMappings;
	}

	@Override
	public Composite createContents(Composite parent, String description) {
		fContents = new Composite(parent, SWT.NONE);
		fContents.setLayout(new GridLayout(2, false));

		if (description != null) {
			createHeader(parent, description);
		}

		Composite tableParent = new Composite(fContents, SWT.NONE);
		tableParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

		fTable = new Table(tableParent, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.FULL_SELECTION);
		fTable.setHeaderVisible(true);
		fTable.setLinesVisible(true);
		fTable.getAccessible().addAccessibleListener(new AccessibleAdapter() {
			@Override
			public void getName(AccessibleEvent e) {
				e.result = PreferencesMessages.ProjectLanguagesPropertyPage_mappingTableTitle;
			}
		});
		fTable.setToolTipText(PreferencesMessages.ProjectLanguagesPropertyPage_mappingTableTitle);

		TableColumn configurationColumn = new TableColumn(fTable, SWT.LEAD);
		configurationColumn.setText(PreferencesMessages.ProjectLanguagesPropertyPage_configurationColumn);
		
		TableColumn contentTypeColumn = new TableColumn(fTable, SWT.LEAD);
		contentTypeColumn.setText(PreferencesMessages.ProjectLanguagesPropertyPage_contentTypeColumn);

		TableColumn languageColumn = new TableColumn(fTable, SWT.LEAD);
		languageColumn.setText(PreferencesMessages.ProjectLanguagesPropertyPage_languageColumn);

		TableColumnLayout layout = new TableColumnLayout();
		layout.setColumnData(configurationColumn, new ColumnWeightData(1, MINIMUM_COLUMN_WIDTH, true));
		layout.setColumnData(contentTypeColumn, new ColumnWeightData(1, MINIMUM_COLUMN_WIDTH, true));
		layout.setColumnData(languageColumn, new ColumnWeightData(1, MINIMUM_COLUMN_WIDTH, true));
		tableParent.setLayout(layout);

		Composite buttons = new Composite(fContents, SWT.NONE);
		buttons.setLayout(new GridLayout());
		buttons.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false));

		Button addButton = new Button(buttons, SWT.PUSH);
		addButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
		addButton.setText(PreferencesMessages.ProjectLanguagesPropertyPage_addMappingButton);
		addButton.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				IProject project = (IProject) getElement().getAdapter(IProject.class);
				ICProjectDescription description = CoreModel.getDefault().getProjectDescription(project, false);
				ICConfigurationDescription[] configurations = description.getConfigurations();
				ProjectContentTypeMappingDialog dialog = new ProjectContentTypeMappingDialog(fContents.getShell(), configurations);
				
				dialog.setContentTypeFilter(createContentTypeFilter(fConfigurationContentTypeMappings));
				dialog.setBlockOnOpen(true);

				if (dialog.open() == Window.OK) {
					String contentType = dialog.getContentTypeID();
					String language = dialog.getLanguageID();
					String configuration = dialog.getConfigurationID();
					if (configuration == null) {
						configuration = ALL_CONFIGURATIONS;
					}
					Map<String, String> contentTypeMappings = fConfigurationContentTypeMappings.get(configuration);
					if (contentTypeMappings == null) {
						contentTypeMappings = new TreeMap<String, String>();
						fConfigurationContentTypeMappings.put(configuration, contentTypeMappings);
					}
					contentTypeMappings.put(contentType, language);
					setChanged(true);
					
					IContentTypeManager contentTypeManager = Platform.getContentTypeManager();
					fAffectedContentTypes.add(contentTypeManager.getContentType(contentType));
					refreshMappings();
				}
			}
		});

		Button removeButton = new Button(buttons, SWT.PUSH);
		removeButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
		removeButton.setText(PreferencesMessages.ProjectLanguagesPropertyPage_removeMappingButton);
		removeButton.addListener(SWT.Selection, new Listener() {

			public void handleEvent(Event event) {
				TableItem[] selection = fTable.getSelection();

				for (int i = 0; i < selection.length; i++) {
					LanguageTableData data = (LanguageTableData) selection[i].getData();
					String contentType = data.contentTypeId;

					String configurationId;
					if (data.configuration == null) {
						configurationId = ALL_CONFIGURATIONS;
					} else {
						configurationId = data.configuration.getId();
					}
					
					Map<String, String> contentTypeMappings = fConfigurationContentTypeMappings.get(configurationId);
					if (contentTypeMappings != null) {
						contentTypeMappings.remove(contentType);
					}

					IContentTypeManager contentTypeManager = Platform.getContentTypeManager();
					fAffectedContentTypes.add(contentTypeManager.getContentType(contentType));
				}
				
				if (selection.length > 0) {
					setChanged(true);
				}

				refreshMappings();
			}
		});

		refreshMappings();
		return fContents;
	}

	private Set<String> createContentTypeFilter(Map<String, Map<String, String>> mappings) {
		Set<String> filter = new HashSet<String>();
		Iterator<Entry<String, Map<String, String>>> configurationContentTypeMappings = mappings.entrySet().iterator();
		while (configurationContentTypeMappings.hasNext()) {
			Entry<String, Map<String, String>> entry = configurationContentTypeMappings.next();
			String configuration = entry.getKey();
			Iterator<Entry<String, String>> contentTypeMappings = entry.getValue().entrySet().iterator();
			while (contentTypeMappings.hasNext()) {
				Entry<String, String> contentTypeEntry = contentTypeMappings.next();
				String contentType = contentTypeEntry.getKey();
				filter.add(createFilterKey(configuration, contentType));
			}
		}
		return filter;
	}
	
	@Override
	public void refreshMappings() {
		if (fTable == null) {
			return;
		}
		
		fTable.removeAll();
		Iterator<Entry<String, Map<String, String>>> mappings = fConfigurationContentTypeMappings.entrySet().iterator();

		IContentTypeManager contentTypeManager = Platform.getContentTypeManager();

		IProject project = (IProject) getElement().getAdapter(IProject.class);
		ICProjectDescription description = CoreModel.getDefault().getProjectDescription(project, false);

		while (mappings.hasNext()) {
			Entry<String, Map<String, String>> configurationEntry = mappings.next();
			String configurationId = configurationEntry.getKey();
			Iterator<Entry<String, String>> contentTypeMappings = configurationEntry.getValue().entrySet().iterator();
			while (contentTypeMappings.hasNext()) {
				Entry<String, String> entry = contentTypeMappings.next();
				TableItem item = new TableItem(fTable, SWT.NONE);
	
				String contentType = entry.getKey();
				String contentTypeName = contentTypeManager.getContentType(contentType).getName();
				String languageId = entry.getValue();
				String languageName = LanguageManager.getInstance().getLanguage(languageId).getName();
				
				ICConfigurationDescription configuration = description.getConfigurationById(configurationId);
				
				item.setData(new LanguageTableData(configuration, contentType, languageId));
				
				if (configuration == null) {
					item.setText(CONFIGURATION_COLUMN, PreferencesMessages.ContentTypeMappingsDialog_allConfigurations);
				} else {
					item.setText(CONFIGURATION_COLUMN, configuration.getName());
				}
				
				if (fOverriddenContentTypes.contains(contentType)) {
					item.setText(CONTENT_TYPE_COLUMN, Messages.format(PreferencesMessages.ProjectLanguagesPropertyPage_overriddenContentType, contentTypeName));
					item.setFont(fOverriddenFont);
				} else {
					item.setText(CONTENT_TYPE_COLUMN, contentTypeName);
				}
				item.setText(LANGUAGE_COLUMN, languageName);
			}
		}
		
		if (fChild != null) {
			Set<String> overrides = new HashSet<String>(createWorkspaceContentTypeFilter(fConfigurationContentTypeMappings));
			fChild.setOverriddenContentTypes(overrides);
			fChild.refreshMappings();
		}
	}
	
	private Set<String> createWorkspaceContentTypeFilter(Map<String, Map<String, String>> configurationContentTypeMappings) {
		Map<String, String> contentTypeMappings = configurationContentTypeMappings.get(ALL_CONFIGURATIONS);
		if (contentTypeMappings == null) {
			return Collections.emptySet();
		}
		return contentTypeMappings.keySet();
	}

	static String createFilterKey(String configurationId, String contentTypeId) {
		return configurationId + CONTENT_TYPE_KEY_DELIMITER + contentTypeId;
	}
	
	private static class LanguageTableData {
		ICConfigurationDescription configuration;
		String contentTypeId;
		
		LanguageTableData(ICConfigurationDescription configuration, String contentTypeId, String languageId) {
			this.configuration = configuration;
			this.contentTypeId = contentTypeId;
		}
	}
}
