/* Copyright (C) 2011 Garrett Fleenor

 This library is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published by
 the Free Software Foundation; either version 3.0 of the License, or (at
 your option) any later version.

 This library 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 Lesser General Public
 License (COPYING.txt) for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with this library; if not, write to the Free Software Foundation,
 Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

 This is a port of libnoise ( http://libnoise.sourceforge.net/index.html ).  Original implementation by Jason Bevins

 */

package com.bioxx.libnoise.model;

import com.bioxx.jmapgen.Point;
import com.bioxx.libnoise.exception.NoModuleException;
import com.bioxx.libnoise.module.Module;

/**
 * Model that defines the displacement of a line segment.
 * 
 * This model returns an output value from a noise module given the
 * one-dimensional coordinate of an input value located on a line segment, which
 * can be used as displacements.
 * 
 * This class is useful for creating: - roads and rivers - disaffected college
 * students
 * 
 * To generate an output value, pass an input value between 0.0 and 1.0 to the
 * GetValue() method. 0.0 represents the start position of the line segment and
 * 1.0 represents the end position of the line segment.
 */
public class Segment {
	// A flag that specifies whether the value is to be attenuated
	// (moved toward 0.0) as the ends of the line segment are approached.
	boolean attenuate = false;

	// A pointer to the noise module used to generate the output values.
	Module module;

	// @a x coordinate of the start of the line segment.
	double x0 = 0;

	// @a x coordinate of the end of the line segment.
	double x1 = 1;

	// @a y coordinate of the start of the line segment.
	double y0 = 0;

	// @a y coordinate of the end of the line segment.
	double y1 = 1;

	// @a z coordinate of the start of the line segment.
	double z0 = 0;

	// @a z coordinate of the end of the line segment.
	double z1 = 1;

	/**
	 * @param module The noise module that is used to generate the output
	 *            values.
	 */
	public Segment(Module module) {
		if (module == null)
			throw new IllegalArgumentException("module cannot be null");
		this.module = module;
	}

	/**
	 * Returns a flag indicating whether the output value is to be attenuated
	 * (moved toward 0.0) as the ends of the line segment are approached by the
	 * input value.
	 * 
	 * @return true if the value is to be attenuated false if not.
	 */
	public boolean attenuate() {
		return this.attenuate;
	}

	/**
	 * Sets a flag indicating that the output value is to be attenuated (moved
	 * toward 0.0) as the ends of the line segment are approached.
	 * 
	 * @param att A flag that specifies whether the output value is to be
	 *            attenuated.
	 */
	public void setAttenuate(boolean att) {
		this.attenuate = att;
	}

	/**
	 * Sets the position ( @a x, @a y, @a z ) of the start of the line segment
	 * to choose values along.
	 * 
	 * @param x x coordinate of the start position.
	 * @param y y coordinate of the start position.
	 * @param z z coordinate of the start position.
	 */
	public void setStartPoint(double x, double y, double z) {
		this.x0 = x;
		this.y0 = y;
		this.z0 = z;
	}

	/**
	 * Sets the position ( @a x, @a y, @a z ) of the end of the line segment to
	 * choose values along.
	 * 
	 * @param x x coordinate of the end position.
	 * @param y y coordinate of the end position.
	 * @param z z coordinate of the end position.
	 */
	public void setEndPoint(double x, double y, double z) {
		this.x1 = x;
		this.y1 = y;
		this.z1 = z;
	}

	public void setPoints(Point p0, Point p1) {
		this.x0 = p0.x;
		this.y0 = 0;
		this.z0 = p0.y;
		this.x1 = p1.x;
		this.y1 = 0;
		this.z1 = p1.y;
	}

	/**
	 * Returns the noise module that is used to generate the output values.
	 * 
	 * @returns A reference to the noise module.
	 * @pre A noise module was passed to the SetModule() method.
	 */
	public Module getModule() {
		return module;
	}

	/**
	 * Sets the noise module that is used to generate the output values.
	 * 
	 * @param module The noise module that is used to generate the output
	 *            values.
	 * 
	 *            This noise module must exist for the lifetime of this object,
	 *            until you pass a new noise module to this method.
	 */
	public void setModule(Module module) {
		if (module == null)
			throw new IllegalArgumentException("module cannot be null");
		this.module = module;
	}

	/**
	 * Returns the output value from the noise module given the one-dimensional
	 * coordinate of the specified input value located on the line segment.
	 * 
	 * @param p The distance along the line segment (ranges from 0.0 to 1.0)
	 * @return The output value from the noise module.
	 * @pre A noise module was passed to the SetModule() method.
	 * @pre The start and end points of the line segment were specified.
	 * 
	 *      The output value is generated by the noise module passed to the
	 *      SetModule() method. This value may be attenuated (moved toward 0.0)
	 *      as @a p approaches either end of the line segment; this is the
	 *      default behavior.
	 * 
	 *      If the value is not to be attenuated, @a p can safely range outside
	 *      the 0.0 to 1.0 range; the output value will be extrapolated along
	 *      the line that this segment is part of.
	 */
	public double getValue(double p) {
		if (module == null)
			throw new NoModuleException();

		double x = (x1 - x0) * p + x0;
		double y = (y1 - y0) * p + y0;
		double z = (z1 - z0) * p + z0;
		double value = module.GetValue(x, y, z);

		if (attenuate) {
			return p * (1.0 - p) * 4 * value;
		} else {
			return value;
		}

	}

}
