/**
 * EasyBeans
 * Copyright (C) 2006 Bull S.A.S.
 * Contact: easybeans@objectweb.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id: ClassMetadata.java 4822 2009-03-18 09:43:15Z benoitf $
 * --------------------------------------------------------------------------
 */

package org.ow2.spec.testengine.metadata;

import java.util.ArrayList;
import java.util.List;

import org.ow2.spec.testengine.SignatureResultSet;

/**
 * Represents the metadata for a given class.
 * @author Florent Benoit
 */
public class ClassMetadata extends AbsMetadata {

    /**
     * UID for Serialization.
     */
    private long uid = 0;

    /**
     * Access mode.
     */
    private int access;

    /**
     * Name of the class.
     */
    private String name;

    /**
     * Signature of this class.
     */
    private String signature;

    /**
     * Name of the super class.
     */
    private String superName;

    /**
     * Array of interfaces for this class.
     */
    private String[] interfaces;

    /**
     * List of methods for this class.
     */
    private List<MethodMetadata> methodMetadataList = null;

    /**
     * List of fields for this class.
     */
    private List<FieldMetadata> fieldMetadataList = null;

    /**
     * List of annotations for this class.
     */
    private List<AnnotationMetadata> annotationMetadataList = null;

    /**
     * List of inner classes for this class.
     */
    private List<InnerClassMetadata> innerClassMetadataList = null;

    /**
     * Build a new Class metadata object.
     * @param access the class's access flags. This parameter also indicates if
     *        the class is deprecated.
     * @param name the internal name of the class.
     * @param signature the signature of this class. May be <tt>null</tt> if
     *        the class is not a generic one, and does not extend or implement
     *        generic classes or interfaces.
     * @param superName the internal of name of the super class (see . For
     *        interfaces, the super class is {@link Object}. May be
     *        <tt>null</tt>, but only for the {@link Object} class.
     * @param interfaces the internal names of the class's interfaces. May be
     *        <tt>null</tt>.
     */
    public ClassMetadata(int access, String name, String signature, String superName, String[] interfaces) {
        this.access = access;
        this.name = name;
        this.signature = signature;
        this.superName = superName;
        this.interfaces = interfaces;
        if (interfaces != null && interfaces.length == 0) {
            this.interfaces = null;
        }

        methodMetadataList = new ArrayList<MethodMetadata>();
        fieldMetadataList = new ArrayList<FieldMetadata>();
        annotationMetadataList = new ArrayList<AnnotationMetadata>();
        innerClassMetadataList = new ArrayList<InnerClassMetadata>();
    }

    /**
     * Add the given method metadata to the list
     * @param methodMetadata the given metadata
     */
    public void addMethodMetadata(MethodMetadata methodMetadata) {
        methodMetadataList.add(methodMetadata);
    }

    /**
     * Add the given field metadata to the list
     * @param fieldMetadata the given metadata
     */
    public void addFieldMetadata(FieldMetadata fieldMetadata) {
        fieldMetadataList.add(fieldMetadata);
    }

    /**
     * Add the given annotation metadata to the list
     * @param annotationMetadata the given metadata
     */
    public void addAnnotationMetadata(AnnotationMetadata annotationMetadata) {
        annotationMetadataList.add(annotationMetadata);
    }

    /**
     * Add the given inner class metadata to the list
     * @param annotationMetadata the given metadata
     */
    public void addInnerClassMetadata(InnerClassMetadata innerClassMetadata) {
        innerClassMetadataList.add(innerClassMetadata);
    }

    /**
     * Sets the uid of this class
     * @param uid
     */
    public void setUID(long uid) {
        this.uid = uid;
    }


    public String toXML(String indent) {
        StringBuilder sb = new StringBuilder();

        String newIndent = indent + "  ";

        // start element
        sb.append(indent);
        sb.append("<class");

        // Name Attribute
        addObjectToSB("name", name, sb);

        // SuperName Attribute
        addObjectToSB("super-name", superName, sb);

        // Access Attribute
        addObjectToSB("access", access, sb);

        // signature Attribute
        addObjectToSB("signature", signature, sb);

        // UID Attribute
        if (uid != 0) {
            addObjectToSB("uid", uid, sb);
        }

        // end attribute
        sb.append(" >");

        // Interfaces
        addArrayObjectToSB("interface", interfaces, sb, newIndent);

        // Inner class
        addListToSB(innerClassMetadataList, sb, newIndent);

        // annotations
        addListToSB(annotationMetadataList, sb, newIndent);

        // methods
        addListToSB(methodMetadataList, sb, newIndent);

        // fields
        addListToSB(fieldMetadataList, sb, newIndent);

        // end element
        sb.append("\n");
        sb.append(indent);
        sb.append("</class>\n");
        return sb.toString();
    }

    public String getName() {
        return name;
    }



    public void compare(ClassMetadata other, SignatureResultSet rs) {
        // compare access
        compare(getName() + " access", access, other.access, rs);

        // compare name
        compare(getName() + " name", name, other.name, rs);

        // super name
        compare(getName() + " super class name", superName, other.superName, rs);

        // signature name
        compare(getName() + " signature", signature, other.signature, rs);

        // interfaces
        compare(getName() + " interfaces", interfaces, other.interfaces, rs);

        // uid if not an enum
        if (!"java/lang/Enum".equals(getSuperName())) {
            compare(getName() + " uid", uid, other.uid, rs);
        }

        // Inner class
        compareList(getName() + " inner class", innerClassMetadataList, other.innerClassMetadataList, rs);

        // methods
        compareList(getName() + " methods", methodMetadataList, other.methodMetadataList, rs);

        // fields
        compareList(getName() + " methods", fieldMetadataList, other.fieldMetadataList, rs);

        // annotations
        compareList(getName() + " annotations", annotationMetadataList, other.annotationMetadataList, rs);

    }

    /**
     * @return super name
     */
    public String getSuperName() {
        return superName;
    }



    public int hashCode() {
        return name.hashCode();
    }

    public boolean equals(Object o) {
        if (!(o instanceof ClassMetadata)) {
            return false;
        }

        SignatureResultSet rs = new SignatureResultSet();
        try {
            compare((ClassMetadata) o, rs);
        } catch (Exception e) {
            return false;
        }
        return !rs.hasErrors();
    }

}
