#include <iostream>
#include <sstream>
#include <fcntl.h> 

#include "glite/data/io/client/ioclient-posix.h"

using namespace std;

/* Method to write to a file */
void write_to_file(int fh, const char *output){

  size_t size = strlen(output);
  int rc;
  if ((rc = glite_posix_write (fh, output, size )) != size) {
    if (rc < 0)   perror ("glite_posix_write");
    else  cerr << "The number of written bytes was less than expected!: " 
	       << rc << endl;
    glite_posix_close (fh);  
    exit (1);
  }
  cout << " ... Write successful ... " << endl;
}

/* Method to convert a double to a string */
string doubleToStr(double d){
  stringstream t;
  t << d;
  return t.str();
}

/* Method to convert an integer to a string */
string intToStr(int d){
  stringstream t;
  t << d;
  return t.str();
}

/*
 * fibonacciGlite-io.cpp created 14:17 on 26th August 2005 author Sara Collins
 * 
 * Program to calculate the fibonacci sequence for a specified number
 * to a specified order. The number and order are read in from a file
 * on the fireman catalog and the output is written into a new file in
 * the catalog.
 *
 * TUTORIAL: use classes detailed in
 * https://edms.cern.ch/file/570771/1.1/EGEE-TECH-570771-v1.1.pdf
 * Hints a given aat each stage.
 */

int main(int argc, char *argv[]){

  //check the correct number of arguments have been passed.
  if(argc != 3 || strcmp(argv[1],"--help") == 0){
    cerr << "Usage : " << argv[0] << " <input file lfn> <output file lfn>" 
	 <<endl;
    return -1;
  }

  /* error code */
  int rc;  
  /* the input  */
  char * infile = argv[1]; 
  /* the file descriptor */
  int fd;  


  cout << "\nReading the file " << infile << endl;

   /* Open/create the file for reading
    * HINT: use glite_posix_open,  
    */
  if ((fd = glite_posix_open (infile, O_RDONLY, 0))  < 0) {
     cout << "Error in glite_posix_open" << endl;
     return -1;
  }

  cout << " Open successful " <<endl;;

  /* Maximum number of characters to be read in */
  size_t maxchar = 20;
  /* Number of bytes read in each time */
  size_t readsize = 1;

  /* Array that will store the values read from the file */
  char * readChars = new char[1];  
  /* Array holding all of the info read in */
  char * inputChars = new char[maxchar];

  /* A count of the number of byes read in */
  int count = 0;


 /* Read from the file (until eof) outputting the data.
  * HINT: use glite_posix_read
  */
  while((rc = glite_posix_read (fd, readChars, readsize )) == readsize ) {
    inputChars[count] = readChars[0];
    cout << readChars[0];
    count++;
  }

  cout << endl<<"Read finished "<<rc<<endl;

  /* Output file */
  char *outfile = argv[2];

  cout << "\nCreating file " << outfile << endl;

  /* Open/create the file for writing.
   * HINT: use glite_posix_open, permissions on the file need to be 0666
   * to be accessed later.
   */
  if ((fd = glite_posix_open(outfile, O_WRONLY | O_CREAT, 0666)) < 0) {
     cout << "Error in glite_posix_open" << endl;
     return -1;
  }

  cout << "Creation (open) successful " << endl;

  /* Convert arguments to double and int */
  double number;
  int order;
  sscanf(inputChars," %lf %d ",&number,&order);
  string num_str = doubleToStr(number);
  string order_str = intToStr(order);

  /* Output initial values of sequence to file 
   * HINT: use write_to_file method defined above.
   */
  string out_str = "1\n";
  write_to_file(fd,out_str.c_str());
  out_str = num_str+"\n";
  if(order > 1)  write_to_file(fd,out_str.c_str());

  double fib = number;
  double fib_prev = 1;

  /* Calculate the next values and output to file
   * HINT: use write_to_file method defined above 
   */
  for(unsigned int i = 3; i <= order; i++){
    double fib_next = fib*number + fib_prev;
    num_str = doubleToStr(fib_next);
    out_str = num_str+"\n";
    write_to_file(fd,out_str.c_str());
    fib_prev = fib;
    fib = fib_next;
  }


  /* Close the file, checking for errors
   * HINT: use glite_posix_close
   */
   if (glite_posix_close (fd)!=0) {
     cout << "Error in glite_posix_close" << endl;
   }
   else {
     cout << " ... Close successful" << endl;
   }
 
  return 0;
}
