/*
 * Copyright (C) 2007 JasperSoft http://www.jaspersoft.com
 * 
 * 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 WITHOUT ANY WARRANTY; and without 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/gpl.txt 
 * or write to:
 * 
 * Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330,
 * Boston, MA  USA  02111-1307
 */

/** 
 *  \file jsrun_params.c
 *  This sample shows how to run a report unit. In particular this sample shows how run a report unit and export it in
 *  pdf. This report unit has several input control. The sample shows how to get all the required information to render
 *  the input controls and pass the selected values to the function that will run the report.
 *  
 *  \see  jasperserver_ws_runReport, jasperserver_ws_get, jasperserver_ws_list
*/

#include <jasperserver.h>
#include <time.h>

const char server[] = "http://127.0.0.1:8080/jasperserver/services/repository";

#define MAX_INPUT_STRING 512




/** \brief Get an instance of jasperserver_server_t
*  This function instance a jasperserver_server_t struncture and fill it with some default used in the sample.
*  It is responsability of the user free the memory used by the allocated jasperserver_server_t;
*
*  \return A server instance.
*/
jasperserver_server_t *get_connection()
{
      jasperserver_server_t *jasperServer = NULL;
      // Create a new structure of type jasperserver_server_t to save the
      // server url and credentials.
      jasperServer = jasperserver_server_new();
      jasperserver_string_cset(jasperServer->url, server);
      jasperserver_string_cset(jasperServer->username, "tomcat");
      jasperserver_string_cset(jasperServer->password, "tomcat");
      
      return jasperServer;
}

/**
This method shows how to print a set of records coming from a query to populate a
query based input control...

\param inputcontrol The input control of type JS_IC_TYPE_SINGLE_SELECT_QUERY
\param datasourceUri The optional uri of a datasource against which execute the query on which the control is based.

*/
void print_query_result(jasperserver_resource_descriptor_t *inputcontrol, char *datasourceUri)
{
     jasperserver_server_t *server = NULL;
     jasperserver_request_t *request = NULL;
     jasperserver_argument_t *arg = NULL;
     jasperserver_resource_descriptor_t *data = NULL;
     jasperserver_resource_property_t *listOfRecords = NULL;
     jasperserver_resource_property_t *record = NULL;
     jasperserver_operation_result_t *result = NULL;
     
     jasperserver_resource_descriptor_t *siblingNode = NULL;
     
     
     request = jasperserver_request_new();
     
     // Temporarly remove sibilng node...
     siblingNode = inputcontrol->next;
     inputcontrol->next = NULL;
     
     arg = jasperserver_argument_new();
     jasperserver_string_cset(arg->name, JS_ARG_IC_GET_QUERY_DATA );
     if (datasourceUri != NULL)
     {
         jasperserver_string_cset(arg->value, datasourceUri );
     }
     
     jasperserver_list_append((jasperserver_list_t **)&request->arguments, (jasperserver_list_t *)arg);
     
     request->resource = inputcontrol;
     
     printf("\n");
     
     server = get_connection();
     
     result = jasperserver_ws_get(server, request, NULL);
     
     if (result && result->returnCode == 0)
     {
          data = result->resources;
          listOfRecords = jasperserver_get_property(data, JS_PROP_QUERY_DATA);
          
          for (record =listOfRecords->properties; record; record = record->next)
          {
              jasperserver_resource_property_t *column = NULL;
              printf("[%s]", JS_UTFSTR( record->value ));  
              // Print the rest of columns....
              for (column = record->properties; column; column = column->next)
              {
                  printf("\t%s", JS_UTFSTR( record->value ));  
              }
              printf("\n");  
          }
     }
     
     request->resource = NULL;
     inputcontrol->next = siblingNode; //reset the sibling node...
     jasperserver_request_free(request);
     jasperserver_operation_result_free(result);
     jasperserver_server_free(server);            
}

