/*****************************************************************************
 * Copyright (C) The Apache Software Foundation. All rights reserved.        *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included with this distribution in  *
 * the LICENSE file.                                                         *
 *****************************************************************************/

package org.apache.batik.dom.svg;

import org.apache.batik.parser.DefaultPathHandler;
import org.apache.batik.parser.ParseException;
import org.apache.batik.parser.PathParser;
import org.w3c.dom.DOMException;
import org.w3c.dom.svg.SVGException;
import org.w3c.dom.svg.SVGPathSeg;
import org.w3c.dom.svg.SVGPathSegArcAbs;
import org.w3c.dom.svg.SVGPathSegArcRel; 
import org.w3c.dom.svg.SVGPathSegClosePath;
import org.w3c.dom.svg.SVGPathSegCurvetoCubicAbs;
import org.w3c.dom.svg.SVGPathSegCurvetoCubicRel; 
import org.w3c.dom.svg.SVGPathSegCurvetoCubicSmoothAbs;
import org.w3c.dom.svg.SVGPathSegCurvetoCubicSmoothRel; 
import org.w3c.dom.svg.SVGPathSegCurvetoQuadraticAbs;
import org.w3c.dom.svg.SVGPathSegCurvetoQuadraticRel; 
import org.w3c.dom.svg.SVGPathSegCurvetoQuadraticSmoothAbs;
import org.w3c.dom.svg.SVGPathSegCurvetoQuadraticSmoothRel; 
import org.w3c.dom.svg.SVGPathSegLinetoAbs;
import org.w3c.dom.svg.SVGPathSegLinetoHorizontalAbs;
import org.w3c.dom.svg.SVGPathSegLinetoHorizontalRel; 
import org.w3c.dom.svg.SVGPathSegLinetoRel;
import org.w3c.dom.svg.SVGPathSegLinetoVerticalAbs;
import org.w3c.dom.svg.SVGPathSegLinetoVerticalRel; 
import org.w3c.dom.svg.SVGPathSegList;
import org.w3c.dom.svg.SVGPathSegMovetoAbs;
import org.w3c.dom.svg.SVGPathSegMovetoRel;

/**
 * This class is the implementation of
 * <code>SVGPathSegList</code>.
 *
 * @author nicolas.socheleau@bitflash.com
 * @version $Id: AbstractSVGPathSegList.java,v 1.5 2003/07/01 13:27:26 vhardy Exp $
 */
