/*

Coyright 2018 Glen Whitney

This file is contributed to C.a.R./CaRMetal software.

    C.a.R. is a 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, version 3 of the License.

    C.a.R. 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, see <http://www.gnu.org/licenses/>.
 
 */

package rene.zirkel.objects;

import rene.gui.Global;
import rene.zirkel.construction.Construction;
import rene.zirkel.construction.ConstructionException;
import rene.zirkel.expression.Expression;

/* A three dimensional circle determined by a 3D point (the "midpoint" of the super
   object), an expression giving its radius, and a TwoPointLineObject
   determined by two 3D points, giving its normal direction. (The line does
   not have to go through the center.
*/
public class Circle3DObject extends PrimitiveCircleObject {
    Expression E_R; // Expression for the radius
    TwoPointLineObject N;

    public Circle3DObject(final Construction c, final PointObject C,
			  final String s, final TwoPointLineObject L)
    throws ConstructionException {
	super(c, C);
	if (!C.is3D()) {
	    throw new ConstructionException("Cannot create Circle3D with "
					    + "non-3D center " +  C.getName());
	}
	if (!L.getP1().is3D() || !L.getP2().is3D()) {
	    throw new ConstructionException("Cannot create Circle3D with "
					    + "non-3D normal " + L.getName());
	}
	E_R = new Expression(s, c, this);
	N = L;
	validate();
	updateText();
    }

    @Override
    public String getTag() {
	return "Circle3D";
    }

    @Override
    public void updateText() {
	setText(text3(Global.name("text.circle3D"),
		      M.getName(), E_R.toString(), N.getName()));
    }

    @Override
    public void validate() {
	super.validate();
	Valid = false;
	if (!M.valid() || !E_R.valid() || !N.valid()) {
	    return;
	}
	try { R = E_R.getValue(); } catch (final Exception e) {
	    R = 0;
	    return;
	}
	if (R < 0) { return; }
	Valid = true;
    }

    @Override
    public void printArgs(final XmlWriter xml) {
	xml.printArg("radius", E_R.toString());
	xml.printArg("normal", N.getName());
	super.printArgs(xml);
    }

    @Override
    public String getStringLength() {
	return E_R.toString();
    }

    @Override
    public double getValue() throws ConstructionException {
	if (!Valid) {
	    throw new InvalidException("exception.invalid");
	} else {
	    return R;
	}
    }

    @Override
    public Enumeration depending() {
	super.depending();
	final Enumeration e = E_R.getDepList().elements();
	while (e.hasMoreElements()) {
	    DL.add((ConstructionObject) e.nextElement());
	}
	DL.add(N);
	return DL.elements();
    }

    /* A (rudimentary version) of the class is almost done at this point, but
       it still needs a paint() method. This we want to share with the
       QuadricObject. The best way I could think of was to create a class that
       encapsulates the X[..] data in QuadricObject, with a method to set that
       up from 5 (x,y) pairs. In QuadricObject, I woul just use the 5 (x,y)
       values of the Point members. Here, in validate, I would use the center,
       radius, and normal data to compute 5 equally-spaced (x,y,z) coordinates
       around the circle. The sticking point is then projecting those to
       (x,y). There does not seem to be any good way to do it -- it seems like
       Expressions that do it are littered all around the code. Ugh. So I am
       giving up for now. 
    */
}
