package org.apache.cocoon.transformation;

import java.util.Map;
import java.io.IOException;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.transformation.AbstractTransformer;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.excalibur.pool.Poolable;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

/**
 * The filter transformer can be used to let only an amount of elements through in 
 * a given block.
 *
 * Usage in sitemap
 *    &lt;map:transform type="filter"&gt;
 *     &lt;map:parameter name="element-name" value="row"/&gt;
 *     &lt;map:parameter name="count" value="5"/&gt;
 *     &lt;map:parameter name="blocknr" value="3"/&gt;
 *    &lt;/map:transform&gt;
 *
 * Only the 3th block will be shown, containing only 5 row elements.
 *
 * @author <a href="mailto:sven.beauprez@the-ecorp.com">Sven Beauprez</a>
 * @version CVS $Revision: 1.11 $ $Date: 2001/06/18 08:30:52 $ $Author: sbeaupre $
 */

public class FilterTransformer extends AbstractTransformer implements Poolable {
  private static final String ELEMENT = "element-name";
  private static final String COUNT = "count";
  private static final String BLOCKNR = "blocknr";
  private static final String BLOCK = "block";
  private static final String BLOCKID = "id";
  private static final int DEFAULT_COUNT = 10;
  private static final int DEFAULT_BLOCK = 1;

  private int counter;
  private int count;
  private int blocknr;
  private int currentBlocknr;
  private String elementName;
  private String parentName;
  boolean skip;
  boolean foundIt;

  /** BEGIN SitemapComponent methods **/
  public void setup(SourceResolver resolver, Map objectModel, String source, Parameters parameters)
  throws ProcessingException, SAXException, IOException {
    counter=0;
    currentBlocknr=0;
    skip=false;
    foundIt=false;
    parentName=null;
    elementName = parameters.getParameter(FilterTransformer.ELEMENT,null);
    String tmpCount = parameters.getParameter(FilterTransformer.COUNT,""+FilterTransformer.DEFAULT_COUNT);
    String tmpBlockNr = parameters.getParameter(FilterTransformer.BLOCKNR,""+FilterTransformer.DEFAULT_BLOCK);
    if (elementName==null || tmpCount==null)  {
      getLogger().error("FilterTransformer: both "+ FilterTransformer.ELEMENT + " and " +
                        FilterTransformer.COUNT + " parameters need to be specified");
    }else  {
      try  {
        count = Integer.parseInt(tmpCount);
        getLogger().debug("FilterTransformer: " + FilterTransformer.COUNT + "=" + count);
      }  catch (NumberFormatException e)  {
        //set default values so we can move on
        count=FilterTransformer.DEFAULT_COUNT;      
        getLogger().error("FilterTransformer: " + FilterTransformer.COUNT + 
                          " not valid, using default value of "+FilterTransformer.DEFAULT_COUNT);
      }
      try  {
        blocknr = Integer.parseInt(tmpBlockNr);
        getLogger().debug("FilterTransformer: " + FilterTransformer.BLOCKNR + "=" + blocknr);
      } catch (NumberFormatException e)  {
        //set default values so we can move on
        blocknr=FilterTransformer.DEFAULT_BLOCK;
        getLogger().error("FilterTransformer: " + FilterTransformer.BLOCKNR + 
                          " not valid, using default value of "+ FilterTransformer.DEFAULT_BLOCK);
      }
    }
  }
  /** END SitemapComponent methods **/

  /** BEGIN SAX ContentHandler handlers **/
  public void startElement(String uri, String name, String raw, Attributes attributes)
  throws SAXException {
    if (name.equalsIgnoreCase(elementName)) {
      foundIt=true;
      counter++;
      if (counter <= (count*(blocknr)) && counter > (count*(blocknr-1))) {
        skip=false;
      } else  {
        skip=true;
      }
      if (currentBlocknr != (int)Math.ceil((float)counter/count)) {
        currentBlocknr = (int)Math.ceil((float)counter/count);
        AttributesImpl attr = new AttributesImpl();
        attr.addAttribute(uri,FilterTransformer.BLOCKID,FilterTransformer.BLOCKID,"CDATA",String.valueOf(currentBlocknr));
        if (counter < count)  {
          super.contentHandler.startElement(uri,FilterTransformer.BLOCK,FilterTransformer.BLOCK,attr);
        } else  {
          super.contentHandler.endElement(uri,FilterTransformer.BLOCK,FilterTransformer.BLOCK);
          super.contentHandler.startElement(uri,FilterTransformer.BLOCK,FilterTransformer.BLOCK,attr);        }
      }
    } else if (!foundIt)  {
      parentName = name;
    }
    if (!skip)  {
      super.contentHandler.startElement(uri,name,raw,attributes);
    }
  }

  public void endElement(String uri,String name,String raw)
  throws SAXException  {
    if (name.equalsIgnoreCase(parentName) && foundIt) {
      
      super.contentHandler.endElement(uri,FilterTransformer.BLOCK,FilterTransformer.BLOCK);
      super.contentHandler.endElement(uri,name,raw);
      foundIt=false;
      skip=false;
    } else if (!skip)  {
      super.contentHandler.endElement(uri,name,raw);
    }
  }

  public void characters(char c[], int start, int len)
  throws SAXException {
    if (!skip)  {
      super.contentHandler.characters(c,start,len);
    }
  }

  public void processingInstruction(String target, String data)
  throws SAXException {
    if (!skip)  {
      super.contentHandler.processingInstruction(target, data);
    }
  }

  public void startEntity(String name)
  throws SAXException {
    if (!skip)  {
      super.lexicalHandler.startEntity(name);
    }
  }

  public void endEntity(String name)
  throws SAXException {
    if (!skip)  {
      super.lexicalHandler.endEntity( name);
    }
  }

  public void startCDATA()
  throws SAXException {
    if (!skip)  {
      super.lexicalHandler.startCDATA();
    }
  }

  public void endCDATA()
  throws SAXException {
    if (!skip)  {
      super.lexicalHandler.endCDATA();
    }
  }

  public void comment(char ch[], int start, int len)
  throws SAXException {
    if (!skip)  {
      super.lexicalHandler.comment(ch, start, len);
    }
  }

  /** END SAX ContentHandler handlers **/
}
