// PlaceArchivesProc.cpp
  
#include <ri.h>
//#include <RixInterfaces.h>
//#include <RiTypesHelper.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include "getFiles.h"
  
// A RiProcedural must implement these functions. This is a fixed requirement.
extern "C"
{
    PRMANEXPORT RtPointer ConvertParameters ( RtString paramStr              );
    PRMANEXPORT RtVoid    Subdivide         ( RtPointer data, RtFloat detail );
    PRMANEXPORT RtVoid    Free              ( RtPointer data                 );
}
  
// A custom data structure for defining an arbitrary number of spheres
// positioned at locations defined by the "coords" array.
typedef struct {
    std::vector <std::string> archivePaths; // a list of paths of the archives 
    RtFloat scale;
    RtFloat *coords;        // effectively an array of x,y,z coordinates
    RtInt    num_coords;
    } ArchivesData;
    
// Declare our utility function
RtFloat randBetween(RtFloat min, RtFloat max);
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
//
RtPointer ConvertParameters(RtString paramStr) {
    long len = strlen(paramStr);
  
    // However, because the paramStr can be very large we allocate memory
    // from the main memory pool (the "heap") and then perform a block 
    // copy of the contents of paramStr.
    char *copyStr = (char*)calloc(len + 1, sizeof(char));
    memcpy(copyStr, paramStr, len + 1);
    
    // Allocate a block of memory to store one instance of ArchivesData.
    ArchivesData *dataPtr = (ArchivesData*)calloc(1, sizeof(ArchivesData));
    
    // Irrespective of how many values are specified by the paramStr we
    // know the first 3 values will specify the:
    //    1     full path to the directory containing rib archives,
    //    2     scaling factor to be applied to the archives, and
    //    3     number of coordinates that define the locations of
    //        the rib archives that will be selected randomly.
    char temp[512];
    sscanf(copyStr, "%s %f %d", temp, &dataPtr->scale, &dataPtr->num_coords);
    //printf("ribs path \"%s\"\n", temp);
    
    std::string ribsDirPath(temp);                     // convert to a C++ style string
    dataPtr->archivePaths = getFiles(ribsDirPath);
    
    // Allocate memory to store an array of coordinates
    RtInt num_floats = dataPtr->num_coords;
    dataPtr->coords = (RtFloat*)calloc(num_floats, sizeof(RtFloat));
    
    char *strPtr = strtok(copyStr, " ");
    strPtr = strtok(NULL, " "); // eat the path to the ribs directory
    strPtr = strtok(NULL, " "); // eat the scale value
    strPtr = strtok(NULL, " "); // eat the num coordinates value
    long count = 0;
    while(strPtr) {
        // Convert each string to a double precision floating point number
        dataPtr->coords[count] = strtod(strPtr, NULL);
        count++;
        strPtr = strtok(NULL, " "); // grab the next part of copyStr.
        }
    // Don't forget to free the memory that was allocated for the copied text.
    free(copyStr);
    return (RtPointer)dataPtr;
}
  
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
RtVoid Subdivide(RtPointer dataPtr, RtFloat detail) {
    RtFloat scale = ((ArchivesData*)dataPtr)->scale;
    RtInt     num_coords = ((ArchivesData*)dataPtr)->num_coords;
    RtFloat *coords =  ((ArchivesData*)dataPtr)->coords;
    std::vector <std::string> paths = ((ArchivesData*)dataPtr)->archivePaths;
    
    if(paths.size() < 1) {
        //printf("Error: no ribs");
        return;
        }
    for(int n = 0; n < num_coords; n = n + 3) {
        RtFloat x = coords[n];
        RtFloat y = coords[n + 1];
        RtFloat z = coords[n + 2];
        RiTransformBegin();
            RiTranslate(x, y, z);
            RiScale(scale, scale, scale);
            
            // Use the nifty function from C++ to randomly select a rib archive    
            std::random_shuffle( paths.begin(), paths.end() );
            //printf("%s\n", paths[0].c_str());
            RiReadArchiveV(paths[0].c_str(), NULL, 0, NULL, NULL );
        RiTransformEnd();
        }
    }
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
RtVoid Free(RtPointer data) {
    free(((ArchivesData*)data)->coords);
    free(data);
    }
    
// ----------------------------------------------------
// Our utility functions begin here 
// ----------------------------------------------------
RtFloat randBetween(RtFloat min, RtFloat max) {
    return ((RtFloat)rand()/RAND_MAX) * (max - min) + min;
    }