/**
This method shows how to get the type of data normally linked to an input control.

\param dataTypeResourceUri The URI of the datatype
\return the type of data

Possible values:
         
\li JS_DT_TYPE_TEXT  1
\li JS_DT_TYPE_NUMBER  2
\li JS_DT_TYPE_DATE  3
\li JS_DT_TYPE_DATE_TIME  4 

*/
int getDataType(const char *dataTypeResourceUri)
{
     int dataType = -1;
     jasperserver_server_t *server = NULL;
     jasperserver_request_t *request = NULL;
     jasperserver_resource_descriptor_t *res = NULL;
     jasperserver_operation_result_t *result = NULL;
     
     request = jasperserver_request_new();
     res = jasperserver_resource_descriptor_new();
     jasperserver_string_cset(res->uriString, dataTypeResourceUri);
     request->resource = res;
     
     server = get_connection();
     
     result = jasperserver_ws_get(server, request, NULL);
     
     if (result && result->returnCode == 0)
     {
          jasperserver_resource_descriptor_t *data = NULL;
          
          data = result->resources;
          if (data)
          {
             dataType = atoi( JS_CSTR( jasperserver_get_property_value(data, JS_PROP_DATATYPE_TYPE) ) );
          }
     }
     
     jasperserver_request_free(request);
     jasperserver_operation_result_free(result);
     jasperserver_server_free(server);            
     
     return dataType;
}

