/*
 * 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.animator;

import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME_PREFIX;
import static com.android.ide.eclipse.adt.AdtConstants.ANDROID_PKG;

import com.android.annotations.VisibleForTesting;
import com.android.ide.common.api.IAttributeInfo.Format;
import com.android.ide.common.resources.ResourceItem;
import com.android.ide.common.resources.ResourceRepository;
import com.android.ide.eclipse.adt.internal.editors.AndroidContentAssist;
import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
import com.android.ide.eclipse.adt.internal.editors.descriptors.SeparatorAttributeDescriptor;
import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
import com.android.resources.ResourceFolderType;
import com.android.resources.ResourceType;
import com.android.util.Pair;

import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.w3c.dom.Node;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Content Assist Processor for /res/drawable XML files
 */
@VisibleForTesting
public final class AnimationContentAssist extends AndroidContentAssist {
    private static final String OBJECT_ANIMATOR = "objectAnimator"; //$NON-NLS-1$
    private static final String PROPERTY_NAME = "propertyName";  //$NON-NLS-1$
    private static final String INTERPOLATOR_PROPERTY_NAME = "interpolator"; //$NON-NLS-1$
    private static final String INTERPOLATOR_NAME_SUFFIX = "_interpolator"; //$NON-NLS-1$

    public AnimationContentAssist() {
        super(AndroidTargetData.DESCRIPTOR_ANIMATOR);
    }

    @Override
    protected int getRootDescriptorId() {
        String folderName = mEditor.getInputFile().getParent().getName();
        ResourceFolderType folderType = ResourceFolderType.getFolderType(folderName);
        if (folderType == ResourceFolderType.ANIM) {
            return AndroidTargetData.DESCRIPTOR_ANIM;
        } else {
            return AndroidTargetData.DESCRIPTOR_ANIMATOR;
        }
    }

    @Override
    protected void computeAttributeValues(List<ICompletionProposal> proposals, int offset,
            String parentTagName, String attributeName, Node node, String wordPrefix,
            boolean skipEndTag, int replaceLength) {

        // Add value completion for the interpolator and propertyName attributes

        if (attributeName.endsWith(INTERPOLATOR_PROPERTY_NAME)) {
            if (!wordPrefix.startsWith("@android:anim/")) { //$NON-NLS-1$
                // List all framework interpolators with full path first
                AndroidTargetData data = mEditor.getTargetData();
                ResourceRepository repository = data.getFrameworkResources();
                List<String> interpolators = new ArrayList<String>();
                String base = '@' + ANDROID_PKG + ':' + ResourceType.ANIM.getName() + '/';
                for (ResourceItem item : repository.getResourceItemsOfType(ResourceType.ANIM)) {
                    String name = item.getName();
                    if (name.endsWith(INTERPOLATOR_NAME_SUFFIX)) {
                        interpolators.add(base + item.getName());
                    }
                }
                addMatchingProposals(proposals, interpolators.toArray(), offset, node, wordPrefix,
                        (char) 0 /* needTag */, true /* isAttribute */, false /* isNew */,
                        skipEndTag /* skipEndTag */, replaceLength);
            }


            super.computeAttributeValues(proposals, offset, parentTagName, attributeName, node,
                    wordPrefix, skipEndTag, replaceLength);
        } else if (parentTagName.equals(OBJECT_ANIMATOR)
                && attributeName.endsWith(PROPERTY_NAME)) {

            // Special case: the user is code completing inside
            //    <objectAnimator propertyName="^">
            // In this case, offer ALL attribute names that make sense for animation
            // (e.g. all numeric ones)

            String attributePrefix = wordPrefix;
            if (startsWith(attributePrefix, ANDROID_NS_NAME_PREFIX)) {
                attributePrefix = attributePrefix.substring(ANDROID_NS_NAME_PREFIX.length());
            }

            AndroidTargetData data = mEditor.getTargetData();
            if (data != null) {
                IDescriptorProvider descriptorProvider =
                    data.getDescriptorProvider(AndroidTargetData.DESCRIPTOR_LAYOUT);
                if (descriptorProvider != null) {
                    ElementDescriptor[] rootElementDescriptors =
                        descriptorProvider.getRootElementDescriptors();
                    Map<String, AttributeDescriptor> matches =
                        new HashMap<String, AttributeDescriptor>(180);
                    for (ElementDescriptor elementDesc : rootElementDescriptors) {
                        for (AttributeDescriptor desc : elementDesc.getAttributes()) {
                            if (desc instanceof SeparatorAttributeDescriptor) {
                                continue;
                            }
                            String name = desc.getXmlLocalName();
                            if (startsWith(name, attributePrefix)) {
                                for (Format f : desc.getAttributeInfo().getFormats()) {
                                    if (f == Format.INTEGER || f == Format.FLOAT) {
                                        // TODO: Filter out some common properties
                                        // that the user probably isn't trying to
                                        // animate:
                                        // num*, min*, max*, *Index, *Threshold,
                                        // *Duration, *Id, *Limit

                                        matches.put(name, desc);
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    List<AttributeDescriptor> sorted =
                        new ArrayList<AttributeDescriptor>(matches.size());
                    sorted.addAll(matches.values());
                    Collections.sort(sorted);
                    // Extract just the name+description pairs, since we don't want to
                    // use the full attribute descriptor (which forces the namespace
                    // prefix to be included)
                    List<Pair<String, String>> pairs =
                        new ArrayList<Pair<String, String>>(sorted.size());
                    for (AttributeDescriptor d : sorted) {
                        pairs.add(Pair.of(d.getXmlLocalName(), d.getAttributeInfo().getJavaDoc()));
                    }

                    addMatchingProposals(proposals, pairs.toArray(), offset, node, wordPrefix,
                            (char) 0 /* needTag */, true /* isAttribute */, false /* isNew */,
                            skipEndTag /* skipEndTag */, replaceLength);
                    return;
                }
            }
        } else {
            super.computeAttributeValues(proposals, offset, parentTagName, attributeName, node,
                    wordPrefix, skipEndTag, replaceLength);
        }
    }
}
