/* ImLib3D
 * Copyright (c) 2001, ULP-IPB Strasbourg.
 *
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*! \file ImageProcessorDescription.hpp */
#ifndef _ImageProcessorDescription_hpp
#define _ImageProcessorDescription_hpp

#include<ImLib3D/ImageProcessorsDescription.hpp>

//! A description of an argument to an image processor, this is simply an interface to the XML description
/*! this the base class */
class ImProcStringArgument : public XIPD::Argument
{
protected:
	//! full description of all improcs, argument types etc
	ImageProcessorsDescription &improcs;
	//! description of this argument's type 	
	XIPD::ArgumentType *typeDesc;
//	bool ignoreOutput;
public:
	string Name(){return name;}
	string Type(){return type;}
	XIPD::ArgumentType *TypeDescritption(){return typeDesc;}
	bool IsInput(){return direction!="output";}
	bool IsOptional(){return isOptional=="true";}
	string OptType(){return optType;}
	string Default(){return defaultValue;}
	string FullSwitch()
	{
		string res="--";
		for(uint i=0;i<name.size();i++)
		{
			res+=isspace(name[i]) ? '-' : tolower(name[i]);
		}
		return res;
	}
	//! returns the string that will be used when calling the image processor
	/*! this method is respoinsible for validating the argument. */
	virtual bool IsValid(const string &strArg,string &message)
	{
		return true;//unkown arg types are ok by default
	}
	
	virtual ~ImProcStringArgument(){;}
	//! factory for one argument from XIPD::Argument
	static ImProcStringArgument *Create(XIPD::Argument &argument,ImageProcessorsDescription &improcs);
	ImProcStringArgument(XIPD::Argument &parent,ImageProcessorsDescription &_improcs):
		XIPD::Argument(parent),improcs(_improcs)
	{
		typeDesc=improcs.GetArgumentType(Type(),false);
	}
};

//! An image processor argument, that is an image
class ImageArgument  : public ImProcStringArgument
{
public:
	virtual bool IsValid(const string &strArg,string &message);
	//! process results 
	ImageArgument(XIPD::Argument &parent,ImageProcessorsDescription &_improcs):
		ImProcStringArgument(parent,_improcs)
	{}
};

//! An image processor argument, that is a string chosen from a list
class ListArgument  : public ImProcStringArgument
{
	virtual bool IsValid(const string &strArg,string &message)
	{
		if(find(Items().begin(),Items().end(),strArg)==Items().end())
		{
			message="invalid argument for "+name+":\""+strArg+"\"";
			return false;
		}
		return true;
	}
public:
	const vector<string> &Items(){return typeDesc->listItems;}
	ListArgument(XIPD::Argument &parent,ImageProcessorsDescription &_improcs):
		ImProcStringArgument(parent,_improcs)
	{
		if(!typeDesc){ThrowError("ListArgument::ListArgument no typeDesc");}
	}
};


//! A list of all arguments to a given image processor
/*! This is meant to be used only for calling image processors's with string arguments */
class ImageProcessorDescription : public XIPD::ImageProcessor
{
public:
	//! each of this processors  arguments
	vector<ImProcStringArgument *> args;
	//! description of all image processors
	ImageProcessorsDescription &improcs;
public:
	//! nb of arguments
	uint size(){return args.size();}
	//! accesor to arguments
	ImProcStringArgument *operator[](int i){return args[i];}
	int IndexOf(ImProcStringArgument *arg)
	{
		vector<ImProcStringArgument *>::iterator p=find(args.begin(),args.end(),arg);
		if(p==args.end()){return -1;}
		else{return p-args.begin();}
	}

	uint FindFullSwitch(string fs)
	{
  		for(uint i=0;i<args.size();i++)
  		{
			if(args[i]->FullSwitch()==fs){return i;}
		}		
		ThrowError("ImageProcessorDescription::FindFullSwitch no match for switch \"%s\"",fs);
		return 0;
	}

	//! prints full description of an image processor to std output
	void PrintHelp();

	//! creates output in a format needed for inserting auto class doc in source file
	void PrintDoxyDoc(const string& type="class head");

	//! builds final list of string arguments, for calling on command line
	vector<string> BuildCmdLine(const vector<string> &args0,bool stripTrailingSpaces=true);
	vector<string> ParseCmdLine(vector<string> cmdline);
	void  ValidateArguments(const vector<string> &resArgs);
	int ProcTemplateTypeNamePos();
	string ProcTemplateTypeName(vector<string> resArgs);

	//! builds a description of all arguments
	ImageProcessorDescription(const string &_name,ImageProcessorsDescription &_improcs):
		XIPD::ImageProcessor(*_improcs.GetImageProcessor(_name)),
		improcs(_improcs)
	{
		//  create arguments
		for(uint i=0;i<arguments.size();i++)
		{
			args.push_back(ImProcStringArgument::Create(arguments[i],improcs));
  		}
	}
};

#endif // _ImageProcessorDescription_hpp