/** \brief This method shows how to render and get the value for an input control.

The sample is not exaustive, not all the kind of input control are shown here, and there is not input validation.

\param inputcontrol The inputcontrol resource.
\param dsUri An optional datasource uri to execute a query in case of query based input control. This uri is
passed here because normally it comes from the report unit (as child resource). 
\return a new instance of a parameter. It is user responsability of the user free the memory for this object.
Anyway, this parameter will be probably added to a resource prepared to execute the runReport service. In that
case, the parameter will be freed by the function jasperserver_request_free();

*/
jasperserver_parameter_t *acquire_value_for_input_control( jasperserver_resource_descriptor_t *inputcontrol, char *dsUri )
{
      jasperserver_string_t *icType = NULL;
      jasperserver_parameter_t *parameter = NULL;
      int icTypeID = -1;
      
      
      
      // Look for the type of inputcontrol....
      icType = jasperserver_get_property_value(inputcontrol, JS_PROP_INPUTCONTROL_TYPE);
      if (icType == NULL) return NULL;
      
      parameter =  jasperserver_parameter_new();
      jasperserver_string_set( parameter->name, JS_UTFSTR(inputcontrol->name));
      
      icTypeID = atoi( JS_CSTR(icType) );
      
      printf("--------------------------------------:\n%s (%s)\n", JS_UTFSTR( inputcontrol->label), JS_UTFSTR( inputcontrol->name) );
      
      // Rendering of the control. You can write your own functions to do that.
      switch (icTypeID)
      {
         case JS_IC_TYPE_BOOLEAN:
         {
             char test[MAX_INPUT_STRING] = "";
             printf("Value [Y/N]: ");
             fgets(test, MAX_INPUT_STRING, stdin);
             jasperserver_string_cset( parameter->value, (strcmp(test, "Y") == 0) ? "true" : "false" );
             return parameter;
         }
         case JS_IC_TYPE_SINGLE_VALUE:
         {
             char test[MAX_INPUT_STRING] = "";
             jasperserver_resource_descriptor_t *resDataType = NULL;
             jasperserver_resource_property_t *prop = NULL;
             int intDataType = JS_DT_TYPE_TEXT; // Set a default...
             // Check what type of data type...
             resDataType = inputcontrol->children;
             prop = jasperserver_get_property(resDataType, JS_PROP_REFERENCE_URI);
             if (prop)
             {
                // the type is linked to another resource...
                intDataType = getDataType( JS_CSTR(prop->value)  );
             }
             else
             {
                 intDataType = atoi( JS_CSTR(jasperserver_get_property(resDataType, JS_PROP_DATATYPE_TYPE )->value) );
             }
             
             switch (intDataType)
             {
                    case JS_DT_TYPE_TEXT:
                        printf("Value (String): ");
                        fgets(test, MAX_INPUT_STRING, stdin);
                        jasperserver_string_cset( parameter->value, test );
                        break;
                    case JS_DT_TYPE_NUMBER:
                        printf("Value (number): ");
                        fgets(test, MAX_INPUT_STRING, stdin);
                        jasperserver_string_cset( parameter->value, test );
                        break;
                    case JS_DT_TYPE_DATE:
                    {
                        // A date must be represented as a number holding the number of MILLISECONDS from Jan 1, 1970.
                        // (java standard).
                        
                        int year = 0;
                        int month = 0;
                        int day = 0;
                        struct tm time_struct;
                        time_t ttime = 0;
                        
                        printf("Value (date in the format mm-dd-yyyy): ");
                        fgets(test, MAX_INPUT_STRING, stdin);
                        sscanf(test, "%d-%d-%d", &month, &day, &year);
                        time_struct.tm_year=year-1900;
                        time_struct.tm_mon=month-1;
                        time_struct.tm_mday=day;
                        time_struct.tm_sec=0;
                        time_struct.tm_min=0;
                        time_struct.tm_hour=0;
                        time_struct.tm_isdst=-1;

                        ttime = mktime(&time_struct);
                        if (ttime != -1) 
                        {
                         printf("Date: %d-%d-%d\n",month,day,year);                            
                        }
                        else
                        {
                            printf("Date not valid, using current time.\n");
                            ttime = time(NULL);
                        }
                        jasperserver_string_format( parameter->value, "%ld000", ttime ); 
                        fflush(stdout);
                        break;
                    }
             }
             
             return parameter;
         }
         case JS_IC_TYPE_SINGLE_SELECT_LIST_OF_VALUES:
         {
             char test[MAX_INPUT_STRING] = "";
             
             // get the list of values (it *SHOULD* be the first child...)
             jasperserver_resource_descriptor_t *lov = NULL;
             jasperserver_resource_property_t *lovList = NULL;
             jasperserver_resource_property_t *lovItem = NULL;
             
             lov = inputcontrol->children;
             
             lovList = jasperserver_get_property( lov, JS_PROP_LOV  );
             printf("\n");
             
             // show all the items...
             for ( lovItem = lovList->properties; lovItem; lovItem = lovItem->next)
   	         {
   	     	  printf("[%s] %s\n", JS_UTFSTR( lovItem->name), JS_UTFSTR( lovItem->value) );
             }
             
             printf("\nSelect a value from the list: ");
             
             fgets(test, MAX_INPUT_STRING, stdin);
             jasperserver_string_cset( parameter->value, test );
             return parameter;
         }
         case JS_IC_TYPE_SINGLE_SELECT_QUERY:
         {
               char test[MAX_INPUT_STRING] = "";
              
               print_query_result( inputcontrol,dsUri);
               printf("\nSelect a value from the list: ");
             
               fgets(test, MAX_INPUT_STRING, stdin);
               jasperserver_string_cset( parameter->value, test );
               
               return parameter;
         }
         default:
         {
             printf("Unhandled input control type (type %d)...\n", icTypeID );
         }      
      }
      
      // No parameter to supply...
      jasperserver_parameter_free( parameter );
      return NULL;
}


