#include <stdio.h>
#include <stdlib.h>
#include "../dynapdf/dynapdf.h"

using namespace DynaPDF;

// Error callback function.
SI32 PDF_CALL PDFError(const void* Data, SI32 ErrCode, const char* ErrMessage, SI32 ErrType)
{
   // The error type is a bitmask, see help file for further information.
   if (ErrType & E_WARNING)
      printf("Warning: %s\n", ErrMessage);
   else if (ErrType & E_SYNTAX_ERROR)
      printf("Syntax error!: %s\n", ErrMessage);
   else if (ErrType & E_VALUE_ERROR)
      printf("Value error: %s\n", ErrMessage);
   else if (ErrType & E_FONT_ERROR)
      printf("TrueType font error!: %s\n", ErrMessage);
   else if (ErrType & E_FILE_ERROR)
      printf("File error: %s\n", ErrMessage);
   else if (ErrType & E_FATAL_ERROR)
      printf("Fatal error: %s\n", ErrMessage);
   else
      printf("%s\n", ErrMessage);
   return 0; // any other return value breaks processing!
}

struct TOutRect
{
   TOutRect(void)
   {
      pdf      = NULL;
      PosX     = 0.0;
      PosY     = 0.0;
      Width    = 0.0;
      Height   = 0.0;
      Distance = 0.0;
      Column   = 0;
      ColCount = 1;
   }
   void*  pdf;      // Active PDF instance
   double PosX;     // Original x-coordinate of first output rectangle
   double PosY;     // Original y-coordinate of first output rectangle
   double Width;    // Original width of first output rectangle
   double Height;   // Original height of first output rectangle
   double Distance; // Space between columns
   SI32 Column;     // Current column
   SI32 ColCount;   // Number of colummns
};

char* GetFileBuffer(const char* FileName, UI32 &BufSize)
{
   size_t size;
   FILE* f = fopen(FileName, "rb");
   if (f == NULL) return NULL;
   char* buffer;
   fseek(f, 0, SEEK_END);
   BufSize = ftell(f);
   fseek(f, 0, SEEK_SET);
   // allocate one more character for the null-terminator
   buffer = (char*)malloc(BufSize +1);
   if (!buffer) return NULL;
   size = fread(buffer, 1, BufSize, f);
   fclose(f);
   BufSize = (UI32)size;
   buffer[BufSize] = 0; // Do NOT forget to add a null-terminator!!!
   return buffer;
}

// Callback function to place the remaining text onto a page if the current column is full.

SI32 PDF_CALL OnPageBreakProc(const void* Data, double LastPosX, double LastPosY, SI32 PageBreak)
{
   TOutRect* r = (TOutRect*)Data;    // get a pointer to our structure
   pdfSetPageCoords(r->pdf, pcTopDown); // we use top down coordinates
   ++r->Column;
   // PageBreak is true if the string contains a page break tag (see help file for further information).
   if (!PageBreak && r->Column < r->ColCount)
   {
      // Calulate the x-coordinate of the column
      double posX = r->PosX + r->Column * (r->Width + r->Distance);
      // change the output rectangle, do not close the page!
      pdfSetTextRect(r->pdf, posX, r->PosY, r->Width, r->Height);
      return 0; // we do not change the alignment
   }else
   {  // the page is full, close the current one and append a new page
      pdfEndPage(r->pdf);
      pdfAppend(r->pdf);
      pdfSetTextRect(r->pdf, r->PosX, r->PosY, r->Width, r->Height);
      r->Column = 0;
      return 0;
   }
}

int main(void)
{
   // The structure TOutRect holds all required variables to calculate
   // the output rectangle. We use it to avoid the usage of global
   // variables.
   TOutRect r;
   char outFile[] = "text_formatting.pdf";
   UI32 bufSize;
   // The text is stored in a file
   char* fText = GetFileBuffer("test_files/sample.txt", bufSize);
   if (!fText)
   {
      printf("Cannot open input file!");
      return 1;
   }

   void* pdf = pdfNewPDF(); // Get a new PDF instance
   r.pdf = pdf;
   if (!pdf)   // Out of memory?
   {
      free(fText);
      return 2;
   }

   pdfSetOnErrorProc(pdf, NULL, PDFError);
   pdfSetDocInfo(pdf, diCreator, "C++ test app");
   pdfSetDocInfo(pdf, diSubject, "Multi-column text");
   pdfSetDocInfo(pdf, diTitle, "Multi-column text");
   pdfSetPageCoords(pdf, pcTopDown);
   pdfCreateNewPDF(pdf, outFile);

   pdfAppend(pdf);

   r.ColCount = 3;    // Set the number of columns
   r.Column   = 0;    // Current column
   r.Distance = 10.0; // Distance between two columns
   r.PosX     = 50.0;
   r.PosY     = 50.0;
   r.Height   = pdfGetPageHeight(pdf) - 100.0;
   r.Width    = (pdfGetPageWidth(pdf) - 100.0 - (r.ColCount -1) * r.Distance) / r.ColCount;

   // The structure is passed to the callback function now
   pdfSetOnPageBreakProc(pdf, &r, OnPageBreakProc);
   // Set the output rectangle first
   pdfSetTextRect(pdf, r.PosX, r.PosY, r.Width, r.Height);

   pdfSetFont(pdf, "Helvetica", fsNone, 10.0, true, cp1252);
   pdfWriteFText(pdf, taJustify, fText); // Now we can print the text

   free(fText);        // free the text buffer

   pdfEndPage(pdf);    // Close the last page
   pdfCloseFile(pdf);  // Close the file

   pdfDeletePDF(pdf); // Do not forget to delete the PDF instance
   printf("PDF file %s successfully created!\n", outFile);
   return 0;
}
