#include "io_3dcoform.h"

#include<QFileInfo>
#include<QUuid>
#include <QtXml/QDomDocument>
#include <QString>

#include <wrap/io_trimesh/import_ply.h>
#include <wrap/io_trimesh/export_ply.h>
#include "../../common/mlapplication.h"

bool CoformIOPlugin::open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask, const RichParameterSet &par, vcg::CallBackPos *cb, QWidget *parent)
{
	// initializing mask
	mask = 0;
	// initializing progress bar status
	if (cb != NULL)		(*cb)(0, "Loading...");

	QString errorMsgFormat = "Error encountered while loading file:\n\"%1\"\n\nError details: %2";

	if (formatName.toUpper() == tr("UUID"))
	{
		QFileInfo filenminfo(fileName);
		QString plyfile = filenminfo.completeBaseName();
		QFileInfo plyinfo(plyfile);
		if (!plyfile.toLower().contains(QString("ply")) || !plyinfo.exists())
		{
			errorMsgFormat.arg(fileName, QString("A valid UUID file name MUST have the format: name.ply.uuid\n(being name.ply the releated PLY file contained in the same folder along with the UUID file)"));
			return false;
		}
		
		QFile file(fileName);
		if (!file.open(QIODevice::ReadOnly))
		{
			errorMsgFormat.arg(fileName, QString("It was not possible to open requested file"));
			return false;
		}

		QByteArray uuidbyte = file.readAll();
		QString coformuuid(uuidbyte);
		CMeshO::PerMeshAttributeHandle<QString> uuidhandle =vcg::tri::Allocator<CMeshO>::AddPerMeshAttribute<QString>(m.cm,uuidPerMeshAttributeName().toStdString());
		if (!vcg::tri::Allocator<CMeshO>::IsValidHandle<QString>(m.cm,uuidhandle))
		{
			errorMsgFormat.arg(fileName, QString("It was not possible to add a per mesh attribute containing the Repository Infrastructure's 3D model uuid"));
			return false;
		}
		uuidhandle() = coformuuid;
		vcg::tri::io::ImporterPLY<CMeshO>::LoadMask(qPrintable(plyfile), mask); 
		// small patch to allow the loading of per wedge color into faces.  
		if(mask & vcg::tri::io::Mask::IOM_WEDGCOLOR) mask |= vcg::tri::io::Mask::IOM_FACECOLOR;
		m.Enable(mask);


		int result = vcg::tri::io::ImporterPLY<CMeshO>::Open(m.cm, qPrintable(plyfile), mask, cb);
		if (result != 0) // all the importers return 0 on success
		{
			if(vcg::tri::io::ImporterPLY<CMeshO>::ErrorCritical(result) )
			{
				errorMessage = errorMsgFormat.arg(fileName, vcg::tri::io::ImporterPLY<CMeshO>::ErrorMsg(result));
				return false;
			}
		}
		 
	}
	else 
	{
		assert(0); // Unknown File type
		return false;
	}

	if (cb != NULL)	(*cb)(99, "Done");
	return true;
}

bool CoformIOPlugin::save(const QString &formatName, const QString &fileName, MeshModel &m, const int mask, const RichParameterSet & par, vcg::CallBackPos *cb, QWidget *parent)
{
	QString errorMsgFormat = "Error encountered while exportering file %1:\n%2";
	bool binaryFlag = false;
	if(formatName.toUpper() == tr("RDF"))
	{
		MetaDataFileGenerator::Person pers(par.getString(coformRIUserUUIDParam()),par.getString(coformRIUserNameParam()),par.getString(coformRIUserSurNameParam()));
		QString comment("RDF file generated by the MeshLab 3D-COFORM Plugin.");
		QList<MetaDataFileGenerator::MeshInfo> mi_input;
		MetaDataFileGenerator::MeshInfo out;
		genMeshInfo(m,true,&out);
		QString	 hist;
		if (m.parent !=NULL)
		{
			foreach(MeshModel* mm,m.parent->meshList)
			{
				MetaDataFileGenerator::MeshInfo mi;
				genMeshInfo(*mm,false,&mi);
				mi_input.push_back(mi);
			}
			hist = m.parent->filterHistory.xmlDoc().toString();
		}
		MetaDataFileGenerator::Process mlprocess(comment,QUuid::createUuid().toString(),mi_input,out,MeshLabApplication::appVer(),hist);
		QString rdftext = MetaDataFileGenerator::generateRDF(mlprocess,pers);
		QFile rdffile(fileName);
		if (!rdffile.open(QIODevice::WriteOnly | QIODevice::Text))
			return false;

		QTextStream rdfout(&rdffile);
		rdfout << rdftext;
		rdffile.close();
		binaryFlag = par.findParameter("Binary")->val->getBool();
		QFileInfo plyfile(fileName);
		int result = vcg::tri::io::ExporterPLY<CMeshO>::Save(m.cm,qPrintable(plyfile.baseName() + ".ply"),mask,binaryFlag,cb);
		if(result!=0)
		{
			errorMessage = errorMsgFormat.arg(fileName, vcg::tri::io::ExporterPLY<CMeshO>::ErrorMsg(result));
			return false;
		}
		return true;
	}
	return false;
}

