/*
 * Copyright (C) 2011 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;

import com.android.ide.common.resources.platform.DeclareStyleableInfo;
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.ElementDescriptor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor;
import com.android.sdklib.SdkConstants;

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

/**
 * Descriptors for /res/animator XML files.
 */
public class AnimatorDescriptors implements IDescriptorProvider {
    /** The root element descriptor */
    private ElementDescriptor mDescriptor;
    /** The root element descriptors */
    private ElementDescriptor[] mRootDescriptors;
    private Map<String, ElementDescriptor> nameToDescriptor;

    /** @return the root descriptor. */
    public ElementDescriptor getDescriptor() {
        if (mDescriptor == null) {
            mDescriptor = new ElementDescriptor("", getRootElementDescriptors()); //$NON-NLS-1$
        }

        return mDescriptor;
    }

    public ElementDescriptor[] getRootElementDescriptors() {
        return mRootDescriptors;
    }

    public ElementDescriptor getElementDescriptor(String mRootTag) {
        if (nameToDescriptor == null) {
            nameToDescriptor = new HashMap<String, ElementDescriptor>();
            for (ElementDescriptor descriptor : getRootElementDescriptors()) {
                nameToDescriptor.put(descriptor.getXmlName(), descriptor);
            }
        }

        ElementDescriptor descriptor = nameToDescriptor.get(mRootTag);
        if (descriptor == null) {
            descriptor = getDescriptor();
        }
        return descriptor;
    }

    public synchronized void updateDescriptors(Map<String, DeclareStyleableInfo> styleMap) {
        if (styleMap == null) {
            return;
        }

        XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor(ANDROID_NS_NAME,
                SdkConstants.NS_RESOURCES);

        List<ElementDescriptor> descriptors = new ArrayList<ElementDescriptor>();

        String sdkUrl =
            "http://developer.android.com/guide/topics/graphics/animation.html"; //$NON-NLS-1$

        ElementDescriptor set = addElement(descriptors, styleMap,
                "set", "Animator Set", "AnimatorSet", null, //$NON-NLS-1$ //$NON-NLS-3$
                null /* tooltip */, sdkUrl,
                xmlns, null, true /*mandatory*/);

        ElementDescriptor objectAnimator = addElement(descriptors, styleMap,
                "objectAnimator", "Object Animator", //$NON-NLS-1$
                "PropertyAnimator", "Animator", //$NON-NLS-1$ //$NON-NLS-2$
                null /* tooltip */, sdkUrl,
                xmlns, null, true /*mandatory*/);

        ElementDescriptor animator = addElement(descriptors, styleMap,
                "animator", "Animator", "Animator", null, //$NON-NLS-1$ //$NON-NLS-3$
                null /* tooltip */, sdkUrl,
                xmlns, null, true /*mandatory*/);

        mRootDescriptors = descriptors.toArray(new ElementDescriptor[descriptors.size()]);

        // Allow arbitrary nesting: the children of all of these element can include
        // any of the others
        if (objectAnimator != null) {
            objectAnimator.setChildren(mRootDescriptors);
        }
        if (animator != null) {
            animator.setChildren(mRootDescriptors);
        }
        if (set != null) {
            set.setChildren(mRootDescriptors);
        }
    }

    /**
     * Looks up the given style, and if found creates a new {@link ElementDescriptor}
     * corresponding to the style. It can optionally take an extra style to merge in
     * additional attributes from, and an extra attribute to add in as well. The new
     * element, if it exists, can also be optionally added into a list.
     *
     * @param descriptors an optional list to add the element into, or null
     * @param styleMap The map style => attributes from the attrs.xml file
     * @param xmlName the XML tag name to use for the element
     * @param uiName the UI name to display the element as
     * @param styleName the name of the style which must exist for this style
     * @param extraStyle an optional extra style to merge in attributes from, or null
     * @param tooltip the tooltip or documentation for this element, or null
     * @param sdkUrl an optional SDK url to display for the element, or null
     * @param extraAttribute an extra attribute to add to the attributes list, or null
     * @param childrenElements an array of children allowed by this element, or null
     * @param mandatory if true, this element is mandatory
     * @return a newly created element, or null if the style does not exist
     */
    public static ElementDescriptor addElement(
            List<ElementDescriptor> descriptors,
            Map<String, DeclareStyleableInfo> styleMap,
            String xmlName, String uiName, String styleName, String extraStyle,
            String tooltip, String sdkUrl,
            AttributeDescriptor extraAttribute,
            ElementDescriptor[] childrenElements,
            boolean mandatory) {
        DeclareStyleableInfo style = styleMap.get(styleName);
        if (style == null) {
            return null;
        }
        ElementDescriptor element = new ElementDescriptor(xmlName, uiName, tooltip, sdkUrl,
                null, childrenElements, mandatory);

        ArrayList<AttributeDescriptor> descs = new ArrayList<AttributeDescriptor>();

        DescriptorsUtils.appendAttributes(descs,
                null,   // elementName
                SdkConstants.NS_RESOURCES,
                style.getAttributes(),
                null,   // requiredAttributes
                null);  // overrides
        element.setTooltip(style.getJavaDoc());

        if (extraStyle != null) {
            style = styleMap.get(extraStyle);
            if (style != null) {
                DescriptorsUtils.appendAttributes(descs,
                        null,   // elementName
                        SdkConstants.NS_RESOURCES,
                        style.getAttributes(),
                        null,   // requiredAttributes
                        null);  // overrides
            }
        }

        if (extraAttribute != null) {
            descs.add(extraAttribute);
        }

        element.setAttributes(descs.toArray(new AttributeDescriptor[descs.size()]));
        if (descriptors != null) {
            descriptors.add(element);
        }

        return element;
    }
}
