/********************************************************************************
 * Copyright (c) 2011-2017 Red Hat Inc. and/or its affiliates and others
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 1.0 which is available at
 * http://www.eclipse.org/legal/epl-v10.html.
 *
 * SPDX-License-Identifier: EPL-1.0
 ********************************************************************************/
package org.eclipse.ceylon.ide.eclipse.code.editor;
import static org.eclipse.ceylon.ide.eclipse.code.preferences.CeylonPreferenceInitializer.AUTO_ACTIVATION;
import static org.eclipse.ceylon.ide.eclipse.code.preferences.CeylonPreferenceInitializer.AUTO_ACTIVATION_DELAY;
import static org.eclipse.ceylon.ide.eclipse.code.preferences.CeylonPreferenceInitializer.AUTO_INSERT;
import static org.eclipse.ceylon.ide.eclipse.code.preferences.CeylonPreferenceInitializer.AUTO_INSERT_PREFIX;
import static org.eclipse.ceylon.ide.eclipse.java2ceylon.Java2CeylonProxies.completionJ2C;
import static org.eclipse.ceylon.ide.eclipse.util.EditorUtil.createColor;
import static org.eclipse.ceylon.ide.eclipse.util.EditorUtil.getPopupStyle;
import static org.eclipse.ceylon.ide.eclipse.util.Highlights.DOC_BACKGROUND;
import static org.eclipse.ceylon.ide.eclipse.util.Highlights.getCurrentThemeColor;
import static org.eclipse.jdt.ui.PreferenceConstants.APPEARANCE_JAVADOC_FONT;
import static org.eclipse.jface.dialogs.DialogSettings.getOrCreateSection;
import static org.eclipse.jface.text.AbstractInformationControlManager.ANCHOR_GLOBAL;
import static org.eclipse.jface.text.IDocument.DEFAULT_CONTENT_TYPE;
import static org.eclipse.ui.texteditor.AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT;
import static org.eclipse.ui.texteditor.AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND;
import static org.eclipse.ui.texteditor.AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT;
import org.eclipse.jface.bindings.keys.KeySequence;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.IAutoEditStrategy;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextDoubleClickStrategy;
import org.eclipse.jface.text.ITextHover;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.ITextViewerExtension2;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.contentassist.ContentAssistEvent;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.ICompletionListener;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistant;
import org.eclipse.jface.text.contentassist.IContentAssistantExtension2;
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
import org.eclipse.jface.text.information.IInformationPresenter;
import org.eclipse.jface.text.information.IInformationProvider;
import org.eclipse.jface.text.information.IInformationProviderExtension;
import org.eclipse.jface.text.information.InformationPresenter;
import org.eclipse.jface.text.presentation.PresentationReconciler;
import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
import org.eclipse.jface.text.reconciler.IReconciler;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
import org.eclipse.ui.internal.editors.text.EditorsPlugin;
import org.eclipse.ceylon.ide.eclipse.code.browser.BrowserInformationControl;
import org.eclipse.ceylon.ide.eclipse.code.complete.EclipseCompletionProcessor;
import org.eclipse.ceylon.ide.eclipse.code.correct.CeylonCorrectionProcessor;
import org.eclipse.ceylon.ide.eclipse.code.hover.AnnotationHover;
import org.eclipse.ceylon.ide.eclipse.code.hover.BestMatchHover;
import org.eclipse.ceylon.ide.eclipse.code.hover.CeylonInformationControlCreator;
import org.eclipse.ceylon.ide.eclipse.code.hover.CeylonInformationProvider;
import org.eclipse.ceylon.ide.eclipse.code.hover.CeylonSourceHover;
import org.eclipse.ceylon.ide.eclipse.code.outline.HierarchyPopup;
import org.eclipse.ceylon.ide.eclipse.code.outline.OutlinePopup;
import org.eclipse.ceylon.ide.eclipse.code.parse.CeylonParseController;
import org.eclipse.ceylon.ide.eclipse.code.resolve.CeylonHyperlinkDetector;
import org.eclipse.ceylon.ide.eclipse.code.resolve.CeylonJavaBackendHyperlinkDetector;
import org.eclipse.ceylon.ide.eclipse.code.resolve.CeylonJavascriptBackendHyperlinkDetector;
import org.eclipse.ceylon.ide.eclipse.code.resolve.CeylonNativeHeaderHyperlinkDetector;
import org.eclipse.ceylon.ide.eclipse.code.resolve.JavaHyperlinkDetector;
import org.eclipse.ceylon.ide.eclipse.code.resolve.ReferencesHyperlinkDetector;
import org.eclipse.ceylon.ide.eclipse.code.search.ReferencesPopup;
import org.eclipse.ceylon.ide.eclipse.ui.CeylonPlugin;
public class CeylonSourceViewerConfiguration 
        extends TextSourceViewerConfiguration {
    
    protected final CeylonEditor editor;
    
    public CeylonSourceViewerConfiguration(CeylonEditor editor) {
        super(EditorsUI.getPreferenceStore());
        this.editor = editor;
    }
    
    public PresentationReconciler getPresentationReconciler(
            ISourceViewer sourceViewer) {
        PresentationReconciler reconciler = 
                new PresentationReconciler();
        //make sure we pass the sourceViewer we get as an argument here
        //otherwise it breaks syntax highlighting in Code popup
        PresentationDamageRepairer damageRepairer = 
                new PresentationDamageRepairer(sourceViewer, 
                        editor);
        reconciler.setRepairer(damageRepairer, 
                DEFAULT_CONTENT_TYPE);
        reconciler.setDamager(damageRepairer, 
                DEFAULT_CONTENT_TYPE);
        return reconciler;
    }
    
    private static final class CompletionListener 
            implements ICompletionListener {
        
        private CeylonEditor editor;
        private EclipseCompletionProcessor processor;
//        private CeylonCompletionProcessor processor;
        
        private CompletionListener(CeylonEditor editor,
//                CeylonCompletionProcessor processor) {
                EclipseCompletionProcessor processor) {
            this.editor = editor;
            this.processor = processor;
            
        }
        @Override
        public void selectionChanged(
                ICompletionProposal proposal,
                boolean smartToggle) {}
        
        @Override
        public void assistSessionStarted(
                ContentAssistEvent event) {
            if (editor!=null) {
                editor.pauseBackgroundParsing();
            }
            
            if (event.assistant instanceof IContentAssistantExtension2) {
                ((IContentAssistantExtension2)event.assistant).setStatusMessage(CeylonContentAssistant.secondLevelStatusMessage);
            }
            
            processor.sessionStarted(event.isAutoActivated);
            /*try {
                editor.getSite().getWorkbenchWindow().run(true, true, new Warmup());
            } 
            catch (Exception e) {}*/
        }
        
        @Override
        public void assistSessionEnded(
                ContentAssistEvent event) {
            if (editor!=null) {
                editor.unpauseBackgroundParsing();
                editor.scheduleParsing(false);
            }
        }
    }
    public ContentAssistant getContentAssistant(
            ISourceViewer sourceViewer) {
        if (editor==null) return null;
        ContentAssistant contentAssistant = 
                new CeylonContentAssistant();
        contentAssistant.setRestoreCompletionProposalSize(
                getOrCreateSection(getSettings(),
                "completion_proposal_popup"));
        EclipseCompletionProcessor completionProcessor = 
                completionJ2C().newCompletionProcessor(editor);
//        CeylonCompletionProcessor completionProcessor =
//            new CeylonCompletionProcessor(editor);
        CompletionListener listener = 
                new CompletionListener(editor, 
                        completionProcessor);
        contentAssistant.addCompletionListener(listener);
        contentAssistant.setContentAssistProcessor(
                completionProcessor, 
                DEFAULT_CONTENT_TYPE);
        configCompletionPopup(contentAssistant);
        contentAssistant.enableColoredLabels(true);
        contentAssistant.setRepeatedInvocationMode(true);
        KeyStroke key = 
                KeyStroke.getInstance(SWT.CTRL, SWT.SPACE);
        contentAssistant.setRepeatedInvocationTrigger(
                KeySequence.getInstance(key));
        CeylonContentAssistant.secondLevelStatusMessage = key.format() + 
                " to toggle second-level completions";
        contentAssistant.setStatusMessage(CeylonContentAssistant.secondLevelStatusMessage);
        CeylonContentAssistant.retrieveCompleteResultsStatusMessage = key.format() + 
                " to retrieve all results";                
        contentAssistant.setStatusLineVisible(true);
        contentAssistant.setInformationControlCreator(
                new CeylonInformationControlCreator(editor, 
                        "Tab or click for focus"));
        contentAssistant.setContextInformationPopupOrientation(
                IContentAssistant.CONTEXT_INFO_ABOVE);
        contentAssistant.setShowEmptyList(true);
        return contentAssistant;
    }
    static void configCompletionPopup(
            ContentAssistant contentAssistant) {
        IPreferenceStore preferenceStore = 
        		CeylonPlugin.getPreferences();
        if (preferenceStore!=null) {
            contentAssistant.enableAutoInsert(
                    preferenceStore.getBoolean(AUTO_INSERT));
            contentAssistant.enableAutoActivation(
                    preferenceStore.getBoolean(AUTO_ACTIVATION));
            contentAssistant.setAutoActivationDelay(
                    preferenceStore.getInt(AUTO_ACTIVATION_DELAY));
            contentAssistant.enablePrefixCompletion(
                    preferenceStore.getBoolean(AUTO_INSERT_PREFIX));
        }
    }
    
    @Override
    public IQuickAssistAssistant getQuickAssistAssistant(
            ISourceViewer sourceViewer) {
        if (editor==null) return null;
        CeylonCorrectionProcessor quickAssist = 
                new CeylonCorrectionProcessor(editor);
        quickAssist.setRestoreCompletionProposalSize(
                getOrCreateSection(getSettings(), 
                "quickassist_proposal_popup"));
        quickAssist.enableColoredLabels(true);
        return quickAssist;
    }
    public AnnotationHover getAnnotationHover(
            ISourceViewer sourceViewer) {
        return new AnnotationHover(editor, true);
    }
    public AnnotationHover getOverviewRulerAnnotationHover(
            ISourceViewer sourceViewer) {
        return new AnnotationHover(editor, true);
    }
    public IAutoEditStrategy[] getAutoEditStrategies(
            ISourceViewer sourceViewer, String contentType) {
        return new IAutoEditStrategy[] { 
                new CeylonAutoEditStrategy() };
    }
        
    public ITextDoubleClickStrategy getDoubleClickStrategy(
            ISourceViewer sourceViewer, String contentType) {
        return new DoubleClickStrategy(); 
    }
    public IHyperlinkDetector[] getHyperlinkDetectors(
            ISourceViewer sourceViewer) {
        CeylonParseController controller = 
                getParseController();
        if (controller==null) {


Answer:             return new IHyperlinkDetector[0];