/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Eclipse Public License, Version 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.eclipse.org/org/documents/epl-v10.php
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.ide.eclipse.adt.internal.editors.uimodel;

import com.android.ide.eclipse.adt.internal.editors.AndroidEditor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor;
import com.android.ide.eclipse.adt.internal.editors.ui.SectionHelper;

import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.widgets.TableWrapData;

/**
 * Represents an XML attribute in that can be modified using a simple text field
 * in the XML editor's user interface.
 * <p/>
 * The XML attribute has no default value. When unset, the text field is blank.
 * When updating the XML, if the field is empty, the attribute will be removed
 * from the XML element.  
 * <p/>
 * See {@link UiAttributeNode} for more information.
 */
public class UiTextAttributeNode extends UiAbstractTextAttributeNode {

    /** Text field */
    private Text mText;
    /** The managed form, set only once createUiControl has been called. */
    private IManagedForm mManagedForm;

    public UiTextAttributeNode(AttributeDescriptor attributeDescriptor, UiElementNode uiParent) {
        super(attributeDescriptor, uiParent);
    }
    
    /* (non-java doc)
     * Creates a label widget and an associated text field.
     * <p/>
     * As most other parts of the android manifest editor, this assumes the
     * parent uses a table layout with 2 columns.
     */
    @Override
    public void createUiControl(Composite parent, IManagedForm managedForm) {
        setManagedForm(managedForm);
        TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor();
        Text text = SectionHelper.createLabelAndText(parent, managedForm.getToolkit(),
                desc.getUiName(), getCurrentValue(),
                DescriptorsUtils.formatTooltip(desc.getTooltip()));

        setTextWidget(text);
    }

    /**
     * No completion values for this UI attribute.
     * 
     * {@inheritDoc}
     */
    @Override
    public String[] getPossibleValues(String prefix) {
        return null;
    }
    
    /**
     * Sets the internal managed form.
     * This is usually set by createUiControl.
     */
    protected void setManagedForm(IManagedForm managedForm) {
         mManagedForm = managedForm;
    }
    
    /**
     * @return The managed form, set only once createUiControl has been called.
     */
    protected IManagedForm getManagedForm() {
        return mManagedForm;
    }
    
    /* (non-java doc)
     * Returns if the attribute node is valid, and its UI has been created.
     */
    @Override
    public boolean isValid() {
        return mText != null;
    }

    @Override
    public String getTextWidgetValue() {
        if (mText != null) {
            return mText.getText();
        }
        
        return null;
    }

    @Override
    public void setTextWidgetValue(String value) {
        if (mText != null) {
            mText.setText(value);
        }
    }

    /**
     * Sets the Text widget object, and prepares it to handle modification and synchronization
     * with the XML node.
     * @param textWidget
     */
    protected final void setTextWidget(Text textWidget) {
        mText = textWidget;
 
        if (textWidget != null) {
            // Sets the with hint for the text field. Derived classes can always override it.
            // This helps the grid layout to resize correctly on smaller screen sizes.
            Object data = textWidget.getLayoutData();
            if (data == null) {
            } else if (data instanceof GridData) {
                ((GridData)data).widthHint = AndroidEditor.TEXT_WIDTH_HINT;
            } else if (data instanceof TableWrapData) {
                ((TableWrapData)data).maxWidth = 100;
            }
            
            mText.addModifyListener(new ModifyListener() {
                /**
                 * Sent when the text is modified, whether by the user via manual
                 * input or programmatic input via setText().
                 * <p/>
                 * Simply mark the attribute as dirty if it really changed.
                 * The container SectionPart will collect these flag and manage them.
                 */
                public void modifyText(ModifyEvent e) {
                    if (!isInInternalTextModification() &&
                            !isDirty() &&
                            mText != null &&
                            getCurrentValue() != null &&
                            !mText.getText().equals(getCurrentValue())) {
                        setDirty(true);
                    }
                }            
            });
            
            // Remove self-reference when the widget is disposed
            mText.addDisposeListener(new DisposeListener() {
                public void widgetDisposed(DisposeEvent e) {
                    mText = null;
                }
            });
        }
        
        onAddValidators(mText);
    }

    /**
     * Called after the text widget as been created.
     * <p/>
     * Derived classes typically want to:
     * <li> Create a new {@link ModifyListener} and attach it to the given {@link Text} widget.
     * <li> In the modify listener, call getManagedForm().getMessageManager().addMessage()
     *      and getManagedForm().getMessageManager().removeMessage() as necessary.
     * <li> Call removeMessage in a new text.addDisposeListener.
     * <li> Call the validator once to setup the initial messages as needed.
     * <p/>
     * The base implementation does nothing.
     * 
     * @param text The {@link Text} widget to validate.
     */
    protected void onAddValidators(Text text) {
    }

    /**
     * Returns the text widget.
     */
    protected final Text getTextWidget() {
        return mText;
    }
}
