#include <iostream>
#include <string>
#include <vector>


#ifndef WANT_NAMESPACES
#define WANT_NAMESPACES
#endif

#include "glite/wmsutils/exception/Exception.h"
#include "glite/wms/jdl/JobAd.h"
#include "glite/wmsui/api/Job.h"
#include "glite/wms/jdl/JDLAttributes.h"

using namespace std;
using namespace glite::wmsui::api;
using namespace glite::wms::jdl;
using namespace glite::wmsutils::exception;

/*
 * fibonacciJob2.cpp created 11:46 on 26th August 2005 author Sara Collins
 * based on edg tutorial program workload.cpp
 *
 * Program to create a job specification and submit the job after first
 * finding the CE which closest match the job description.
 *
 * TUTORIAL: use classes detailed in
 * http://egee-jra1-wm.mi.infn.it/egee-jra1-wm/glite-wms-api-index.shtml
 * An example api can be found at,
 * http://egee-jra1-wm.mi.infn.it/egee-jra1-wm/ui_cpp_api_usage.shtml
 * Hints are given at each stage.
 */


int main (int argc,char *argv[])
{
  //check the correct number of arguments are passed.
  if (argc < 2 || strcmp(argv[1],"--help") == 0) {
    cerr << "Usage : " << argv[0]
	 << " <glite resource broker>"
	 << endl;
    return 1;
  }
	
  /* Declare the values of the attributes for the job. */

  /* The name of the WMS */
  const string HOST = argv[1];
  /* Port number of the WMS */
  const int WM_PORT = 7772;
  /* Port number of the logging and bookkeeping service */
  const int LB_PORT = 9000;
  const string EXECUTABLE = "fibonacci";
  /* Arguments to the exectuable which include order and number
   * for fibonacci sequence.
   */
  const string ARGUMENTS = " 1 15 fib.out";
  /* The file which will contain the standard output from the job */
  const string STDOUTPUT = "std.out";
  /* The file which will contain the standard error from the job */
  const string STDERROR	= "std.err";
  /* The output file from the job */
  const string OUTPUTFILE = "fib.out";
  /* The broker info file */
  const string BROKERINFO = ".BrokerInfo";
	
  try{
    /* declare the JobAd object */
    JobAd jad;
	
    /* Add the Executable to the JobAd 
     * HINT: use the attributes listed in
     * $(GLITE_LOCATION)/include/glite/wms/jdl/JDLAttributes.h
     * and JobAd method setAttribute().
     */
    jad.setAttribute(JDL::EXECUTABLE,EXECUTABLE);
		
    /* Add the Arguments to the JobAd */
    jad.setAttribute(JDL::ARGUMENTS,ARGUMENTS);
		
    /* Add the InputSandbox  to the JobAd */
    jad.setAttribute(JDL::INPUTSB,"./"+EXECUTABLE);
		
    /* Add the Stdandard Output  to the JobAd */
    jad.setAttribute(JDL::STDOUTPUT,STDOUTPUT);

    /* Add the Stdandard Error  to the JobAd */
    jad.setAttribute(JDL::STDERROR,STDERROR);
	
    /* Add the Rank  to the JobAd 
     * HINT: use setAttributeExpr() method of JobAd
     */
    jad.setAttributeExpr(JDL::RANK,"other.GlueCEStateWaitingJobs == 0 ? other.GlueCEStateFreeCPUs : -other. GlueCEStateWaitingJobs");
	
    /* Add the requirements  to the JobAd 
     * HINT: as for Rank
     */ 
    jad.setAttributeExpr(JDL::REQUIREMENTS,
			 "other.GlueCEStateStatus == \"Production\"");
	
    /* Add the Virtual Organization  to the JobAd */
    jad.setAttribute(JDL::VIRTUAL_ORGANISATION,(string) "gilda");
	
    /* Add the Output Sandbox  to the JobAd 
     * HINT: use setAttribute for the first entry and addAttribute
     * for subsequent entries.
     */
    jad.setAttribute(JDL::OUTPUTSB,STDOUTPUT);
    jad.addAttribute(JDL::OUTPUTSB,OUTPUTFILE);
    jad.addAttribute(JDL::OUTPUTSB,STDERROR);
    jad.addAttribute(JDL::OUTPUTSB,BROKERINFO);
	
    /* Check the syntax and the semantic of the jdl
     * HINT: use method of JobAd.
     */;  
    jad.check();

    cout << "*** Final JDL" << endl;
    cout << "*** This is the string rapresentation:\n" << jad.toString() << endl;

    /* Create a job object from the job description.
     * HINT: use Job.
     */
    glite::wmsui::api::Job job(jad);

    /* Set the logging level for the job.
     * HINT: use method of Job.
     */
    job.setLoggerLevel(6);

    /* Generate list of all the resources and their rank which match
     * the job description.  
     * HINT: use job method
     */
    vector<pair<string,double> >  matching = job.listMatchingCE (HOST,WM_PORT);

    cout << "This is the the matchmaking with the ranking" << endl; 
       
    /* Check some resources have been found, otherwise exit
     * HINT: use vector method 
     */
    if(matching.size() == 0){
      cout << "No suitable resources found" <<endl;
      return 0;
    }

    /* For each resource in list, output name and rank
     * HINT: use vector methods and pair attributes.
     */
    for ( vector<pair<string,double> >::iterator it = matching.begin(); 
          it != matching.end(); ++it ) {
      cout << "Resource= "<< it->first << "  Rank = " 
	   << it->second << endl;
    } 

    cout << "Submitting to first CE from list" << endl;

    /* Submit the job to the first CE from the list
     * HINT: use method of job.
     */
    job.submit(HOST,WM_PORT,HOST,LB_PORT,matching[0].first);
	
    /* Output the jobID number.
     * HINT: use Job method.
     */
    cout << "Job Submission OK; JobID= "  
	 << job.getJobId()->toString()  << endl << flush ;
    
    return 0;
		       
  } 
  //catch necessary exceptions
  catch (glite::wmsutils::exception::Exception &exc) {
    cerr << exc.printStackTrace();
    return 1;
  }	
}