docs: @SuppressWarnings({"checkstyle:cyclomaticcomplexity", "checkstyle:npathcomplexity"})
  	private E readPolyElement(int elementIndex, ShapeElementType type) throws IOException {
  		final boolean hasZ = type.hasZ();
  		final boolean hasM = type.hasM();
  
  		// Ignore the bounds stored inside the file
  		skipBytes(8 * 4);
  
  		// Count of parts
  		final int numParts;
  		if (type == ShapeElementType.MULTIPOINT || type == ShapeElementType.MULTIPOINT_Z
  				|| type == ShapeElementType.MULTIPOINT_M) {
  			numParts = 0;
  		} else {
  			numParts = readLEInt();
  		}
  
  		// Count of points
  		final int numPoints = readLEInt();
  
  		// Read the parts' indexes
  		final int[] parts = new int[numParts];
  		for (int idxParts = 0; idxParts < numParts; ++idxParts) {
  			parts[idxParts] = readLEInt();
  		}
  
  		// Read the points
  		final ESRIPoint[] points = new ESRIPoint[numPoints];
  
  		for (int idxPoints = 0; idxPoints < numPoints; ++idxPoints) {
  			// Read coordinates
  			final double x = fromESRI_x(readLEDouble());
  			final double y = fromESRI_y(readLEDouble());
  
  			// Create point
  			if (!Double.isNaN(x) && !Double.isNaN(y)) {
  				points[idxPoints] = new ESRIPoint(x, y);
  			} else {
  				throw new ShapeFileException("invalid (x,y) coordinates"); //$NON-NLS-1$
  			}
  		} // for i= 0 to numPoints
  
  		if (hasZ) {
  			// Zmin and Zmax: 2*Double - ignored
  			skipBytes(2 * 8);
  			// Z array: numpoints*Double
  			double z;
  			for (int i = 0; i < numPoints; ++i) {
  				z = fromESRI_z(readLEDouble());
  				if (!Double.isNaN(z)) {
  					points[i].setZ(z);
  				}
  			}
  		}
  
  		if (hasM) {
  			// Mmin and Mmax: 2*Double - ignored
  			skipBytes(2 * 8);
  			// M array: numpoints*Double
  			double measure;
  			for (int i = 0; i < numPoints; ++i) {
  				measure = fromESRI_m(readLEDouble());
  				if (!Double.isNaN(measure)) {
  					points[i].setM(measure);
  				}
  			}
  		}
  
  		// Create the instance of the element
  		E newElement = null;
  		switch (type) {
  		case POLYGON_Z:
  		case POLYGON_M:
  		case POLYGON:
  			newElement = createPolygon(createAttributeCollection(elementIndex), elementIndex, parts, points, hasZ);
  			break;
  		case POLYLINE_Z:
  		case POLYLINE_M:
  		case POLYLINE:
  			newElement = createPolyline(createAttributeCollection(elementIndex), elementIndex, parts, points, hasZ);
  			break;
  		case MULTIPOINT:
  		case MULTIPOINT_M:
  		case MULTIPOINT_Z:
  			newElement = createMultiPoint(createAttributeCollection(elementIndex), elementIndex, points, hasZ);
  			break;
  			//$CASES-OMITTED$
  		default:
  		}
  
  		return newElement;
  	}