// copyright=> http://www.jxml.com/mdsax/License.txt

package com.jxml.quick.util.qjml2java;

import java.io.PrintWriter;
import java.util.ArrayList;

import com.jxml.quick.model.qjml.*;


/**
 * This class represents a list of children. The children can be other lists,
 * or Child objects. The child objects are links to element or attribute
 * definitions.
 *
 * If all the children have a common class or parent class,
 * it is a "typed list".
 */
public class ElList {
    public String fieldName;
    public String targetClass;
    public boolean property;
    public ArrayList children = new ArrayList(); // of (Child or ElList)
    public boolean typedList; // true if it's a list of a single element
                              // or if there is a common parent class
    public String childTargetClass; // targetClass of the child when typedList=true
    public boolean newClass;
    public boolean hasAClass;
    public String childName;
    public boolean optional;
    boolean inited = false;
    
    public ElList() {
    }
    
    public void init() {
        if (inited)
            return;
        inited = true;
        for (int i=0; i<children.size(); i++)
            if (children.get(i) instanceof Child)
                ((Child)children.get(i)).init();
            else
                ((ElList)children.get(i)).init();
        
        if (targetClass == null && fieldName != null) {
            // look for a common class in the children
            for (int i=0; i<children.size(); i++) {
                Object child = children.get(i);
                if (i == 0) {
                    if (child instanceof Child)
                        targetClass = ((Child)child).eldef.targetClass;
                    else
                        targetClass = ((ElList)child).targetClass;
                } else {
                    String ctarget;
                    if (child instanceof Child)
                        ctarget = ((Child)child).eldef.targetClass;
                    else
                        ctarget = ((ElList)child).targetClass;
                    if (ctarget == null || !ctarget.equals(targetClass)) {
                        targetClass = null;
                        break;
                    }
                }
            }
            
            if (targetClass == null)
                // look for a common parent element in the children
                for (int i=0; i<children.size(); i++) {
                    Object child = children.get(i);
                    if (i == 0) {
                        if (child instanceof Child) {
                            Element parent = ((Child)child).eldef.parentElement;
                            if (parent == null)
                                break;
                            else
                                targetClass = parent.targetClass;
                        } else
                            targetClass = ((ElList)child).targetClass;
                    } else {
                        String ctarget;
                        if (child instanceof Child) {
                            Element parent = ((Child)child).eldef.parentElement;
                            if (parent == null)
                                ctarget = null;
                            else
                                ctarget = parent.targetClass;
                        } else
                            ctarget = ((ElList)child).targetClass;
                        if (ctarget == null || !ctarget.equals(targetClass)) {
                            targetClass = null;
                            break;
                        }
                    }
                }
            
            // look for a common interface in the children
            
            if (targetClass == null)
                // give up !
                targetClass = "java.lang.Object";
        }
        if (typedList && (childName == null || childTargetClass == null)) {
            Child child = (Child)children.get(0);
            if (childName == null)
                childName = child.fieldName;
            if (childTargetClass == null)
                childTargetClass = child.eldef.targetClass;
        }
        if ("java.util.ArrayList".equals(targetClass))
            newClass = false;
        else {
            newClass = true;
            for (int i=0; i<children.size(); i++) {
                Object child = children.get(i);
                if (child instanceof Child) {
                    if (!((Child)child).eldef.newClass)
                        newClass = false;
                } else if (!((ElList)child).newClass)
                    newClass = false;
            }
        }
        hasAClass = !Element.isJavaType(targetClass);
    }
    
    /* add all the element children in a list */
    public void getAllClasses(ArrayList allElements, ArrayList discarded) {
        for (int i=0; i<children.size(); i++) {
            Object child = children.get(i);
            if (child instanceof Child)
                ((Child)child).eldef.getAllClasses(allElements, discarded);
            else
                ((ElList)child).getAllClasses(allElements, discarded);
        }
    }
    
    public void getChildInfo(ArrayList elChildren) {
        for (int i=0; i<children.size(); i++) {
            Object child = children.get(i);
            if (child instanceof Child) {
                elChildren.add(((Child)child).eldef);
            } else
                ((ElList)child).getChildInfo(elChildren);
        }
    
    }
    
    public void getXChildInfo(ArrayList xchildren) {
        for (int i=0; i<children.size(); i++) {
            Object child = children.get(i);
            if (child instanceof Child) {
                xchildren.addAll(((Child)child).eldef.subXChildren());
            } else
                ((ElList)child).getXChildInfo(xchildren);
        }
    
    }
    
    public void makeFields(ArrayList fields, boolean attributes) {
        if (fieldName != null) {
            boolean childNewClass = false;
            String comment = null;
            if (typedList) {
                childNewClass = children.get(0) instanceof Child &&
                    ((Child)children.get(0)).eldef.newClass;
                comment = "list of " + Element.getClassName(childTargetClass);
            }
            ArrayList elChildren = new ArrayList();
            getChildInfo(elChildren);
            ArrayList xchildren = new ArrayList();
            getXChildInfo(xchildren);
            
            // check if field already exists (this is the case if QMProperty
            // or QMField was used in QJML)
            ClassField cf = null;
            for (int i=0; i<fields.size(); i++)
                if (((ClassField)fields.get(i)).name.equals(fieldName)) {
                    cf = (ClassField)fields.get(i);
                    break;
                }
            if (cf != null) {
                if (cf.classpath == null)
                    cf.classpath = targetClass;
                if (property != cf.property)
                    System.err.println("Warning: is " + fieldName +
                        " a property or not ?");
                cf.newClass = newClass;
                cf.hasAClass = hasAClass;
                cf.comment = comment;
                cf.attribute = attributes;
                cf.optional = optional;
                cf.typedList = typedList;
                cf.childClass = childTargetClass;
                cf.childNewClass = childNewClass;
                cf.childName = childName;
                cf.children = elChildren;
                cf.xchildren = xchildren;
            } else
                ClassField.addNewField(fields, new ClassField(fieldName,
                    targetClass, property, newClass, hasAClass, comment, null,
                    attributes, optional, null, typedList, childTargetClass,
                    childNewClass, childName, elChildren, xchildren));
        } else
            for (int i=0; i<children.size(); i++) {
                Object child = children.get(i);
                if (child instanceof Child)
                    ((Child)child).makeFields(fields, attributes);
                else
                    ((ElList)child).makeFields(fields, attributes);
            }
    }
    
}
