package net.sf.jasperreports.engine.util;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import net.sf.jasperreports.crosstabs.JRCellContents;
import net.sf.jasperreports.crosstabs.JRCrosstab;
import net.sf.jasperreports.crosstabs.JRCrosstabCell;
import net.sf.jasperreports.crosstabs.JRCrosstabColumnGroup;
import net.sf.jasperreports.crosstabs.JRCrosstabRowGroup;
import net.sf.jasperreports.crosstabs.design.JRDesignCrosstab;
import net.sf.jasperreports.engine.JRBand;
import net.sf.jasperreports.engine.JRChild;
import net.sf.jasperreports.engine.JRElementGroup;
import net.sf.jasperreports.engine.JRFrame;
import net.sf.jasperreports.engine.JRGroup;
import net.sf.jasperreports.engine.JRReport;
import net.sf.jasperreports.engine.JRVisitor;

public class JRElementsVisitor extends JRDelegationVisitor {
  public static void visitReport(JRReport report, JRVisitor visitor) {
    JRElementsVisitor reportVisitor = new JRElementsVisitor(visitor);
    reportVisitor.visitReport(report);
  }
  
  public JRElementsVisitor(JRVisitor visitor) {
    super(visitor);
  }
  
  public void visitReport(JRReport report) {
    visitBand(report.getBackground());
    visitBand(report.getTitle());
    visitBand(report.getPageHeader());
    visitBand(report.getColumnHeader());
    visitBand(report.getDetail());
    visitBand(report.getColumnFooter());
    visitBand(report.getPageFooter());
    visitBand(report.getLastPageFooter());
    visitBand(report.getSummary());
    visitBand(report.getNoData());
    JRGroup[] groups = report.getGroups();
    if (groups != null)
      for (int i = 0; i < groups.length; i++) {
        JRGroup group = groups[i];
        visitBand(group.getGroupHeader());
        visitBand(group.getGroupFooter());
      }  
  }
  
  protected void visitBand(JRBand band) {
    if (band != null)
      band.visit(this); 
  }
  
  protected void visitElements(List elements) {
    if (elements != null)
      for (Iterator it = elements.iterator(); it.hasNext(); ) {
        JRChild child = it.next();
        child.visit(this);
      }  
  }
  
  public void visitElementGroup(JRElementGroup elementGroup) {
    super.visitElementGroup(elementGroup);
    visitElements(elementGroup.getChildren());
  }
  
  public void visitFrame(JRFrame frame) {
    super.visitFrame(frame);
    visitElements(frame.getChildren());
  }
  
  public void visitCrosstab(JRCrosstab crosstab) {
    super.visitCrosstab(crosstab);
    visitCrosstabCell(crosstab.getWhenNoDataCell());
    visitCrosstabCell(crosstab.getHeaderCell());
    JRCrosstabRowGroup[] rowGroups = crosstab.getRowGroups();
    for (int i = 0; i < rowGroups.length; i++) {
      JRCrosstabRowGroup rowGroup = rowGroups[i];
      visitCrosstabCell(rowGroup.getHeader());
      visitCrosstabCell(rowGroup.getTotalHeader());
    } 
    JRCrosstabColumnGroup[] columnGroups = crosstab.getColumnGroups();
    for (int j = 0; j < columnGroups.length; j++) {
      JRCrosstabColumnGroup columnGroup = columnGroups[j];
      visitCrosstabCell(columnGroup.getHeader());
      visitCrosstabCell(columnGroup.getTotalHeader());
    } 
    if (crosstab instanceof JRDesignCrosstab) {
      List cells = ((JRDesignCrosstab)crosstab).getCellsList();
      for (Iterator it = cells.iterator(); it.hasNext(); ) {
        JRCrosstabCell cell = it.next();
        visitCrosstabCell(cell.getContents());
      } 
    } else {
      JRCrosstabCell[][] cells = crosstab.getCells();
      if (cells != null) {
        Set cellContents = new HashSet();
        for (int k = 0; k < cells.length; k++) {
          for (int m = 0; m < (cells[k]).length; m++) {
            JRCrosstabCell cell = cells[k][m];
            if (cell != null && cell.getContents() != null && cellContents.add(cell.getContents()))
              visitCrosstabCell(cell.getContents()); 
          } 
        } 
      } 
    } 
  }
  
  protected void visitCrosstabCell(JRCellContents cell) {
    if (cell != null)
      visitElements(cell.getChildren()); 
  }
}