public abstract class AbstractSVGPathSegList
    extends AbstractSVGList
    implements SVGPathSegList,
               SVGPathSegConstants {

    /**
     * Separator for a point list.
     */
    public final static String SVG_PATHSEG_LIST_SEPARATOR
        =" ";
    /**
     * Creates a new SVGPathSegList.
     */
    protected AbstractSVGPathSegList() {
        super();
    }

    /**
     * Return the separator between segments in the list.
     */
    protected String getItemSeparator(){
        return SVG_PATHSEG_LIST_SEPARATOR;
    }

    /**
     * Create an SVGException when the checkItemType fails.
     *
     * @return SVGException
     */
    protected abstract SVGException createSVGException(short type,
                                                       String key,
                                                       Object[] args);


    /**
     */
    public SVGPathSeg initialize ( SVGPathSeg newItem )
        throws DOMException, SVGException {

        return (SVGPathSeg)initializeImpl(newItem);
    }

    /**
     */
    public SVGPathSeg getItem ( int index )
        throws DOMException {

        return (SVGPathSeg)getItemImpl(index);
    }

    /**
     */
    public SVGPathSeg insertItemBefore ( SVGPathSeg newItem, int index )
        throws DOMException, SVGException {

        return (SVGPathSeg)insertItemBeforeImpl(newItem,index);
    }

    /**
     */
    public SVGPathSeg replaceItem ( SVGPathSeg newItem, int index )
        throws DOMException, SVGException {

        return (SVGPathSeg)replaceItemImpl(newItem,index);
    }

    /**
     */
    public SVGPathSeg removeItem ( int index )
        throws DOMException {

        return (SVGPathSeg)removeItemImpl(index);
    }

    /**
     */
    public SVGPathSeg appendItem ( SVGPathSeg newItem )
        throws DOMException, SVGException {

        return (SVGPathSeg) appendItemImpl(newItem);
    }

    /**
     */
    protected SVGItem createSVGItem(Object newItem){
        
        SVGPathSeg pathSeg = (SVGPathSeg)newItem;

        return createPathSegItem(pathSeg);
    }
    
    /**
     * Parse the 'd' attribute.
     *
     * @param value 'd' attribute value
     * @param handler : list handler
     */
    protected void doParse(String value, ListHandler handler)
        throws ParseException{

        PathParser pathParser = new PathParser();
        
        PathSegListBuilder builder = new PathSegListBuilder(handler);
        
        pathParser.setPathHandler(builder);
        pathParser.parse(value);
        
    }

    /**
     * Check if the item is an SVGPathSeg.
     */
    protected void checkItemType(Object newItem){
        if ( !( newItem instanceof SVGPathSeg ) ){
            createSVGException(SVGException.SVG_WRONG_TYPE_ERR,
                               "expected SVGPathSeg",
                               null);
        }
    }

    /**
     * create an SVGItem representing this SVGPathSeg.
     */
    protected SVGPathSegItem createPathSegItem(SVGPathSeg pathSeg){

        SVGPathSegItem pathSegItem = null;

        short type = pathSeg.getPathSegType();

        switch(type){
        case SVGPathSeg.PATHSEG_ARC_ABS:
        case SVGPathSeg.PATHSEG_ARC_REL:
            pathSegItem = new SVGPathSegArcItem(pathSeg);
            break;
        case SVGPathSeg.PATHSEG_CLOSEPATH:
            pathSegItem = new SVGPathSegItem(pathSeg);
            break;
        case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS:
        case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL:
            pathSegItem = new SVGPathSegCurvetoCubicItem(pathSeg);
            break;
        case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
        case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
            pathSegItem = new SVGPathSegCurvetoCubicSmoothItem(pathSeg);
            break;
        case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS:
        case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL:
            pathSegItem = new SVGPathSegCurvetoQuadraticItem(pathSeg);
            break;
        case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
        case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
            pathSegItem = new SVGPathSegCurvetoQuadraticSmoothItem(pathSeg);
            break;
        case SVGPathSeg.PATHSEG_LINETO_ABS:
        case SVGPathSeg.PATHSEG_LINETO_REL:
        case SVGPathSeg.PATHSEG_MOVETO_ABS:
        case SVGPathSeg.PATHSEG_MOVETO_REL:
            pathSegItem = new SVGPathSegMovetoLinetoItem(pathSeg);
            break;
        case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL:
        case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS:
            pathSegItem = new SVGPathSegLinetoHorizontalItem(pathSeg);
            break;
        case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL:
        case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS:
            pathSegItem = new SVGPathSegLinetoVerticalItem(pathSeg);
            break;
        default:
        }
        return pathSegItem;
    }

    /**
     * Internal representation of the item SVGPathSeg.
     */
    protected class SVGPathSegItem extends AbstractSVGItem
        implements SVGPathSeg,
                   SVGPathSegClosePath {

        protected short type;

        protected String letter;

        protected float x;
        protected float y;
        protected float x1;
        protected float y1;
        protected float x2;
        protected float y2;
        protected float r1;
        protected float r2;
        protected float angle;
        protected boolean largeArcFlag;
        protected boolean sweepFlag;

        protected SVGPathSegItem(){}

        public SVGPathSegItem(short type,String letter){
            this.type = type;
            this.letter = letter;
        }

        public SVGPathSegItem(SVGPathSeg pathSeg){
            this.type = pathSeg.getPathSegType();
            switch(type){
            case SVGPathSeg.PATHSEG_CLOSEPATH:
                letter = PATHSEG_CLOSEPATH_LETTER;
                break;
            default:
            }
        }
        protected String getStringValue(){
            return letter;
        }

        public short getPathSegType() {
            return type;
        }
          
        
        public String getPathSegTypeAsLetter(){
            return letter;
        }
        
    }

    public class SVGPathSegMovetoLinetoItem extends SVGPathSegItem 
        implements SVGPathSegMovetoAbs,
                   SVGPathSegMovetoRel,
                   SVGPathSegLinetoAbs,
                   SVGPathSegLinetoRel {

        public SVGPathSegMovetoLinetoItem(short type, String letter,
                                          float x, float y){
            super(type,letter);
            this.x = x;
            this.y = y;
        }

        public SVGPathSegMovetoLinetoItem(SVGPathSeg pathSeg){
            this.type = pathSeg.getPathSegType();
            switch(type){
            case SVGPathSeg.PATHSEG_LINETO_REL:
                letter = PATHSEG_LINETO_REL_LETTER;
                x = ((SVGPathSegLinetoRel)pathSeg).getX();
                y = ((SVGPathSegLinetoRel)pathSeg).getY();
                break;
            case SVGPathSeg.PATHSEG_LINETO_ABS:
                letter = PATHSEG_LINETO_ABS_LETTER;
                x = ((SVGPathSegLinetoAbs)pathSeg).getX();
                y = ((SVGPathSegLinetoAbs)pathSeg).getY();
                break;
            case SVGPathSeg.PATHSEG_MOVETO_REL:
                letter = PATHSEG_MOVETO_REL_LETTER;
                x = ((SVGPathSegMovetoRel)pathSeg).getX();
                y = ((SVGPathSegMovetoRel)pathSeg).getY();
                break;
            case SVGPathSeg.PATHSEG_MOVETO_ABS:
                letter = PATHSEG_MOVETO_ABS_LETTER;
                x = ((SVGPathSegMovetoAbs)pathSeg).getX();
                y = ((SVGPathSegMovetoAbs)pathSeg).getY();
                break;
            default:
            }
        }

        public float getX(){
            return x;
        }
        public float getY(){
            return y;
        }

        public void setX(float x){
            this.x = x;
            resetAttribute();
        }
        public void setY(float y){
            this.y = y;
            resetAttribute();
        }

        protected String getStringValue(){
            StringBuffer buf = new StringBuffer();
            buf.append(letter);
            buf.append(' ');
            buf.append(Float.toString(x));
            buf.append(' ');
            buf.append(Float.toString(y));
            
            return buf.toString();
        }
    }
    
    public class SVGPathSegCurvetoCubicItem extends SVGPathSegItem 
        implements SVGPathSegCurvetoCubicAbs,
                   SVGPathSegCurvetoCubicRel {

        public SVGPathSegCurvetoCubicItem(short type,String letter,
                                      float x1,float y1,float x2, float y2, 
                                      float x, float y){
            super(type,letter);
            this.x = x;
            this.y = y;
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
        }

        public SVGPathSegCurvetoCubicItem(SVGPathSeg pathSeg){
            this.type = pathSeg.getPathSegType();
            switch(type){
            case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS:
                letter = PATHSEG_CURVETO_CUBIC_ABS_LETTER;
                x = ((SVGPathSegCurvetoCubicAbs)pathSeg).getX();
                y = ((SVGPathSegCurvetoCubicAbs)pathSeg).getY();
                x1 = ((SVGPathSegCurvetoCubicAbs)pathSeg).getX1();
                y1 = ((SVGPathSegCurvetoCubicAbs)pathSeg).getY1();
                x2 = ((SVGPathSegCurvetoCubicAbs)pathSeg).getX2();
                y2 = ((SVGPathSegCurvetoCubicAbs)pathSeg).getY2();
                break;
            case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL:
                letter = PATHSEG_CURVETO_CUBIC_REL_LETTER;
                x = ((SVGPathSegCurvetoCubicRel)pathSeg).getX();
                y = ((SVGPathSegCurvetoCubicRel)pathSeg).getY();
                x1 = ((SVGPathSegCurvetoCubicRel)pathSeg).getX1();
                y1 = ((SVGPathSegCurvetoCubicRel)pathSeg).getY1();
                x2 = ((SVGPathSegCurvetoCubicRel)pathSeg).getX2();
                y2 = ((SVGPathSegCurvetoCubicRel)pathSeg).getY2();
                break;
            default:
            }
        }

        public float getX(){
            return x;
        }
        public float getY(){
            return y;
        }

        public void setX(float x){
            this.x = x;
            resetAttribute();
        }
        public void setY(float y){
            this.y = y;
            resetAttribute();
        }

        public float getX1(){
            return x1;
        }
        public float getY1(){
            return y1;
        }

        public void setX1(float x1){
            this.x1 = x1;
            resetAttribute();
        }
        public void setY1(float y1){
            this.y1 = y1;
            resetAttribute();
        }

        public float getX2(){
            return x2;
        }
        public float getY2(){
            return y2;
        }

        public void setX2(float x2){
            this.x2 = x2;
            resetAttribute();
        }
        public void setY2(float y2){
            this.y2 = y2;
            resetAttribute();
        }

        protected String getStringValue(){
            StringBuffer buf = new StringBuffer();
            buf.append(letter);
            buf.append(' ');
            buf.append(Float.toString(x1));
            buf.append(' ');
            buf.append(Float.toString(y1));
            buf.append(' ');
            buf.append(Float.toString(x2));
            buf.append(' ');
            buf.append(Float.toString(y2));
            buf.append(' ');
            buf.append(Float.toString(x));
            buf.append(' ');
            buf.append(Float.toString(y));

            return buf.toString();
        }
    }

    public class SVGPathSegCurvetoQuadraticItem extends SVGPathSegItem 
        implements SVGPathSegCurvetoQuadraticAbs,
                   SVGPathSegCurvetoQuadraticRel {

        public SVGPathSegCurvetoQuadraticItem(short type,String letter,
                                          float x1,float y1,float x, float y ){
            super(type,letter);
            this.x = x;
            this.y = y;
            this.x1 = x1;
            this.y1 = y1;
        }

        public SVGPathSegCurvetoQuadraticItem(SVGPathSeg pathSeg){
            this.type = pathSeg.getPathSegType();
            switch(type){
            case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS:
                letter = PATHSEG_CURVETO_QUADRATIC_ABS_LETTER;
                x = ((SVGPathSegCurvetoQuadraticAbs)pathSeg).getX();
                y = ((SVGPathSegCurvetoQuadraticAbs)pathSeg).getY();
                x1 = ((SVGPathSegCurvetoQuadraticAbs)pathSeg).getX1();
                y1= ((SVGPathSegCurvetoQuadraticAbs)pathSeg).getY1();
                break;
            case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL:
                letter = PATHSEG_CURVETO_QUADRATIC_REL_LETTER;
                x = ((SVGPathSegCurvetoQuadraticRel)pathSeg).getX();
                y = ((SVGPathSegCurvetoQuadraticRel)pathSeg).getY();
                x1 = ((SVGPathSegCurvetoQuadraticRel)pathSeg).getX1();
                y1= ((SVGPathSegCurvetoQuadraticRel)pathSeg).getY1();
                break;
        default:
 
            }
        }

        public float getX(){
            return x;
        }
        public float getY(){
            return y;
        }

        public void setX(float x){
            this.x = x;
            resetAttribute();
        }
        public void setY(float y){
            this.y = y;
            resetAttribute();
        }

        public float getX1(){
            return x1;
        }
        public float getY1(){
            return y1;
        }

        public void setX1(float x1){
            this.x1 = x1;
            resetAttribute();
        }
        public void setY1(float y1){
            this.y1 = y1;
            resetAttribute();
        }

        protected String getStringValue(){
            StringBuffer buf = new StringBuffer();
            buf.append(letter);
            buf.append(' ');
            buf.append(Float.toString(x1));
            buf.append(' ');
            buf.append(Float.toString(y1));
            buf.append(' ');
            buf.append(Float.toString(x));
            buf.append(' ');
            buf.append(Float.toString(y));
            
            return buf.toString();
        }
    }

    public class SVGPathSegArcItem extends SVGPathSegItem 
        implements SVGPathSegArcAbs,
                   SVGPathSegArcRel {

        public SVGPathSegArcItem(short type,String letter,
                             float r1,float r2,float angle,
                             boolean largeArcFlag, boolean sweepFlag,
                             float x, float y ){
            super(type,letter);
            this.x = x;
            this.y = y;
            this.r1 = r1;
            this.r2 = r2;
            this.angle = angle;
            this.largeArcFlag = largeArcFlag;
            this.sweepFlag = sweepFlag;
        }
        
        public SVGPathSegArcItem(SVGPathSeg pathSeg){
            this.type = pathSeg.getPathSegType();
            switch(type){
            case SVGPathSeg.PATHSEG_ARC_ABS:
                letter = PATHSEG_ARC_ABS_LETTER;
                x = ((SVGPathSegArcAbs)pathSeg).getX();
                y = ((SVGPathSegArcAbs)pathSeg).getY();
                r1 = ((SVGPathSegArcAbs)pathSeg).getR1();
                r2 = ((SVGPathSegArcAbs)pathSeg).getR2();
                angle = ((SVGPathSegArcAbs)pathSeg).getAngle();
                largeArcFlag = ((SVGPathSegArcAbs)pathSeg).getLargeArcFlag();
                sweepFlag = ((SVGPathSegArcAbs)pathSeg).getSweepFlag();
                break;
            case SVGPathSeg.PATHSEG_ARC_REL:
                letter = PATHSEG_ARC_REL_LETTER;
                x = ((SVGPathSegArcRel)pathSeg).getX();
                y = ((SVGPathSegArcRel)pathSeg).getY();
                r1 = ((SVGPathSegArcRel)pathSeg).getR1();
                r2 = ((SVGPathSegArcRel)pathSeg).getR2();
                angle = ((SVGPathSegArcRel)pathSeg).getAngle();
                largeArcFlag = ((SVGPathSegArcRel)pathSeg).getLargeArcFlag();
                sweepFlag = ((SVGPathSegArcRel)pathSeg).getSweepFlag();
                break;
            default:
            }
        }

        public float getX(){
            return x;
        }
        public float getY(){
            return y;
        }

        public void setX(float x){
            this.x = x;
            resetAttribute();
        }
        public void setY(float y){
            this.y = y;
            resetAttribute();
        }

        public float getR1(){
            return r1;
        }
        public float getR2(){
            return r2;
        }

        public void setR1(float r1){
            this.r1 = r1;
            resetAttribute();
        }
        public void setR2(float r2){
            this.r2 = r2;
            resetAttribute();
        }

        public float getAngle(){
            return angle;
        }

        public void setAngle(float angle){
            this.angle = angle;
            resetAttribute();
        }

        public boolean getSweepFlag(){
            return sweepFlag;
        }

        public void setSweepFlag(boolean sweepFlag){
            this.sweepFlag = sweepFlag;
            resetAttribute();
        }

        public boolean getLargeArcFlag(){
            return largeArcFlag;
        }

        public void setLargeArcFlag(boolean largeArcFlag){
            this.largeArcFlag = largeArcFlag;
            resetAttribute();
        }

        protected String getStringValue(){
            StringBuffer buf = new StringBuffer();
            buf.append(letter);
            buf.append(' ');
            buf.append(Float.toString(r1));
            buf.append(' ');
            buf.append(Float.toString(r2));
            buf.append(' ');
            buf.append(Float.toString(angle));
            buf.append(' ');
            buf.append((largeArcFlag?"1":"0"));
            buf.append(' ');
            buf.append((sweepFlag?"1":"0"));
            buf.append(' ');
            buf.append(Float.toString(x));
            buf.append(' ');
            buf.append(Float.toString(y));
            
            return buf.toString();
        }
    }

    public class SVGPathSegLinetoHorizontalItem
        extends SVGPathSegItem 
        implements SVGPathSegLinetoHorizontalAbs,
                   SVGPathSegLinetoHorizontalRel {

        public SVGPathSegLinetoHorizontalItem(short type, String letter,
                                              float value){
            super(type,letter);
            this.x = value;
        }
        public SVGPathSegLinetoHorizontalItem(SVGPathSeg pathSeg){
            this.type = pathSeg.getPathSegType();
            switch(type){
            case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS:
                letter = PATHSEG_LINETO_HORIZONTAL_ABS_LETTER;
                x = ((SVGPathSegLinetoHorizontalAbs)pathSeg).getX();
                break;
            case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL:
                letter = PATHSEG_LINETO_HORIZONTAL_REL_LETTER;
                x = ((SVGPathSegLinetoHorizontalRel)pathSeg).getX();
                break;
            default:
            }
        }

        public float getX(){
            return x;
        }

        public void setX(float x){
            this.x = x;
            resetAttribute();
        }

        protected String getStringValue(){
            StringBuffer buf = new StringBuffer();
            buf.append(letter);
            buf.append(' ');
            buf.append(Float.toString(x));

            return buf.toString();
        }
    }

    public class SVGPathSegLinetoVerticalItem
        extends SVGPathSegItem
    implements SVGPathSegLinetoVerticalAbs,
               SVGPathSegLinetoVerticalRel {

        public SVGPathSegLinetoVerticalItem(short type, String letter,
                                          float value){
            super(type,letter);
            this.y = value;
        }
        
        public SVGPathSegLinetoVerticalItem(SVGPathSeg pathSeg){
            this.type = pathSeg.getPathSegType();
            switch(type){
            case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS:
                letter = PATHSEG_LINETO_VERTICAL_ABS_LETTER;
                y = ((SVGPathSegLinetoVerticalAbs)pathSeg).getY();
                break;
            case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL:
                letter = PATHSEG_LINETO_VERTICAL_REL_LETTER;
                y = ((SVGPathSegLinetoVerticalRel)pathSeg).getY();
                break;
            default:
            }
        }

        public float getY(){
            return y;
        }

        public void setY(float y){
            this.y = y;
            resetAttribute();
        }

        protected String getStringValue(){
            StringBuffer buf = new StringBuffer();
            buf.append(letter);
            buf.append(' ');
            buf.append(Float.toString(y));

            return buf.toString();
        }
    }

    public class SVGPathSegCurvetoCubicSmoothItem extends SVGPathSegItem 
        implements SVGPathSegCurvetoCubicSmoothAbs,
                   SVGPathSegCurvetoCubicSmoothRel {

        public SVGPathSegCurvetoCubicSmoothItem(short type,String letter,
                                          float x2,float y2,float x, float y ){
            super(type,letter);
            this.x = x;
            this.y = y;
            this.x2 = x2;
            this.y2 = y2;
        }

        public SVGPathSegCurvetoCubicSmoothItem(SVGPathSeg pathSeg){
            this.type = pathSeg.getPathSegType();
            switch(type){
            case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
                letter = PATHSEG_CURVETO_CUBIC_SMOOTH_ABS_LETTER;
                x = ((SVGPathSegCurvetoCubicSmoothAbs)pathSeg).getX();
                y = ((SVGPathSegCurvetoCubicSmoothAbs)pathSeg).getY();
                x2 = ((SVGPathSegCurvetoCubicSmoothAbs)pathSeg).getX2();
                y2 = ((SVGPathSegCurvetoCubicSmoothAbs)pathSeg).getY2();
                break;
            case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
                letter = PATHSEG_CURVETO_CUBIC_SMOOTH_REL_LETTER;
                x = ((SVGPathSegCurvetoCubicSmoothRel)pathSeg).getX();
                y = ((SVGPathSegCurvetoCubicSmoothRel)pathSeg).getY();
                x2 = ((SVGPathSegCurvetoCubicSmoothRel)pathSeg).getX2();
                y2 = ((SVGPathSegCurvetoCubicSmoothRel)pathSeg).getY2();
                break;
            default:
            }
        }

        public float getX(){
            return x;
        }
        public float getY(){
            return y;
        }

        public void setX(float x){
            this.x = x;
            resetAttribute();
        }
        public void setY(float y){
            this.y = y;
            resetAttribute();
        }

        public float getX2(){
            return x2;
        }
        public float getY2(){
            return y2;
        }

        public void setX2(float x2){
            this.x2 = x2;
            resetAttribute();
        }
        public void setY2(float y2){
            this.y2 = y2;
            resetAttribute();
        }

        protected String getStringValue(){
            StringBuffer buf = new StringBuffer();
            buf.append(letter);
            buf.append(' ');
            buf.append(Float.toString(x2));
            buf.append(' ');
            buf.append(Float.toString(y2));
            buf.append(' ');
            buf.append(Float.toString(x));
            buf.append(' ');
            buf.append(Float.toString(y));
            
            return buf.toString();
        }
    }

    public class SVGPathSegCurvetoQuadraticSmoothItem extends SVGPathSegItem 
        implements SVGPathSegCurvetoQuadraticSmoothAbs ,
                   SVGPathSegCurvetoQuadraticSmoothRel {

        public SVGPathSegCurvetoQuadraticSmoothItem(short type, String letter,
                                                float x, float y){
            super(type,letter);
            this.x = x;
            this.y = y;
        }

        public SVGPathSegCurvetoQuadraticSmoothItem(SVGPathSeg pathSeg){
            this.type = pathSeg.getPathSegType();
            switch(type){
            case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
                letter = PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS_LETTER;
                x = ((SVGPathSegCurvetoQuadraticSmoothAbs)pathSeg).getX();
                y = ((SVGPathSegCurvetoQuadraticSmoothAbs)pathSeg).getY();
                break;
            case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
                letter = PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL_LETTER;
                x = ((SVGPathSegCurvetoQuadraticSmoothRel)pathSeg).getX();
                y = ((SVGPathSegCurvetoQuadraticSmoothRel)pathSeg).getY();
                break;
            default:
            }
        }

        public float getX(){
            return x;
        }
        public float getY(){
            return y;
        }

        public void setX(float x){
            this.x = x;
            resetAttribute();
        }
        public void setY(float y){
            this.y = y;
            resetAttribute();
        }

        protected String getStringValue(){
            StringBuffer buf = new StringBuffer();
            buf.append(letter);
            buf.append(' ');
            buf.append(Float.toString(x));
            buf.append(' ');
            buf.append(Float.toString(y));
            
            return buf.toString();
        }
    }

    protected class PathSegListBuilder extends DefaultPathHandler {

        protected ListHandler listHandler;

        public PathSegListBuilder(ListHandler listHandler){
            this.listHandler  = listHandler;
        }
        /**
         * Implements {@link org.apache.batik.parser.PathHandler#startPath()}.
         */
        public void startPath() throws ParseException {
            listHandler.startList();
        }

        /**
         * Implements {@link org.apache.batik.parser.PathHandler#endPath()}.
         */
        public void endPath() throws ParseException {
            listHandler.endList();
        }
        
        /**
         * Implements {@link org.apache.batik.parser.PathHandler#movetoRel(float,float)}.
         */
        public void movetoRel(float x, float y) throws ParseException {
            listHandler.item(new SVGPathSegMovetoLinetoItem
                (SVGPathSeg.PATHSEG_MOVETO_REL,PATHSEG_MOVETO_REL_LETTER,
                 x,y));
        }

        /**
         * Implements {@link org.apache.batik.parser.PathHandler#movetoAbs(float,float)}.
         */
        public void movetoAbs(float x, float y) throws ParseException {
            listHandler.item(new SVGPathSegMovetoLinetoItem
                (SVGPathSeg.PATHSEG_MOVETO_ABS,PATHSEG_MOVETO_ABS_LETTER,
                 x,y));
        }

        /**
         * Implements {@link org.apache.batik.parser.PathHandler#closePath()}.
         */
        public void closePath() throws ParseException {
            listHandler.item(new SVGPathSegItem
                (SVGPathSeg.PATHSEG_CLOSEPATH,PATHSEG_CLOSEPATH_LETTER));
            
        }

        /**
         * Implements {@link org.apache.batik.parser.PathHandler#linetoRel(float,float)}.
         */
        public void linetoRel(float x, float y) throws ParseException {
            listHandler.item(new SVGPathSegMovetoLinetoItem
                (SVGPathSeg.PATHSEG_LINETO_REL,PATHSEG_LINETO_REL_LETTER,
                 x,y));
        }

        /**
         * Implements {@link org.apache.batik.parser.PathHandler#linetoAbs(float,float)}.
         */
        public void linetoAbs(float x, float y) throws ParseException {
            listHandler.item(new SVGPathSegMovetoLinetoItem
                (SVGPathSeg.PATHSEG_LINETO_ABS,PATHSEG_LINETO_ABS_LETTER,
                 x,y));
        }

        /**
         * Implements {@link org.apache.batik.parser.PathHandler#linetoHorizontalRel(float)}.
         */
        public void linetoHorizontalRel(float x) throws ParseException {
            listHandler.item(new SVGPathSegLinetoHorizontalItem
                (SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL,PATHSEG_LINETO_HORIZONTAL_REL_LETTER,
                 x));
        }

        /**
         * Implements {@link org.apache.batik.parser.PathHandler#linetoHorizontalAbs(float)}.
         */
        public void linetoHorizontalAbs(float x) throws ParseException {
            listHandler.item(new SVGPathSegLinetoHorizontalItem
                (SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS,PATHSEG_LINETO_HORIZONTAL_ABS_LETTER,
                 x));
        }

        /**
         * Implements {@link org.apache.batik.parser.PathHandler#linetoVerticalRel(float)}.
         */
        public void linetoVerticalRel(float y) throws ParseException {
            listHandler.item(new SVGPathSegLinetoVerticalItem
                (SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL,PATHSEG_LINETO_VERTICAL_REL_LETTER,
                 y));
        }

        /**
         * Implements {@link org.apache.batik.parser.PathHandler#linetoVerticalAbs(float)}.
         */
        public void linetoVerticalAbs(float y) throws ParseException {
            listHandler.item(new SVGPathSegLinetoVerticalItem
                (SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS,PATHSEG_LINETO_VERTICAL_ABS_LETTER,
                 y));
        }

        /**
         * Implements {@link
         * org.apache.batik.parser.PathHandler#curvetoCubicRel(float,float,float,float,float,float)}.
         */
        public void curvetoCubicRel(float x1, float y1, 
                                    float x2, float y2, 
                                    float x, float y) throws ParseException {
            listHandler.item(new SVGPathSegCurvetoCubicItem
                (SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL,PATHSEG_CURVETO_CUBIC_REL_LETTER,
                 x1,y1,x2,y2,x,y));
        }

        /**
         * Implements {@link
         * org.apache.batik.parser.PathHandler#curvetoCubicAbs(float,float,float,float,float,float)}.
         */
        public void curvetoCubicAbs(float x1, float y1, 
                                    float x2, float y2, 
                                    float x, float y) throws ParseException {
            listHandler.item(new SVGPathSegCurvetoCubicItem
                (SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS,PATHSEG_CURVETO_CUBIC_ABS_LETTER,
                 x1,y1,x2,y2,x,y));
        }

        /**
         * Implements {@link
         * org.apache.batik.parser.PathHandler#curvetoCubicSmoothRel(float,float,float,float)}.
         */
        public void curvetoCubicSmoothRel(float x2, float y2, 
                                          float x, float y) throws ParseException {
            listHandler.item(new SVGPathSegCurvetoCubicSmoothItem
                (SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL,PATHSEG_CURVETO_CUBIC_SMOOTH_REL_LETTER,
                 x2,y2,x,y));
        }

        /**
         * Implements {@link
         * org.apache.batik.parser.PathHandler#curvetoCubicSmoothAbs(float,float,float,float)}.
         */
        public void curvetoCubicSmoothAbs(float x2, float y2, 
                                          float x, float y) throws ParseException {
            listHandler.item(new SVGPathSegCurvetoCubicSmoothItem
                (SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS,PATHSEG_CURVETO_CUBIC_SMOOTH_ABS_LETTER,
                 x2,y2,x,y));
        }

        /**
         * Implements {@link
         * org.apache.batik.parser.PathHandler#curvetoQuadraticRel(float,float,float,float)}.
         */
        public void curvetoQuadraticRel(float x1, float y1, 
                                        float x, float y) throws ParseException {
            listHandler.item(new SVGPathSegCurvetoQuadraticItem
                (SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL,PATHSEG_CURVETO_QUADRATIC_REL_LETTER,
                 x1,y1,x,y));
        }

        /**
         * Implements {@link
         * org.apache.batik.parser.PathHandler#curvetoQuadraticAbs(float,float,float,float)}.
         */
        public void curvetoQuadraticAbs(float x1, float y1, 
                                        float x, float y) throws ParseException {
            listHandler.item(new SVGPathSegCurvetoQuadraticItem
                (SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS,PATHSEG_CURVETO_QUADRATIC_ABS_LETTER,
                 x1,y1,x,y));
        }

        /**
         * Implements {@link org.apache.batik.parser.PathHandler#curvetoQuadraticSmoothRel(float,float)}.
         */
        public void curvetoQuadraticSmoothRel(float x, float y)
            throws ParseException {
            listHandler.item(new SVGPathSegCurvetoQuadraticSmoothItem
                (SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL,PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL_LETTER,
                 x,y));
        }

        /**
         * Implements {@link org.apache.batik.parser.PathHandler#curvetoQuadraticSmoothAbs(float,float)}.
         */
        public void curvetoQuadraticSmoothAbs(float x, float y)
            throws ParseException {
            listHandler.item(new SVGPathSegCurvetoQuadraticSmoothItem
                (SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS,PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS_LETTER,
                 x,y));
        }

        /**
         * Implements {@link
         * org.apache.batik.parser.PathHandler#arcRel(float,float,float,boolean,boolean,float,float)}.
         */
        public void arcRel(float rx, float ry, 
                           float xAxisRotation, 
                           boolean largeArcFlag, boolean sweepFlag, 
                           float x, float y) throws ParseException {
            listHandler.item(new SVGPathSegArcItem
                (SVGPathSeg.PATHSEG_ARC_REL,PATHSEG_ARC_REL_LETTER,
                 rx,ry,xAxisRotation,largeArcFlag,sweepFlag,x,y));
        }
        
        /**
         * Implements {@link
         * org.apache.batik.parser.PathHandler#arcAbs(float,float,float,boolean,boolean,float,float)}.
         */
        public void arcAbs(float rx, float ry, 
                           float xAxisRotation, 
                           boolean largeArcFlag, boolean sweepFlag, 
                           float x, float y) throws ParseException {
            listHandler.item(new SVGPathSegArcItem
                (SVGPathSeg.PATHSEG_ARC_ABS,PATHSEG_ARC_ABS_LETTER,
                 rx,ry,xAxisRotation,largeArcFlag,sweepFlag,x,y));
        }
    }
}
