/*
 *	filterCommon.h - Helper routines for filter classes
 *	Copyright (C) 2018, D Haley 

 *	This program is 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, either version 3 of the License, or
 *	(at your option) any later version.

 *	This program 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/>.
*/

#ifndef FILTERCOMMON_H
#define FILTERCOMMON_H

#include "../filter.h"

#include "common/stringFuncs.h"
#include "common/basics.h"
#include "common/xmlHelper.h"

#include "backend/APT/APTRanges.h"

#include "config.h"


//TODO: Namespace this into the filter base class?

const size_t PROGRESS_REDUCE=5000;


//Create a "choice" string that is used ot populate drop-down combo boxes
// this is created from a vector of int-string pairs
std::string choiceString(std::vector<std::pair<unsigned int, std::string> > comboString, 
									unsigned int curChoice);



//serialise 3D std::vectors to specified output stream in XML format
void writeVectorsXML(std::ostream &f, const char *containerName,
		const std::vector<Point3D> &vectorParams, unsigned int depth);

//Serialise out "enabled" ions as XML. If the iput vectors are not of equal length,
// no data will be written
void writeIonsEnabledXML(std::ostream &f, const char *containerName, 
		const std::vector<bool> &enabledState, const std::vector<std::string> &names, 
			unsigned int depth);

//Read an enabled ions file as XML
void readIonsEnabledXML(xmlNodePtr nodePtr, vector<bool> &enabledStatus, vector<string> &names);

//serialise 3D scalars to specified output stream in XML format
// - depth is tab indentation depth
// - container name for : <container> (newline) <scalar .../><scalar ... /> </container>
template<class T>
void writeScalarsXML(std::ostream &f, const char *containerName,
		const std::vector<T> &scalarParams, unsigned int depth)
{
	f << tabs(depth) << "<"  << containerName << ">" << std::endl;
	for(unsigned int ui=0; ui<scalarParams.size(); ui++)
		f << tabs(depth+1) << "<scalar value=\"" << scalarParams[ui] << "\"/>" << std::endl; 
	
	f << tabs(depth) << "</" << containerName << ">" << std::endl;
}

//Nodeptr must be pointing at container node
template<class T>
bool readScalarsXML(xmlNodePtr nodePtr,std::vector<T> &scalarParams)
{
	std::string tmpStr;
	nodePtr=nodePtr->xmlChildrenNode;

	scalarParams.clear();
	while(!XMLHelpFwdToElem(nodePtr,"scalar"))
	{
		xmlChar *xmlString;
		T v;
		//Get value
		xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value");
		if(!xmlString)
			return false;
		tmpStr=(char *)xmlString;
		xmlFree(xmlString);

		//Check it is streamable
		if(stream_cast(v,tmpStr))
			return false;
		scalarParams.push_back(v);
	}
	return true;
}

//serialise 3D std::vectors to specified output stream in XML format
bool readVectorsXML(xmlNodePtr nodePtr,
	std::vector<Point3D> &vectorParams);


//Parse a "colour" node, extracting rgba data
bool parseXMLColour(xmlNodePtr &nodePtr, ColourRGBAf &rgbaf); 
		

//Returns the ion stream's range ID from the rangefile, if and only if it every ion in input
// is ranged tht way. Otherwise returns -1.
unsigned int getIonstreamIonID(const IonStreamData *d, const RangeFile *r);

//obtain the number of basic items in the input, given the stream type mask
size_t getTotalSizeByType(const std::vector<const FilterStreamData*> &dataIn, unsigned int streamTypeMask);

const RangeFile *getRangeFile(const std::vector<const FilterStreamData*> &dataIn);




//Draw a colour bar
DrawColourBarOverlay *makeColourBar(float minV, float maxV,size_t nColours,size_t colourMap, bool reverseMap=false, float alpha=1.0f) ;



//Input buffer should be bufXY[ui*2 + offset] (X-> offset=0, Y->offset=1)
// n - number of input points
// output is the vertices of the triangulation
unsigned int do2DDelaunay(double *bufXY, unsigned int n, 
		std::vector<size_t> &ta, std::vector<size_t> &tb, std::vector<size_t> &tc);




//Shared voxel property output for visualisation of voxel contents
// this is used by several filters
class VoxelAppearanceProperties
{
	private:
		Filter *parent;

		void getTexturedSlice(const Voxels<float> &v, 
			size_t axis,float offset, size_t interpolateMode,
			float &minV,float &maxV,DrawTexturedQuad &texQ) const;
	public:

		//Constructor, requires parent filter data
		explicit VoxelAppearanceProperties(Filter *p);


		//Interpolation mode to use when slicing	
		size_t sliceInterpolate;
		//Axis that is normal to the slice 0,1,2 => x,y,z
		size_t sliceAxis;
		//Fractional offset from lower bound of data cube [0,1]
		float sliceOffset;
		
		//Plane and normal for free slice. Note that the plane coordinate is in reduced voxel coords for each axis
		Point3D freeSlicePlane,freeSliceNormal; 

		ColourRGBAf rgba;

		//!3D Point Representation size
		float splatSize;

		//!Isosurface level
		float isoLevel;

		//!If using volume render mode, this is the transfer function to apply
		std::vector<std::pair<float, ColourRGBAf>  > transferFunction;

		//!Default output representation mode
		unsigned int representation;

		//!Whether to use a built-in or custom colour map
		bool builtinColourmap;

		//!Colour map to use when using axial slices
		unsigned int colourMap;

		//Number of colour levels for colour map
		size_t nColours;
		//Whether to show the colour map bar or not
		bool showColourBar;
		//Whether to use an automatic colour bound, or to use user spec
		bool autoColourMap;
		//Colour map start/end
		float colourMapBounds[2];

		//Do we want to show the bounding box?
		bool showBoundBox;
		
		//Colour for bounding box (if shown)
		ColourRGBAf boundColour;

		//Write a serialised representation of the properites
		void writeState(std::ostream &f, unsigned int format, unsigned int depth) const;

		unsigned int readState(xmlNodePtr &node);


		unsigned int refresh(Voxels<float> &v, vector<const FilterStreamData *> &getOut,
				std::vector<SelectionDevice *> &devices) const;
		

		void getProperties(FilterPropGroup &propertyList, size_t &curGroup,
				unsigned int keyOffset) const;

		bool setProperty(unsigned int keyOffset, unsigned int key, bool &handled,
					const string &value, bool &cacheOK, bool &needUpdate,
					vector<FilterStreamData *> &filterOutputs);

		//!Get the human-readable options for the visual representation (enum)
		static std::string getRepresentTypeString(int type);

		//Assignment to other voxel Appearnance
		void operator=(const VoxelAppearanceProperties &);
};



#ifdef DEBUG 

//Test functions
bool testCommon();

#endif

#endif
