/*++

Copyright (C) 2024 3MF Consortium (Original Author)

All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

This file has been generated by the Automatic Component Toolkit (ACT) version 1.8.1-develop.

Abstract: This is an autogenerated Java file in order to allow an easy
 use of the 3MF Library

Interface version: 2.5.0

*/

package lib3mf;

import com.sun.jna.Library;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;


import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

public class MeshObject extends Object {

	public MeshObject(Lib3MFWrapper wrapper, Pointer handle) {
		super(wrapper, handle);
	}

	/**
	 * Returns the vertex count of a mesh object.
	 *
	 * @return filled with the vertex count.
	 * @throws Lib3MFException
	 */
	public int getVertexCount() throws Lib3MFException {
		Pointer bufferVertexCount = new Memory(4);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_getvertexcount.invokeInt(new java.lang.Object[]{mHandle, bufferVertexCount}));
		return bufferVertexCount.getInt(0);
	}

	/**
	 * Returns the triangle count of a mesh object.
	 *
	 * @return filled with the triangle count.
	 * @throws Lib3MFException
	 */
	public int getTriangleCount() throws Lib3MFException {
		Pointer bufferVertexCount = new Memory(4);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_gettrianglecount.invokeInt(new java.lang.Object[]{mHandle, bufferVertexCount}));
		return bufferVertexCount.getInt(0);
	}

	/**
	 * Returns the vertex count of a mesh object.
	 *
	 * @param index Index of the vertex (0 to vertexcount - 1)
	 * @return filled with the vertex coordinates.
	 * @throws Lib3MFException
	 */
	public Position getVertex(int index) throws Lib3MFException {
		Pointer bufferCoordinates = new Memory(Position.SIZE);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_getvertex.invokeInt(new java.lang.Object[]{mHandle, index, bufferCoordinates}));
		Position coordinates = new Position();
		coordinates.readFromPointer(bufferCoordinates, 0);
		return coordinates;
	}

	/**
	 * Sets the coordinates of a single vertex of a mesh object
	 *
	 * @param index Index of the vertex (0 to vertexcount - 1)
	 * @param coordinates contains the vertex coordinates.
	 * @throws Lib3MFException
	 */
	public void setVertex(int index, Position coordinates) throws Lib3MFException {
		Pointer bufferCoordinates = new Memory(Position.SIZE);
		coordinates.writeToPointer(bufferCoordinates, 0);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_setvertex.invokeInt(new java.lang.Object[]{mHandle, index, bufferCoordinates}));
	}

	/**
	 * Adds a single vertex to a mesh object
	 *
	 * @param coordinates contains the vertex coordinates.
	 * @return Index of the new vertex
	 * @throws Lib3MFException
	 */
	public int addVertex(Position coordinates) throws Lib3MFException {
		Pointer bufferCoordinates = new Memory(Position.SIZE);
		coordinates.writeToPointer(bufferCoordinates, 0);
		Pointer bufferNewIndex = new Memory(4);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_addvertex.invokeInt(new java.lang.Object[]{mHandle, bufferCoordinates, bufferNewIndex}));
		return bufferNewIndex.getInt(0);
	}

	/**
	 * Obtains all vertex positions of a mesh object
	 *
	 * @return contains the vertex coordinates.
	 * @throws Lib3MFException
	 */
	public Position[] getVertices() throws Lib3MFException {
		Pointer countNeededVertices = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_getvertices.invokeInt(new java.lang.Object[]{mHandle, 0L, countNeededVertices, null}));
		long countVertices = countNeededVertices.getLong(0);
		Pointer bufferVertices = new Memory(Math.max(1, countVertices * Position.SIZE));
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_getvertices.invokeInt(new java.lang.Object[]{mHandle, countVertices, countNeededVertices, bufferVertices}));
		Position vertices[] = new Position[(int)countVertices];
		for (int i = 0; i < (int)countVertices; i++) {
		  vertices[i] = new Position();
		  vertices[i].readFromPointer(bufferVertices, i * Position.SIZE);
		}
		return vertices;
	}

	/**
	 * Returns indices of a single triangle of a mesh object.
	 *
	 * @param index Index of the triangle (0 to trianglecount - 1)
	 * @return filled with the triangle indices.
	 * @throws Lib3MFException
	 */
	public Triangle getTriangle(int index) throws Lib3MFException {
		Pointer bufferIndices = new Memory(Triangle.SIZE);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_gettriangle.invokeInt(new java.lang.Object[]{mHandle, index, bufferIndices}));
		Triangle indices = new Triangle();
		indices.readFromPointer(bufferIndices, 0);
		return indices;
	}

	/**
	 * Sets the indices of a single triangle of a mesh object.
	 *
	 * @param index Index of the triangle (0 to trianglecount - 1)
	 * @param indices contains the triangle indices.
	 * @throws Lib3MFException
	 */
	public void setTriangle(int index, Triangle indices) throws Lib3MFException {
		Pointer bufferIndices = new Memory(Triangle.SIZE);
		indices.writeToPointer(bufferIndices, 0);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_settriangle.invokeInt(new java.lang.Object[]{mHandle, index, bufferIndices}));
	}

	/**
	 * Adds a single triangle to a mesh object
	 *
	 * @param indices contains the triangle indices.
	 * @return Index of the new triangle
	 * @throws Lib3MFException
	 */
	public int addTriangle(Triangle indices) throws Lib3MFException {
		Pointer bufferIndices = new Memory(Triangle.SIZE);
		indices.writeToPointer(bufferIndices, 0);
		Pointer bufferNewIndex = new Memory(4);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_addtriangle.invokeInt(new java.lang.Object[]{mHandle, bufferIndices, bufferNewIndex}));
		return bufferNewIndex.getInt(0);
	}

	/**
	 * Get all triangles of a mesh object
	 *
	 * @return contains the triangle indices.
	 * @throws Lib3MFException
	 */
	public Triangle[] getTriangleIndices() throws Lib3MFException {
		Pointer countNeededIndices = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_gettriangleindices.invokeInt(new java.lang.Object[]{mHandle, 0L, countNeededIndices, null}));
		long countIndices = countNeededIndices.getLong(0);
		Pointer bufferIndices = new Memory(Math.max(1, countIndices * Triangle.SIZE));
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_gettriangleindices.invokeInt(new java.lang.Object[]{mHandle, countIndices, countNeededIndices, bufferIndices}));
		Triangle indices[] = new Triangle[(int)countIndices];
		for (int i = 0; i < (int)countIndices; i++) {
		  indices[i] = new Triangle();
		  indices[i].readFromPointer(bufferIndices, i * Triangle.SIZE);
		}
		return indices;
	}

	/**
	 * Sets the property at the object-level of the mesh object.
	 *
	 * @param uniqueResourceID the object-level Property UniqueResourceID.
	 * @param propertyID the object-level PropertyID.
	 * @throws Lib3MFException
	 */
	public void setObjectLevelProperty(int uniqueResourceID, int propertyID) throws Lib3MFException {
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_setobjectlevelproperty.invokeInt(new java.lang.Object[]{mHandle, uniqueResourceID, propertyID}));
	}

	/**
	 * Gets the property at the object-level of the mesh object.
	 *
	 * @return GetObjectLevelProperty Result Tuple
	 * @throws Lib3MFException
	 */
	public GetObjectLevelPropertyResult getObjectLevelProperty() throws Lib3MFException {
		Pointer bufferUniqueResourceID = new Memory(4);
		Pointer bufferPropertyID = new Memory(4);
		Pointer bufferHasObjectLevelProperty = new Memory(1);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_getobjectlevelproperty.invokeInt(new java.lang.Object[]{mHandle, bufferUniqueResourceID, bufferPropertyID, bufferHasObjectLevelProperty}));
		GetObjectLevelPropertyResult returnTuple = new GetObjectLevelPropertyResult();
		returnTuple.UniqueResourceID = bufferUniqueResourceID.getInt(0);
		returnTuple.PropertyID = bufferPropertyID.getInt(0);
		returnTuple.HasObjectLevelProperty = bufferHasObjectLevelProperty.getByte(0) != 0;
		return returnTuple;
	}

	public static class GetObjectLevelPropertyResult {
		/**
		 * the object-level Property UniqueResourceID.
		 */
		public int UniqueResourceID;

		/**
		 * the object-level PropertyID.
		 */
		public int PropertyID;

		/**
		 * Has an object-level property been specified?
		 */
		public boolean HasObjectLevelProperty;

	}
	/**
	 * Sets the properties of a single triangle of a mesh object.
	 *
	 * @param index Index of the triangle (0 to trianglecount - 1)
	 * @param properties contains the triangle properties.
	 * @throws Lib3MFException
	 */
	public void setTriangleProperties(int index, TriangleProperties properties) throws Lib3MFException {
		Pointer bufferProperties = new Memory(TriangleProperties.SIZE);
		properties.writeToPointer(bufferProperties, 0);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_settriangleproperties.invokeInt(new java.lang.Object[]{mHandle, index, bufferProperties}));
	}

	/**
	 * Gets the properties of a single triangle of a mesh object.
	 *
	 * @param index Index of the triangle (0 to trianglecount - 1)
	 * @return returns the triangle properties.
	 * @throws Lib3MFException
	 */
	public TriangleProperties getTriangleProperties(int index) throws Lib3MFException {
		Pointer bufferProperty = new Memory(TriangleProperties.SIZE);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_gettriangleproperties.invokeInt(new java.lang.Object[]{mHandle, index, bufferProperty}));
		TriangleProperties property = new TriangleProperties();
		property.readFromPointer(bufferProperty, 0);
		return property;
	}

	/**
	 * Sets the properties of all triangles of a mesh object. Sets the object level property to the first entry of the passed triangle properties, if not yet specified.
	 *
	 * @param propertiesArray contains the triangle properties array. Must have trianglecount elements.
	 * @throws Lib3MFException
	 */
	public void setAllTriangleProperties(TriangleProperties[] propertiesArray) throws Lib3MFException {
		Pointer bufferPropertiesArray = new Memory(Math.max(1, TriangleProperties.SIZE * propertiesArray.length));
		for (int i = 0; i < propertiesArray.length; i++) {
		  propertiesArray[i].writeToPointer(bufferPropertiesArray, i * TriangleProperties.SIZE);
		}
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_setalltriangleproperties.invokeInt(new java.lang.Object[]{mHandle, (long) propertiesArray.length, bufferPropertiesArray}));
	}

	/**
	 * Gets the properties of all triangles of a mesh object.
	 *
	 * @return returns the triangle properties array. Must have trianglecount elements.
	 * @throws Lib3MFException
	 */
	public TriangleProperties[] getAllTriangleProperties() throws Lib3MFException {
		Pointer countNeededPropertiesArray = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_getalltriangleproperties.invokeInt(new java.lang.Object[]{mHandle, 0L, countNeededPropertiesArray, null}));
		long countPropertiesArray = countNeededPropertiesArray.getLong(0);
		Pointer bufferPropertiesArray = new Memory(Math.max(1, countPropertiesArray * TriangleProperties.SIZE));
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_getalltriangleproperties.invokeInt(new java.lang.Object[]{mHandle, countPropertiesArray, countNeededPropertiesArray, bufferPropertiesArray}));
		TriangleProperties propertiesArray[] = new TriangleProperties[(int)countPropertiesArray];
		for (int i = 0; i < (int)countPropertiesArray; i++) {
		  propertiesArray[i] = new TriangleProperties();
		  propertiesArray[i].readFromPointer(bufferPropertiesArray, i * TriangleProperties.SIZE);
		}
		return propertiesArray;
	}

	/**
	 * Clears all properties of this mesh object (triangle and object-level).
	 *
	 * @throws Lib3MFException
	 */
	public void clearAllProperties() throws Lib3MFException {
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_clearallproperties.invokeInt(new java.lang.Object[]{mHandle}));
	}

	/**
	 * Set all triangles of a mesh object
	 *
	 * @param vertices contains the positions.
	 * @param indices contains the triangle indices.
	 * @throws Lib3MFException
	 */
	public void setGeometry(Position[] vertices, Triangle[] indices) throws Lib3MFException {
		Pointer bufferVertices = new Memory(Math.max(1, Position.SIZE * vertices.length));
		for (int i = 0; i < vertices.length; i++) {
		  vertices[i].writeToPointer(bufferVertices, i * Position.SIZE);
		}
		Pointer bufferIndices = new Memory(Math.max(1, Triangle.SIZE * indices.length));
		for (int i = 0; i < indices.length; i++) {
		  indices[i].writeToPointer(bufferIndices, i * Triangle.SIZE);
		}
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_setgeometry.invokeInt(new java.lang.Object[]{mHandle, (long) vertices.length, bufferVertices, (long) indices.length, bufferIndices}));
	}

	/**
	 * Retrieves, if an object describes a topologically oriented and manifold mesh, according to the core spec.
	 *
	 * @return returns, if the object is oriented and manifold.
	 * @throws Lib3MFException
	 */
	public boolean isManifoldAndOriented() throws Lib3MFException {
		Pointer bufferIsManifoldAndOriented = new Memory(1);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_ismanifoldandoriented.invokeInt(new java.lang.Object[]{mHandle, bufferIsManifoldAndOriented}));
		return bufferIsManifoldAndOriented.getByte(0) != 0;
	}

	/**
	 * Retrieves the BeamLattice within this MeshObject.
	 *
	 * @return the BeamLattice within this MeshObject
	 * @throws Lib3MFException
	 */
	public BeamLattice beamLattice() throws Lib3MFException {
		Pointer bufferTheBeamLattice = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_beamlattice.invokeInt(new java.lang.Object[]{mHandle, bufferTheBeamLattice}));
		Pointer valueTheBeamLattice = bufferTheBeamLattice.getPointer(0);
		BeamLattice theBeamLattice = null;
		if (valueTheBeamLattice == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "TheBeamLattice was a null pointer");
		}
		theBeamLattice = mWrapper.PolymorphicFactory(valueTheBeamLattice, BeamLattice.class);
		return theBeamLattice;
	}

	/**
	 * Retrieves the VolumeData of this MeshObject.
	 *
	 * @return the VolumeData of this MeshObject
	 * @throws Lib3MFException
	 */
	public VolumeData getVolumeData() throws Lib3MFException {
		Pointer bufferTheVolumeData = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_getvolumedata.invokeInt(new java.lang.Object[]{mHandle, bufferTheVolumeData}));
		Pointer valueTheVolumeData = bufferTheVolumeData.getPointer(0);
		VolumeData theVolumeData = null;
		if (valueTheVolumeData != Pointer.NULL) {
		  theVolumeData = mWrapper.PolymorphicFactory(valueTheVolumeData, VolumeData.class);
		}
		return theVolumeData;
	}

	/**
	 * Sets the VolumeData of this MeshObject.
	 *
	 * @param theVolumeData the VolumeData of this MeshObject
	 * @throws Lib3MFException
	 */
	public void setVolumeData(VolumeData theVolumeData) throws Lib3MFException {
		Pointer theVolumeDataHandle = null;
		if (theVolumeData != null) {
			theVolumeDataHandle = theVolumeData.getHandle();
		} else {
			throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "TheVolumeData is a null value.");
		}
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_setvolumedata.invokeInt(new java.lang.Object[]{mHandle, theVolumeDataHandle}));
	}

	/**
	 * Adds a new triangle set.
	 *
	 * @param identifier the new identifier. MUST be unique within the mesh. MUST NOT be an empty string
	 * @param name the human readable name. MUST NOT be an empty string
	 * @return the new Triangle Set Instance.
	 * @throws Lib3MFException
	 */
	public TriangleSet addTriangleSet(String identifier, String name) throws Lib3MFException {
		byte[] bytesIdentifier = identifier.getBytes(StandardCharsets.UTF_8);
		Memory bufferIdentifier = new Memory(bytesIdentifier.length + 1);
		bufferIdentifier.write(0, bytesIdentifier, 0, bytesIdentifier.length);
		bufferIdentifier.setByte(bytesIdentifier.length, (byte)0);
		byte[] bytesName = name.getBytes(StandardCharsets.UTF_8);
		Memory bufferName = new Memory(bytesName.length + 1);
		bufferName.write(0, bytesName, 0, bytesName.length);
		bufferName.setByte(bytesName.length, (byte)0);
		Pointer bufferTheTriangleSet = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_addtriangleset.invokeInt(new java.lang.Object[]{mHandle, bufferIdentifier, bufferName, bufferTheTriangleSet}));
		Pointer valueTheTriangleSet = bufferTheTriangleSet.getPointer(0);
		TriangleSet theTriangleSet = null;
		if (valueTheTriangleSet == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "TheTriangleSet was a null pointer");
		}
		theTriangleSet = mWrapper.PolymorphicFactory(valueTheTriangleSet, TriangleSet.class);
		return theTriangleSet;
	}

	/**
	 * Checks if a triangle set exists.
	 *
	 * @param identifier the identifier to be found.
	 * @return flag if the triangles set exists.
	 * @throws Lib3MFException
	 */
	public boolean hasTriangleSet(String identifier) throws Lib3MFException {
		byte[] bytesIdentifier = identifier.getBytes(StandardCharsets.UTF_8);
		Memory bufferIdentifier = new Memory(bytesIdentifier.length + 1);
		bufferIdentifier.write(0, bytesIdentifier, 0, bytesIdentifier.length);
		bufferIdentifier.setByte(bytesIdentifier.length, (byte)0);
		Pointer bufferTriangleSetExists = new Memory(1);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_hastriangleset.invokeInt(new java.lang.Object[]{mHandle, bufferIdentifier, bufferTriangleSetExists}));
		return bufferTriangleSetExists.getByte(0) != 0;
	}

	/**
	 * Finds a new triangle set by identifier. Fails if not existing.
	 *
	 * @param identifier the identifier to be found.
	 * @return the triangle Set Instance.
	 * @throws Lib3MFException
	 */
	public TriangleSet findTriangleSet(String identifier) throws Lib3MFException {
		byte[] bytesIdentifier = identifier.getBytes(StandardCharsets.UTF_8);
		Memory bufferIdentifier = new Memory(bytesIdentifier.length + 1);
		bufferIdentifier.write(0, bytesIdentifier, 0, bytesIdentifier.length);
		bufferIdentifier.setByte(bytesIdentifier.length, (byte)0);
		Pointer bufferTheTriangleSet = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_findtriangleset.invokeInt(new java.lang.Object[]{mHandle, bufferIdentifier, bufferTheTriangleSet}));
		Pointer valueTheTriangleSet = bufferTheTriangleSet.getPointer(0);
		TriangleSet theTriangleSet = null;
		if (valueTheTriangleSet == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "TheTriangleSet was a null pointer");
		}
		theTriangleSet = mWrapper.PolymorphicFactory(valueTheTriangleSet, TriangleSet.class);
		return theTriangleSet;
	}

	/**
	 * Returns number of triangle sets.
	 *
	 * @return the number of triangle sets of this mesh.
	 * @throws Lib3MFException
	 */
	public int getTriangleSetCount() throws Lib3MFException {
		Pointer bufferCount = new Memory(4);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_gettrianglesetcount.invokeInt(new java.lang.Object[]{mHandle, bufferCount}));
		return bufferCount.getInt(0);
	}

	/**
	 * Returns a specific triangle set by index.
	 *
	 * @param index the index of the triangle set.
	 * @return the triangle Set Instance.
	 * @throws Lib3MFException
	 */
	public TriangleSet getTriangleSet(int index) throws Lib3MFException {
		Pointer bufferTheTriangleSet = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_meshobject_gettriangleset.invokeInt(new java.lang.Object[]{mHandle, index, bufferTheTriangleSet}));
		Pointer valueTheTriangleSet = bufferTheTriangleSet.getPointer(0);
		TriangleSet theTriangleSet = null;
		if (valueTheTriangleSet == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "TheTriangleSet was a null pointer");
		}
		theTriangleSet = mWrapper.PolymorphicFactory(valueTheTriangleSet, TriangleSet.class);
		return theTriangleSet;
	}


}

