/*******************************************************************************
 * Copyright (c) 2006 Spirit Link GmbH
 * All rights reserved.
 * 
 * Contributors:
 *     Tom Seidel - initial API and implementation
 *******************************************************************************/

package de.spiritlink.fieldassist;

import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.ParseException;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.DecoratedField;
import org.eclipse.jface.fieldassist.FieldAssistColors;
import org.eclipse.jface.fieldassist.FieldDecoration;
import org.eclipse.jface.fieldassist.IControlContentAdapter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Text;

/**
 * @since 3.2
 *
 */
public class ContentAssistField {

    private final DecoratedField field;
    private final Color defaultTextColor;
    private final ContentAssistFieldConfiguration configuration;
    private Color errorColor;
    private boolean valid = true;

    public ContentAssistField(
            DecoratedField field,
            ContentAssistFieldConfiguration configuration) {
        this.field = field;
        this.configuration = configuration;
        final Text text = (Text) field.getControl();
        this.defaultTextColor = text.getBackground();
        text.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent event) {
                handleModify();
            }
        });
        text.addFocusListener(new FocusListener() {
            public void focusGained(FocusEvent event) {
                handleFocusGained();
            }

            public void focusLost(FocusEvent event) {
                handleFocusLost();
            }

        });
        this.field.addFieldDecoration(
                this.configuration.getFieldDecoration(),
                this.configuration.getDecorationPosition(), true);
        installContentProposalAdapter(this.configuration.getContentAdapter());
    }

    private void showErrorDecoration(boolean show) {
        final FieldDecoration dec = this.configuration.getErrorDecoration(this);
        if (show) {
            this.field.addFieldDecoration(dec, this.configuration.getDecorationPosition(), false);
            this.field.showDecoration(dec);
        } else {
            this.field.hideDecoration(dec);
        }
        this.valid = !show;
    }

    private void showWarningDecoration(boolean show) {
        final FieldDecoration dec = this.configuration.getWarningDecoration(this);
        if (show) {
            this.field.addFieldDecoration(dec, this.configuration.getDecorationPosition(), false);
            this.field.showDecoration(dec);
        } else {
            this.field.hideDecoration(dec);
        }
    }

    private void showContentAssistDecoration(boolean show) {
        final FieldDecoration dec = this.configuration.getFieldDecoration();
        if (show) {
            this.field.addFieldDecoration(dec, this.configuration.getDecorationPosition(), true);
            this.field.showDecoration(dec);
        } else {
            this.field.hideDecoration(dec);
        }
    }

    private void showRequiredFieldDecoration(boolean show) {
        final FieldDecoration dec = this.configuration.getRequiredFieldDecoration();
        if (show) {
            this.field.addFieldDecoration(dec, this.configuration.getDecorationPosition(), false);
            this.field.showDecoration(dec);
        } else {
            this.field.hideDecoration(dec);
        }
    }
    
    

    void handleModify() {
        // Error indicator supercedes all others
        if (this.configuration.isError(this)) {
            showError();
        } else {
            hideError();
            if (this.configuration.isWarning(this)) {
                showWarning();
            } else {
                hideWarning();
                if (this.configuration.hasContentAssist()) {
                    showContentAssistDecoration(true);
                } else {
                    showContentAssistDecoration(false);
                    showRequiredFieldDecoration(this.configuration.isShowRequiredFieldDecoration());
                }
            }
        }
    }
    private void hideError() {
        if (this.configuration.isShowErrorDecoration()) {
            showErrorDecoration(false);
        }
        if (this.configuration.isShowErrorColor()) {
            this.field.getControl().setBackground(this.defaultTextColor);
        }
    }

   

    private void showError() {
        //final FieldDecoration dec = this.configuration.getErrorDecoration(this);
        
        if (this.configuration.isShowErrorDecoration()) {
            showErrorDecoration(true);
        }
        if (this.configuration.isShowErrorColor()) {
            this.field.getControl().setBackground(getErrorColor());
        }
    }
    
    private void showWarning() {
        if (this.configuration.isShowWarningDecoration()) {
            showWarningDecoration(true);
        }
    }

    private void hideWarning() {
        if (this.configuration.isShowWarningDecoration()) {
            showWarningDecoration(false);
        }
    }
    
    private Color getErrorColor() {
        if (this.errorColor == null) {
            final RGB rgb = FieldAssistColors.computeErrorFieldBackgroundRGB(this.field.getControl());
            this.errorColor = new Color(this.field.getControl().getDisplay(), rgb);
        }
        return this.errorColor;
    }
    
    void handleFocusGained() {
        // only set color if error color not already showing
        if (this.configuration.isShowErrorColor() && this.configuration.isError(this))
            return;
        if (this.configuration.isShowRequiredColor() && this.configuration.isRequired(this)) {
            this.field.getControl().setBackground(this.defaultTextColor);
        }
    }

    void handleFocusLost() {
        // only set color if error color not showing
        if (this.configuration.isShowErrorColor() && this.configuration.isError(this))
            return;
        if (this.configuration.isShowRequiredColor() && this.configuration.isRequired(this)
                && this.configuration.getContentAdapter().getControlContents(this.field.getControl()).length() == 0) {
            this.field.getControl().setBackground(FieldAssistColors
                    .getRequiredFieldBackgroundColor(this.field.getControl()));
        }
    }
    
    void installContentProposalAdapter(IControlContentAdapter contentAdapter) {
        KeyStroke keyStroke = null;
        if (this.configuration.getTriggerKey() != null) {
            try {
                keyStroke = KeyStroke.getInstance(this.configuration.getTriggerKey());
            } catch (final ParseException e) {
                keyStroke = KeyStroke.getInstance(SWT.F10);
            }
        } 
        

        final ContentProposalAdapter adapter = new ContentProposalAdapter(this.field.getControl(),
                contentAdapter, this.configuration.getContentProposalProvider(), keyStroke,
                new char[] {});
        
        adapter.setAutoActivationDelay(this.configuration.getDelay());
        adapter.setPropagateKeys(this.configuration.isPropagate());
        adapter.setFilterStyle(this.configuration.getContentAssistFilterStyle());
        adapter.setProposalAcceptanceStyle(this.configuration.getContentProposalAcceptance());
        adapter.setLabelProvider(this.configuration.getLableProvider());
    }
    
    public Text getControl() {
        return (Text) this.field.getControl();
    }

    /**
     * @return the valid
     */
    public boolean isValid() {
        return this.valid;
    }





}

