//# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
//# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
//# License for more details.
//#
//# You should have received a copy of the GNU Library General Public License
//# along with this library; if not, write to the Free Software Foundation,
//# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
//#
//# Correspondence concerning AIPS++ should be addressed as follows:
//#        Internet email: aips2-request@nrao.edu.
//#        Postal address: AIPS++ Project Office
//#                        National Radio Astronomy Observatory
//#                        520 Edgemont Road
//#                        Charlottesville, VA 22903-2475 USA
//#


#include <imageanalysis/Annotations/AnnPolyline.h>

#include <casacore/images/Regions/WCPolygon.h>

using namespace casacore;
namespace casa {

AnnPolyline::AnnPolyline(
	const Vector<Quantity>& xPositions,
	const Vector<Quantity>& yPositions,
	const String& dirRefFrameString,
	const CoordinateSystem& csys,
	const IPosition& imShape,
	const Quantity& beginFreq,
	const Quantity& endFreq,
	const String& freqRefFrameString,
	const String& dopplerString,
	const Quantity& restfreq,
	const Vector<Stokes::StokesTypes> stokes,
	const Bool annotationOnly,
	const Bool requireImageRegion
) : AnnRegion(
		POLYLINE, dirRefFrameString, csys, imShape, beginFreq,
		endFreq, freqRefFrameString, dopplerString,
		restfreq, stokes, annotationOnly, requireImageRegion
), _origXPos(xPositions), _origYPos(yPositions) {
	_init();
}

AnnPolyline::AnnPolyline(
	const Vector<Quantity>& xPositions,
	const Vector<Quantity>& yPositions,
	const CoordinateSystem& csys,
	const IPosition& imShape,
	const Vector<Stokes::StokesTypes>& stokes,
	const Bool requireImageRegion
) : AnnRegion(POLYGON, csys, imShape, stokes, requireImageRegion),
	_origXPos(xPositions), _origYPos(yPositions) {
	_init();
}

AnnPolyline& AnnPolyline::operator= (
	const AnnPolyline& other
) {
	if (this == &other) {
		return *this;
	}
	AnnRegion::operator=(other);
	_origXPos.resize(other._origXPos.nelements());
	_origXPos = other._origXPos;
	_origYPos.resize(other._origYPos.nelements());
	_origYPos = other._origYPos;
	return *this;
}

Vector<MDirection> AnnPolyline::getCorners() const {
	return getConvertedDirections();
}

ostream& AnnPolyline::print(ostream &os) const {
	_printPrefix(os);
	os << "poly [";
	for (uInt i=0; i<_origXPos.size(); i++) {
		os << "[" << _printDirection(_origXPos[i], _origYPos[i]) << "]";
		if (i < _origXPos.size()-1) {
			os << ", ";
		}
	}
	os << "]";
	_printPairs(os);
	return os;
}

void AnnPolyline::worldVertices(vector<Quantity>& x, vector<Quantity>& y) const {
	const CoordinateSystem csys = getCsys();
	const IPosition dirAxes = _getDirectionAxes();
	String xUnit = csys.worldAxisUnits()[dirAxes[0]];
	String yUnit = csys.worldAxisUnits()[dirAxes[1]];
	Vector<MDirection> corners = getConvertedDirections();
	x.resize(corners.size());
	y.resize(corners.size());
	for (uInt i=0; i<corners.size(); i++) {
		x[i] = Quantity(corners[i].getAngle(xUnit).getValue(xUnit)[0], xUnit);
		y[i] = Quantity(corners[i].getAngle(yUnit).getValue(yUnit)[1], yUnit);
	}
}

void AnnPolyline::pixelVertices(vector<Double>& x, vector<Double>& y) const {
	vector<Quantity> xx, xy;
	worldVertices(xx, xy);

	const CoordinateSystem csys = getCsys();
	Vector<Double> world = csys.referenceValue();
	const IPosition dirAxes = _getDirectionAxes();
	String xUnit = csys.worldAxisUnits()[dirAxes[0]];
	String yUnit = csys.worldAxisUnits()[dirAxes[1]];

	x.resize(xx.size());
	y.resize(xx.size());

	for (uInt i=0; i<xx.size(); i++) {
		world[dirAxes[0]] = xx[i].getValue(xUnit);
		world[dirAxes[1]] = xy[i].getValue(yUnit);
		Vector<Double> pixel;
		csys.toPixel(pixel, world);
		x[i] = pixel[dirAxes[0]];
		y[i] = pixel[dirAxes[1]];
	}
}

void AnnPolyline::_init() {
	String preamble(String(__FUNCTION__) + ": ");
	if (_origXPos.size() != _origYPos.size()) {
		throw AipsError(
			preamble + "x and y vectors are not the same length but must be."
		);
	}
	AnnotationBase::Direction corners(_origXPos.size());
	for (uInt i=0; i<_origXPos.size(); i++) {
		corners[i].first = _origXPos[i];
		corners[i].second = _origYPos[i];
	}
	_checkAndConvertDirections(String(__FUNCTION__), corners);
	Vector<Double> xv(_origXPos.size()), yv(_origYPos.size());
	for (uInt i=0; i<xv.size(); i++) {
		Vector<Double> coords = getConvertedDirections()[i].getAngle("rad").getValue();
		xv[i] = coords[0];
		yv[i] = coords[1];
	}
	Quantum<Vector<Double> > x(xv, "rad");
	Quantum<Vector<Double> > y(yv, "rad");
	try {
		WCPolygon wpoly(
			x, y, IPosition(_getDirectionAxes()),
			getCsys(), RegionType::Abs
		);
		_setDirectionRegion(wpoly);
		_extend();
	} catch (const ToLCRegionConversionError& err) {
		if (_requireImageRegion) {
			throw(err);
		} else {
			ImageRegion defaultRegion;
			_setDirectionRegion(defaultRegion);
			_imageRegion = _directionRegion;
		}
	}
}


}