/*!\file PetscOptionsDetermineSolverType.cpp
 * \brief: 	Petsc comes with a wide array of solvers, some of them considered external (externally linked libraries). 
	To activate these solvers, Petsc uses the Options database, which is set at the command line prompt 
	when launching a Petsc executable (option -mat_type EXTERNALMATRIXTYPE). 
	
	We do not use this feature, because once the Cielo server is launched, we cannot go back and modify 
	the command line arguments. We rely therefore on the use of the options_string sent from the Solver_client 
	module to the server Solver/ module. On the server side, we receive this options_string and plug it into the 
	options database using the routine PetscOptionsInsertMultipleSTring. Once this is done, the KSP (Petsc solver) 
	object registers these options and selects the correct solution method.  

	Now, for external solvers, this does not work, because the choice of external solver needs to be done when launching
	the Petsc executable ( this way, every matrix created conforms to the external package, and the solver then 
	knows what to do directly by looking at the type of input matrix ). To circumvent this problem, we 
	still use the options_string sent by the Solver_client, and we look for the -mat_type option. If we find 
	a -mat_type option with an argument relating to an external solver, we then convert the solver matrix  
	to the external type, and the KSP object then knows what to do. 

	This routine parses the options_string and returns the type of external solver being used as an enum. If there is no 
	external solver used, we return a default enum.

	Note: figure out if first and second should be xfreed.
 */

#ifdef HAVE_CONFIG_H
	#include "config.h"
#else
#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
#endif

/*Petsc includes: */
#include "petscmat.h"
#include "petscvec.h"
#include "petscksp.h"

#include "./petscpatches.h"

#include "../../../shared/shared.h"

#undef __FUNCT__
#define __FUNCT__ "PetscOptionsDetermineSolverType"

void PetscOptionsDetermineSolverType(int* psolver_type,char* options_string){


	/*The list of options is going to be pairs of the type "-option option_value"*/
	PetscToken *token=NULL;
	char* first=NULL;
	char* second=NULL;
	size_t len;
	int ignore_second;
	int first_token=1;

	/*output: */
	int solver_type=PETSCPACKAGE;


	PetscTokenCreate(options_string,' ',&token);
	for (;;){
		

		/*Read next tokens*/
		if(first_token){
			PetscTokenFind(token,&first);
		}
		PetscTokenFind(token,&second);
		
		if (!first){
			/*We are at the end of options*/
			break;
		}
		if(!second){
			/*We have no second value, end the token analysis.*/
			if(first[0]!='-'){
				/*This is not good, the option does not have '-'! Get out*/
				throw ErrorException(__FUNCT__,exprintf("%s%s%s","Option ",first," should be preceded by '-'!"));
			}
			break;
		}
		else{
			/*Ok, we have a second token coming in. Is it another option, or 'first' option's value?*/
			if (second[0]=='-'){
				/*Second is another option, ignore it and prepare next loop step*/
				first=second;
				first_token=0;
			}
			else{
				/*Second is 'first' option's value*/
				PetscStrlen(second,&len);
				while (len > 0 && (second[len-1] == ' ' || second[len-1] == 'n')) {
					len--; second[len] = 0;
				}
				/*We now have a pair first and second. Check whether first is equal to -mat_type. If so, check 
				 * the second argument for the name of the external package desired.*/
				if (strcmp(first,"-mat_type")==0){
					if (strcmp(second,"aijmumps")==0){
						solver_type=MUMPSPACKAGE_LU;
					}
					if (strcmp(second,"sbaijmumps")==0){
						solver_type=MUMPSPACKAGE_CHOL;
					}
					if (strcmp(second,"aijspooles")==0){
						solver_type=SPOOLESPACKAGE_LU;
					}
					if (strcmp(second,"sbaijspooles")==0){
						solver_type=SPOOLESPACKAGE_CHOL;
					}
					if (strcmp(second,"superlu_dist")==0){
						solver_type=SUPERLUDISTPACKAGE;
					}
				}
				
				first_token=1;
			}
		}
	}

	PetscTokenDestroy(token);

	/*Assign output: */
	*psolver_type=solver_type;
}
