/*
 * $Id: QuadraticSegment.java,v 1.1 2004/12/15 11:54:18 eed3si9n Exp $
 * 
 * $Copyright: copyright (c) 2004, e.e d3si9n $
 * $License: 
 * This source code is part of DoubleType.
 * DoubleType is a graphical typeface designer.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This Program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * In addition, as a special exception, e.e d3si9n gives permission to
 * link the code of this program with any Java Platform that is available
 * to public with free of charge, including but not limited to
 * Sun Microsystem's JAVA(TM) 2 RUNTIME ENVIRONMENT (J2RE),
 * and distribute linked combinations including the two.
 * You must obey the GNU General Public License in all respects for all 
 * of the code used other than Java Platform. If you modify this file, 
 * you may extend this exception to your version of the file, but you are not
 * obligated to do so. If you do not wish to do so, delete this exception
 * statement from your version.
 * $
 */

package org.doubletype.ossa.adapter;

import java.util.*;

import org.doubletype.ossa.xml.XContourPoint;

/**
 * @author e.e
 */
public class QuadraticSegment {
    public static final int LINE = 0;
    public static final int CURVE = 1;
    
    /**
     * converts quadratic contour into a list of quadratic segments.
     * @param a_contour
     * @return
     */
    public static ArrayList<QuadraticSegment> toSegments(EContour a_contour) {
        ArrayList<QuadraticSegment> retval = new ArrayList<>();
        
        ArrayList points = toConcreatePoints(a_contour);
        if (points.size() < 3) {
            return retval;
        } // if
        
        for (int i = 0; i < points.size() - 1; i++) {
            EContourPoint startPoint = (EContourPoint) points.get(i);
            EContourPoint nextPoint = (EContourPoint) points.get(i + 1);
            
            // if this is a line segment
            if (nextPoint.isOn()) {
                retval.add(new QuadraticSegment(startPoint, null, nextPoint));
            } else {
                EContourPoint offCurvePoint = nextPoint;
                i++;
                nextPoint = (EContourPoint) points.get(i + 1);
                retval.add(new QuadraticSegment(startPoint, offCurvePoint, nextPoint));
            } // if-else
        } // for i
        
        return retval;
    }
    
    /**
     * converts a list of quadratic segments into a quadratic contour.
     * @param a_segments
     * @return
     */
    public static EContour toContour(ArrayList<QuadraticSegment> a_segments) {
        EContour retval = new EContour();
        retval.setType(EContour.k_quadratic);
        
        for (QuadraticSegment segment: a_segments) {
            EContourPoint startPoint = (EContourPoint) segment.m_startPoint.clone();
            startPoint.setControlPoint1(null);
            startPoint.setControlPoint2(null);
            
            if (segment.m_type == LINE) {
                retval.addContourPoint(startPoint);
                
            } else {
                retval.addContourPoint(startPoint);
                retval.addContourPoint(segment.m_offCurvePoint);
            }
        } // for i
        
        return retval;
    }
    
    /**
     * converts quadratic contour to concreate points by inserting
     * on-curve point between off-curve points.
     * @param a_contour
     * @return
     */
    private static ArrayList<EContourPoint> toConcreatePoints(EContour a_contour) {
        ArrayList<EContourPoint> retval = new ArrayList<>();
        
        XContourPoint [] points = a_contour.getContourPoint();
		if (points.length < 3)
			return retval;
		
		EContourPoint fromPoint = (EContourPoint) points[points.length - 1];
		for (XContourPoint point: points) {
			EContourPoint toPoint = (EContourPoint) point;
			if (!toPoint.isOn() && !fromPoint.isOn()) {
				double xMidpoint = (toPoint.getX() + fromPoint.getX()) / 2;
				double yMidpoint = (toPoint.getY() + fromPoint.getY()) / 2;
				retval.add(new EContourPoint(xMidpoint, yMidpoint, true));
			} // if
			
			retval.add(toPoint);
			fromPoint = toPoint;
		} // for i
		
		// all contours should start with on-curve point
		// move off-curve point to the end if a contour starts with one.
		EContourPoint firstPoint = (EContourPoint) retval.get(0);
		if (!firstPoint.isOn()) {
			retval.remove(0);
			retval.add(firstPoint);
		} // if
		
		retval.add(retval.get(0));
        
        return retval;
    }
    
    private EContourPoint m_startPoint;
    private EContourPoint m_offCurvePoint;
    private EContourPoint m_endPoint;
    
    private int m_type = LINE;
    
    /**
     * 
     */
    public QuadraticSegment(EContourPoint a_startPoint, EContourPoint a_offCurvePoint,
            	EContourPoint a_endPoint) {
        m_startPoint = a_startPoint;
        m_offCurvePoint = a_offCurvePoint;
        m_endPoint = a_endPoint;
        
        if (m_offCurvePoint != null) {
            m_type = CURVE;
        } // if
    }
    
    /**
     * Convert quadratic segment to cubic.
     * @param a_segment
     * @return
     */
    public CubicSegment toCubicSegment() {        
        // if the segment is a line
        if (m_type == LINE) {
            return new CubicSegment(m_startPoint, m_endPoint);
        } // if
        
        double x, y;
        x = m_startPoint.getX() + 2.0 / 3.0 * (m_offCurvePoint.getX() - m_startPoint.getX());
        y = m_startPoint.getY() + 2.0 / 3.0 * (m_offCurvePoint.getY() - m_startPoint.getY());
        EContourPoint controlPoint1 = new EContourPoint(x, y, false);
        
        x = m_offCurvePoint.getX() + 1.0 / 3.0 * (m_endPoint.getX() - m_offCurvePoint.getX());
        y = m_offCurvePoint.getY() + 1.0 / 3.0 * (m_endPoint.getY() - m_offCurvePoint.getY());
        EContourPoint controlPoint2 = new EContourPoint(x, y, false);
        
        return new CubicSegment(m_startPoint, controlPoint1, controlPoint2, m_endPoint);
    } 

}
