/*
 * ColumnGroup.java
 *
 * Created on June 9, 2006, 10:19 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package usda.weru.util.table;

import java.util.ArrayList;
import java.util.Vector;
import java.util.Iterator;
import java.util.List;
import org.jdom2.Element;

/**
 * Wrapper class for a group of Columns and/or Column Groups.
 * @author Joseph Levin
 */
public class ColumnGroup implements XmlObject, ColumnGroupOrColumn, Iterable <ColumnGroupOrColumn>{
    private List<ColumnGroupOrColumn> c_children;
    List<String> boldedColumns = new ArrayList<String>();
    private Label c_label;
    private final WepsTableMeta c_meta;
    private ColumnGroup c_parent;
    private ColumnGroup c_tempParent;       //Used when there are multiple labels so child ColumnGroup or Column objects are added to the correct parent.
    /**
     * Creates a new instance of ColumnGroup
     * @param meta The WepsTableMeta to which this ColumnGroup will be associated.
     */
    public ColumnGroup(WepsTableMeta meta) {
        init();    
        c_meta = meta;
        c_label = new Label(meta);
    }
    
    private void init(){
        c_children = new Vector <ColumnGroupOrColumn> ();
    }
    
    /**
     * Return an Iterator for the List containing the ColumnGroups children.
     * @return An Iterator for the List of children.
     */
    @Override
    public Iterator<ColumnGroupOrColumn> iterator(){
        return c_children.listIterator();
    }
        
    /**
     * Add a Column or ColumnGroup to this ColumnGroup.
     * @param child The Column or ColumnGroup to be added.
     */
    public void add(ColumnGroupOrColumn child){
        c_children.add(child.setParent(this));
    }
    
    /**
     * The Label used for this ColumnGroup.
     * @return The Label for this ColumnGroup.
     */
    @Override
    public Label getLabel(){        
        if (c_label == null){
            c_label = new Label(c_meta);
        }   
        return c_label;        
    }
    
    /**
     * Set the ColumnGroup this ColumnGroup will be a part of.
     * @param parent The ColumnGroup this ColumnGroup will be a part of.
     * @return <b>this</b>
     */
    @Override
    public ColumnGroupOrColumn setParent(ColumnGroup parent){
        c_parent = parent;
        return this;
    }
    
    /**
     * Return the ColumnGroup this ColumnGroup is a part of.
     * @return The ColumnGroup containing this ColumnGroup.
     */
    @Override
    public ColumnGroup getParentGroup(){
        return c_parent;
    }
    
    /**
     * Return the row in the header containing this ColumnGroup.
     * @return The depth in the header.
     */
    @Override
    public int depthInHeader(){
        int depth = 0;
        if (getLabel() != null && getLabel().getSpanRows() > 1){
            depth = depth + getLabel().getSpanRows() - 1;
        }
        if (getParentGroup() != null){
            depth = depth + getParentGroup().depthInHeader() + 1;
        }
        return depth;
    }
    
    /**
     * Return the number of columns directly under this ColumnGroup.
     * @return The number of columns under this ColumnGroup.
     */
    @Override
    public int bottomBreadth(){
        int breadth = 0;
        for (ColumnGroupOrColumn child : c_children){
            if (child instanceof ColumnGroup){
                breadth = breadth + ((ColumnGroup) child).bottomBreadth();
            }
            else if (child instanceof Column){
                breadth++;                
            }
        }
        return breadth;
    }
    
    /**
     * Check to see if the supplied ColumnGroup or Column is the first child of this ColumnGroup.
     * @param child The ColumnGroup or Column in question.
     * @return <b>true</b> if the ColumnGroup or Column is the first child, <b>false</b> otherwise.
     */
    @Override
    public boolean isFirstChild(ColumnGroupOrColumn child){
        return c_children.indexOf(child) == 0;
    }
    
    /**
     * Load configuration settings for this ColumnGroup from a jdom Element.
     * @param node An org.jdom2.Element containing configuration information about this ColumnGroup.
     */
    @Override
    public void fromXml(Element node){
        //Load labels first because we may have to make wrapping column containers
        loadLabels(node);
        
        //Load children(label, columns or column;
        List <Element> children = node.getChildren();
        for (Element child : children){
            if (child.getName().equals(WepsTableEnum.XML_columngroup)){
                //Child ColumnGroup 
                loadColumns(child);
            }
            else if (child.getName().equals(WepsTableEnum.XML_column)){
                //Child Column
                loadColumn(child);                
            }            
        }
        
        
    }
    
    private void loadColumns(Element node){
        ColumnGroup childColumns = new ColumnGroup(c_meta);
        childColumns.fromXml(node);
        boldedColumns.addAll(childColumns.boldedColumns);
        c_tempParent.add(childColumns);
    }
    
    private void loadColumn(Element node){
        Column childColumn = new Column(c_meta);
        childColumn.fromXml(node);
        c_tempParent.add(childColumn);
        c_meta.addColumn(childColumn);
        
    }
    
    /**
     * Set the Label to be used by this ColumnGroup.
     * @param label The Label to be used by this ColumnGroup.
     */
    public void setLabel(Label label){
        c_label = label;
    }
    
    private void loadLabels(Element node){
        List <Element> labelNodes = node.getChildren(WepsTableEnum.XML_label);
        c_label = new Label(c_meta);
        
        boolean first = true;
        ColumnGroup parent = this;
        for (Element child : labelNodes){
            if (first){
                first = false;
                c_label.fromXml(child);
            }
            else{
                //We have more labels which we will create unique ColumnGroup objects for.
                ColumnGroup tempColumns = new ColumnGroup(c_meta);
                Label tempLabel = new Label(c_meta);
                tempLabel.fromXml(child);
                tempColumns.setLabel(tempLabel);
                parent.add(tempColumns);
                parent = tempColumns;
            }
        }
        List<Element> bold = node.getChildren(WepsTableEnum.XML_bolder);
        if(!bold.isEmpty())
        {
            boldedColumns.add(c_label.c_text);
        }
        c_tempParent = parent;        
    }
    
    /**
     * Return the ID of this ColumnGroup.
     * @return The ID of this ColumnGroup.
     */
    @Override
    public String toString(){
        if (getLabel() != null){
            return getLabel().getText();            
        }
        else{
            return super.toString();
        }
    }
    
    public List<String> getBoldedColumns()
    {
        return boldedColumns;
    }
}