int main(int argc, char **argv)
{ 
   jasperserver_server_t *jasperServer = NULL;
    
   // Uri of a sample with a lot of input controls... 
   char *reportUnitUri = "/reports/samples/SalesByMonth";
   
   // File to store the final result...
   char *outfile = "test.pdf";
   
   char *datasourceUri = NULL;
   jasperserver_request_t *request = NULL;
   jasperserver_argument_t *argPdfExport = NULL;
   jasperserver_resource_descriptor_t *report = NULL;
   jasperserver_resource_descriptor_t *inputcontrol = NULL;
   jasperserver_resource_descriptor_t *resource = NULL;
   jasperserver_operation_result_t *operationResult = NULL;
   
     
   // Fill the structure to connect to the server 
   jasperServer = get_connection();
   
   // Create the request to get informations about the report...
   request = jasperserver_request_new();   
   
   // Create the resource to get...
   report = jasperserver_resource_descriptor_new();
   jasperserver_string_cset(report->uriString, reportUnitUri);
   
   // Add the resource to the request
   request->resource = report;
   
   // Get the whole report resource...
   operationResult = jasperserver_ws_get( jasperServer, request, NULL);
   
   if (!operationResult || operationResult->returnCode != 0)
   {
       printf("Error getting report information\n");
       exit(0);
   }
   
   jasperserver_resource_descriptor_free(report);
   report = NULL;
   
   if (!operationResult->resources)
   {
       printf("Resource not found on this server!\n");
       exit(0);                          
   }
   
   report = operationResult->resources;
   
   // Void and free this operations result.
   operationResult->resources = NULL; // This avoids to free the memory used for the resource...
   jasperserver_operation_result_free(operationResult);
   operationResult = NULL;
   
   // Void and free this request
   request->resource = NULL; // This avoids to free the memory used for the resource...
   jasperserver_request_free(request);
   
   
   // Find the datasource uri (used only for query based input control that does not have
   // a defined datasource to use...
   for ( resource = report->children; resource; resource = resource->next)
   {
       if ( !strcmp( JS_UTFSTR(resource->wsType), JS_TYPE_DATASOURCE) )
       {
            jasperserver_resource_property_t *prop = NULL;
            prop = jasperserver_get_property(resource, JS_PROP_REFERENCE_URI );
            if (prop && JS_NOTNULL(prop->value) )
            {
             datasourceUri = (char *)JS_CSTR( prop->value);             
             break;
            }
       }
       else if (!strcmp( JS_UTFSTR(resource->wsType), JS_TYPE_DATASOURCE_JDBC) ||
                !strcmp( JS_UTFSTR(resource->wsType), JS_TYPE_DATASOURCE_JNDI) ||
                !strcmp( JS_UTFSTR(resource->wsType), JS_TYPE_DATASOURCE_BEAN))
       {
                datasourceUri = (char *)JS_CSTR(resource->uriString);    
                break;
       }
   }   
   
   printf("Report datasource URI %s\n", datasourceUri);
   fflush(stdout);
   
   // Now we need to present to the user the input controls....
   // and fill the request for the report execution...
   
   for ( inputcontrol = report->children; inputcontrol; inputcontrol = inputcontrol->next)
   {
         if ( !strcmp( JS_UTFSTR(inputcontrol->wsType), JS_TYPE_INPUT_CONTROL) )
         {
              jasperserver_parameter_t *parameter = NULL;
              // Inputcontrol found!
              // Show the input control and get the parameter...                                             
              parameter = acquire_value_for_input_control( inputcontrol, datasourceUri );
              if (parameter != NULL)
              {
                 parameter->next = NULL;
                 jasperserver_list_append((jasperserver_list_t **)&report->parameters, (jasperserver_list_t *)parameter);
              }
         }
   }
   
   printf("--------------------------------------\n");
   
   // We have collected all the information to execute the report...              
   // Create a new structure of type jasperserver_request_t to store
   // the request information like the resource to list    
   request = jasperserver_request_new();   
     
   // Set PDF as export format...
   argPdfExport = jasperserver_argument_new();
   jasperserver_string_cset(argPdfExport->name, JS_ARG_RUN_OUTPUT_FORMAT);
   jasperserver_string_cset(argPdfExport->value, JS_ARG_RUN_OUTPUT_FORMAT_PDF);

   request->resource = report;
   jasperserver_list_append((jasperserver_list_t **)&request->arguments, (jasperserver_list_t *)argPdfExport);

   // Call the web service
   operationResult = jasperserver_ws_runReport(jasperServer, request, outfile);
      
   if (operationResult && operationResult->returnCode != 0)
   {
       printf("Error filling the report: %d (%s)", operationResult->returnCode, JS_UTFSTR(operationResult->returnMessage) );
   }
   else
   {
       printf("test.pdf succesfully created.\n\n");
   }
                
   // Free the unused resources                      
   jasperserver_server_free( jasperServer );
   jasperserver_request_free( request );
   jasperserver_operation_result_free( operationResult );
   
   return 0;
}