void CoformIOPlugin::initSaveParameter(const QString &format, MeshModel &/*m*/, RichParameterSet &par) 
{
	if(format.toUpper() == tr("RDF"))
	{
		par.addParam(new RichBool("Binary",true, "Binary encoding",
		"Save the mesh using a binary encoding. If false the mesh is saved in a plain, readable ascii format"));	
		par.addParam(new RichString(coformRIUserNameParam(),"","3D-COFORM RI User Name","User name (e.g. Guido)"));
		par.addParam(new RichString(coformRIUserSurNameParam(),"","3D-COFORM RI User Surname","User surname (e.g. Ranzuglia)"));
		QUuid uuidnull;
		QString uuidst = uuidnull.toString().remove(QRegExp("(\\{|\\})"));
		par.addParam(new RichString(coformRIUserUUIDParam(),uuidst,"3D-COFORM RI User UUID",QString("UUID related to the person inserted in the user name/surname fields")));
	}
}

/*
	returns the list of the file's type which can be imported
*/
QList<MeshIOInterface::Format> CoformIOPlugin::importFormats() const
{
	QList<Format> formatList;
	formatList << Format("Repository Infrastructure UUID File",tr("UUID"));
	return formatList;
}

/*
	returns the list of the file's type which can be exported
*/
QList<MeshIOInterface::Format> CoformIOPlugin::exportFormats() const
{
	QList<Format> formatList;
	formatList << Format("MeshLab Resource Description Format",tr("RDF"));
	return formatList;
}

void CoformIOPlugin::GetExportMaskCapability( QString &format, int &capability, int &defaultBits ) const
{
	//the 3d file referred as the process output file inside the rdf file is saved as a ply file
	if(format.toUpper() == tr("RDF"))
	{
		capability = vcg::tri::io::ExporterPLY<CMeshO>::GetExportMaskCapability();
		defaultBits=capability;
		defaultBits &= (~vcg::tri::io::Mask::IOM_FLAGS);
		defaultBits &= (~vcg::tri::io::Mask::IOM_VERTNORMAL);
	}
}

CoformIOPlugin::CoformIOPlugin()
:MeshIOInterface()
{
}

CoformIOPlugin::~CoformIOPlugin()
{
}

//void CoformIOPlugin::initGlobalParameterSet( QAction * format, RichParameterSet & globalparam)
//{
//	if (format->text().contains(tr("RDF")))
//	{
//		globalparam.addParam(new RichString(coformRIUserNameParam(),"","3D-COFORM RI User Name","User name (e.g. Guido)"));
//		globalparam.addParam(new RichString(coformRIUserSurNameParam(),"","3D-COFORM RI User Surname","User surname (e.g. Ranzuglia)"));
//		QUuid uuidnull;
//		QString uuidst = uuidnull.toString().remove(QRegExp("(\\{|\\})"));
//		globalparam.addParam(new RichString(coformRIUserUUIDParam(),uuidst,"3D-COFORM RI User UUID",QString("UUID related to the person inserted in the user name/surname fields")));
//	}
//}

void CoformIOPlugin::genMeshInfo(MeshModel& m,const bool isoutputfile,MetaDataFileGenerator::MeshInfo* minfo )
{
	if (minfo != NULL)
	{
		minfo->megabyte = sizeof(m);
		QFileInfo fileinfo(m.label());
		
		QString lab = m.label();
		if (fileinfo.suffix() == ".uuid")
			lab.remove("uuid");
		minfo->label =	lab;
		minfo->nfc = m.cm.FN();
		minfo->nvt = m.cm.VN();
		CMeshO::PerMeshAttributeHandle<QString> hand = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<QString>(m.cm,uuidPerMeshAttributeName().toStdString());
		if (isoutputfile)
			minfo->uuid	= QUuid::createUuid().toString();
		else
			if (vcg::tri::Allocator<CMeshO>::IsValidHandle<QString>(m.cm,hand))
				minfo->uuid = hand();
			else
				minfo->uuid = QUuid().toString();
	}	
}
Q_EXPORT_PLUGIN(CoformIOPlugin)