#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
   #include <windows.h>
   #include <shellapi.h>
   #include <conio.h>
#endif

#define PDF_STATIC // Enable static binding when compiling the project with the workspace dynapdf_static.
#include "../dynapdf/dynapdf.h"

static const BYTE TEST_TEXT[] =
{
   0x54,0x68,0x65,0x20,0x71,0x75,0x69,0x63,0x6B,0x20,0x62,0x72,0x6F,0x77,0x6E,0x20,
   0x66,0x6F,0x78,0x20,0x61,0x6E,0x64,0x20,0x74,0x68,0x65,0x20,0x6C,0x61,0x7A,0x79,
   0x20,0x6D,0x6F,0x75,0x73,0x65,0x2E,0x20,0xE4,0xF6,0xFC,0x20,0xC4,0xD6,0xDC,0x20,
   0xDF,0x20,0x80,0x20,0x40,0x00
};

#define TEST_TEXT1  (const char*)TEST_TEXT
#define TEST_TEXT2  "The quick brown fox."
#define CHAR_COUNT  20
#define SPACE_COUNT 3

static UI32 TimeStart;
static char LineBuffer[512];
static TFontSelMode m_SelMode = smFamilyName;

struct TPDFFont
{
   UI16* FamilyName;
   char* PostScriptName;
   SI32  Style;
};

void** Fonts = NULL;
SI32   FontCount;
SI32   fPos = 0L;

// Error callback function.
SI32 PDF_CALL PDFError(const void* Data, SI32 ErrCode, const char* ErrMessage, SI32 ErrType)
{
   printf("%s\n", ErrMessage);
   return 0; // any other return value breaks processing!
}

char* GetCodepageAsStr(TCodepage CP)
{
   switch(CP)
   {
      case cp1250: return "1250";
      case cp1251: return "1251";
      case cp1252: return "1252";
      case cp1253: return "1253";
      case cp1254: return "1254";
      case cp1255: return "1255";
      case cp1256: return "1256";
      case cp1257: return "1257";
      case cp1258: return "1258";
      case cp8859_2: return "8859_2";
      case cp8859_3: return "8859_3";
      case cp8859_4: return "8859_4";
      case cp8859_5: return "8859_5";
      case cp8859_6: return "8859_6";
      case cp8859_7: return "8859_7";
      case cp8859_8: return "8859_8";
      case cp8859_9: return "8859_9";
      case cp8859_10: return "8859_10";
      case cp8859_13: return "8859_13";
      case cp8859_14: return "8859_14";
      case cp8859_15: return "8859_15";
      case cp8859_16: return "8859_16";
      case cpSymbol: return "Symbol";
      case cp437: return "437";
      case cp737: return "737";
      case cp775: return "775";
      case cp850: return "850";
      case cp852: return "852";
      case cp855: return "855";
      case cp857: return "857";
      case cp860: return "860";
      case cp861: return "861";
      case cp862: return "862";
      case cp863: return "863";
      case cp864: return "864";
      case cp865: return "865";
      case cp866: return "866";
      case cp869: return "869";
      case cp874: return "874";
      case cpUnicode: return "Unicode";
      default: return "CJK code pages are not supported in this test";
   }
}

double WriteTextLine(const void* PDF, double PosX, double PosY, const char* FontName, const char* DisplayName, TFStyle Style, TCodepage CP)
{
   SI32 retval;
   char errText[] = "unsupported Codepage!";
   pdfSetFont(PDF, "Helvetica", fsRegular | fsUnderlined, 14.0, true, cp1252);
   pdfWriteText(PDF, PosX, PosY, DisplayName);
   pdfSetFont(PDF, "Helvetica", fsRegular, 10.0, true, cp1252);
   PosY += 20;
   pdfWriteText(PDF, PosX, PosY, "Font style fsNone:");
   pdfWriteText(PDF, PosX, PosY + 10.0, "Font style fsUnderlined:");
   pdfWriteText(PDF, PosX, PosY + 20.0, "Font style fsStriked");
   pdfWriteText(PDF, PosX, PosY + 30.0, "Font style fsUnderlined + fsStriked:");

   if (m_SelMode == smFamilyName)
      retval = pdfSetFont(PDF, FontName, Style, 10.0, true, CP);
   else
      retval = pdfSetFont(PDF, DisplayName, Style, 10.0, true, CP);
   if (retval >= 0)
   {
      PosX += 170;
      pdfWriteText(PDF, PosX, PosY, TEST_TEXT1);
      pdfChangeFontStyle(PDF, Style | fsUnderlined);
      pdfWriteText(PDF, PosX, PosY + 10.0, TEST_TEXT1);
      pdfChangeFontStyle(PDF, Style | fsStriked);
      pdfWriteText(PDF, PosX, PosY + 20.0, TEST_TEXT1);
      pdfChangeFontStyle(PDF, Style | fsUnderlined | fsStriked);
      pdfWriteText(PDF, PosX, PosY + 30.0, TEST_TEXT1);
      pdfChangeFontStyle(PDF, Style);
   }else
   {
      PosX += 170;
      pdfWriteText(PDF, PosX, PosY, errText);
      pdfChangeFontStyle(PDF, Style | fsUnderlined);
      pdfWriteText(PDF, PosX, PosY + 10.0, errText);
      pdfChangeFontStyle(PDF, Style | fsStriked);
      pdfWriteText(PDF, PosX, PosY + 20.0, errText);
      pdfChangeFontStyle(PDF, Style | fsUnderlined | fsStriked);
      pdfWriteText(PDF, PosX, PosY + 30.0, errText);
      pdfChangeFontStyle(PDF, Style);
   }
   return (PosY + 30.0);
}

void TestStandardFonts(const void* PDF, TCodepage CP)
{
   char title[64] = "Standard Type1 Fonts (code page ";
   double posY = 50.0;

   // We change the font search order to make sure that the standard fonts will be selected
   TFontBaseType searchOrder[4] = {fbtStdFont, fbtDisabled, fbtDisabled, fbtDisabled};
   pdfSetFontSearchOrder(PDF, searchOrder);
   pdfSetFontSelMode(PDF, m_SelMode);

   pdfAppend(PDF);
   pdfSetLineWidth(PDF, 0.5);
   pdfSetStrokeColor(PDF, PDF_BLACK);
   pdfSetFillColor(PDF, PDF_NAVY);

   if (m_SelMode == smFamilyName)
      pdfSetFont(PDF, "Helvetica", fsRegular | fsItalic | fsUnderlined, 20.0, true, cp1252);
   else
      pdfSetFont(PDF, "Helvetica-Oblique", fsUnderlined, 20.0, true, cp1252);

   strcat(title, GetCodepageAsStr(CP));
   strcat(title, ")");

   pdfWriteText(PDF, 50.0, posY, title);
   pdfSetFillColor(PDF, PDF_BLACK);
   posY += 30;
   posY = WriteTextLine(PDF, 50.0, posY, "Helvetica", "Helvetica", fsRegular, CP) + 20.0;
   posY = WriteTextLine(PDF, 50.0, posY, "Helvetica", "Helvetica-Bold", fsBold, CP) + 20.0;
   posY = WriteTextLine(PDF, 50.0, posY, "Helvetica", "Helvetica-Oblique", fsItalic, CP) + 20.0;
   posY = WriteTextLine(PDF, 50.0, posY, "Helvetica", "Helvetica-BoldOblique", fsItalic | fsBold, CP) + 20.0;

   posY = WriteTextLine(PDF, 50.0, posY, "Courier", "Courier", fsRegular, CP) + 20.0;
   posY = WriteTextLine(PDF, 50.0, posY, "Courier", "Courier-Bold", fsBold, CP) + 20.0;
   posY = WriteTextLine(PDF, 50.0, posY, "Courier", "Courier-Oblique", fsItalic, CP) + 20.0;
   posY = WriteTextLine(PDF, 50.0, posY, "Courier", "Courier-BoldOblique", fsBold | fsItalic, CP) + 20.0;
   posY = WriteTextLine(PDF, 50.0, posY, "Times", "Times-Roman", fsRegular, CP) + 20.0;
   WriteTextLine(PDF, 50.0, posY, "Times", "Times-Bold", fsBold, CP);
   pdfEndPage(PDF);

   pdfAppend(PDF);
   posY = 50.0;
   pdfSetLineWidth(PDF, 0.5);
   pdfSetStrokeColor(PDF, PDF_BLACK);
   pdfSetFillColor(PDF, PDF_NAVY);

   if (m_SelMode == smFamilyName)
      pdfSetFont(PDF, "Helvetica", fsRegular | fsItalic | fsUnderlined, 20.0, true, cp1252);
   else
      pdfSetFont(PDF, "Helvetica-Oblique", fsUnderlined, 20.0, true, cp1252);

   pdfWriteText(PDF, 50.0, posY, title);
   pdfSetFillColor(PDF, PDF_BLACK);
   posY += 30;
   posY = WriteTextLine(PDF, 50.0, posY, "Times", "Times-Italic", fsItalic, CP) + 20.0;
   posY = WriteTextLine(PDF, 50.0, posY, "Times", "Times-BoldItalic", fsBold | fsItalic, CP) + 20.0;

   // We cannot emulate a font style when trying to select the font with the postscript name.
   m_SelMode = smFamilyName;
   pdfSetFontSelMode(PDF, m_SelMode);

   posY = WriteTextLine(PDF, 50.0, posY, "ZapfDingbats", "ZapfDingbats", fsRegular, CP) + 20.0;
   posY = WriteTextLine(PDF, 50.0, posY, "ZapfDingbats", "ZapfDingbats-Bold (emulated)", fsBold, CP) + 20.0;
   posY = WriteTextLine(PDF, 50.0, posY, "ZapfDingbats", "ZapfDingbats-Italic (emulated)", fsItalic, CP) + 20.0;
   posY = WriteTextLine(PDF, 50.0, posY, "ZapfDingbats", "ZapfDingbats-BoldItalic (emulated)", fsBold | fsItalic, CP) + 20.0;
   posY = WriteTextLine(PDF, 50.0, posY, "Symbol", "Symbol", fsRegular, CP) + 20.0;
   posY = WriteTextLine(PDF, 50.0, posY, "Symbol", "Symbol-Bold (emulated)", fsBold, CP) + 20.0;
   posY = WriteTextLine(PDF, 50.0, posY, "Symbol", "Symbol-Italic (emulated)", fsItalic, CP) + 20.0;
   WriteTextLine(PDF, 50.0, posY, "Symbol", "Symbol-BoldItalic (emulated)", fsBold | fsItalic, CP);
   pdfEndPage(PDF);
}

double WritePropertyLine(const void* PDF, double PosX, double PosY, const UI16* FontName, const char* DisplayName, TFStyle Style, TCodepage CP)
{
   SI32 retval;
   double strRect = 300;
   double orgWidth, w, desc;
   char errText[256];

   if (m_SelMode == smFamilyName)
      pdfSetFont(PDF, "Helvetica", fsRegular | fsItalic | fsUnderlined, 14.0, true, cp1252);
   else
      pdfSetFont(PDF, "Helvetica-Oblique", fsUnderlined, 14.0, true, cp1252);

   pdfWriteText(PDF, PosX, PosY, DisplayName);
   PosY += 20.0;
   pdfSetFont(PDF, "Helvetica", fsRegular, 10.0, false, cp1252);
   pdfWriteText(PDF, PosX, PosY, "Regular:");
   pdfWriteText(PDF, PosX, PosY +10, "Character spacing:");
   pdfWriteText(PDF, PosX, PosY +20, "Word spacing:");
   pdfWriteText(PDF, PosX, PosY +30, "Text scaling:");
   pdfWriteText(PDF, PosX, PosY +40, "Character + word spacing:");
   pdfWriteText(PDF, PosX, PosY +50, "Character + word spacing + text scaling:");
   PosX += 200;

   if (m_SelMode == smFamilyName)
      retval = pdfSetFontW(PDF, FontName, Style, 10.0, true, CP);
   else
      retval = pdfSetFont(PDF, DisplayName, Style, 10.0, true, CP);

   if (retval < 0)
   {
      sprintf(errText, "%s", pdfGetErrorMessage(PDF));
      pdfWriteText(PDF, PosX, PosY, errText);
      pdfWriteText(PDF, PosX, PosY +10, errText);
      pdfWriteText(PDF, PosX, PosY +20, errText);
      pdfWriteText(PDF, PosX, PosY +30, errText);
      pdfWriteText(PDF, PosX, PosY +40, errText);
      pdfWriteText(PDF, PosX, PosY +50, errText);
      return (PosY + 70.0);
   }
   orgWidth = pdfGetTextWidth(PDF, TEST_TEXT2);
   if (orgWidth == 0.0)
   {
      sprintf(errText, "unsupported code page");
      pdfWriteText(PDF, PosX, PosY, errText);
      pdfWriteText(PDF, PosX, PosY +10, errText);
      pdfWriteText(PDF, PosX, PosY +20, errText);
      pdfWriteText(PDF, PosX, PosY +30, errText);
      pdfWriteText(PDF, PosX, PosY +40, errText);
      pdfWriteText(PDF, PosX, PosY +50, errText);
      return (PosY + 70.0);
   }

   desc = pdfGetDescent(PDF);

   pdfWriteText(PDF, PosX, PosY, TEST_TEXT1);
   PosY += 10.0;
   pdfSetCharacterSpacing(PDF, (strRect - orgWidth) / (CHAR_COUNT -1));
   pdfWriteText(PDF, PosX, PosY, TEST_TEXT2);
   w = pdfGetTextWidth(PDF, TEST_TEXT2);
   pdfRectangle(PDF, PosX, PosY + desc / 2, w, 10.0, fmStroke);
   pdfSetCharacterSpacing(PDF, 0.0);

   pdfSetWordSpacing(PDF, (strRect - orgWidth) / SPACE_COUNT);
   pdfWriteText(PDF, PosX, PosY + 10, TEST_TEXT2);
   w = pdfGetTextWidth(PDF, TEST_TEXT2);
   pdfRectangle(PDF, PosX, PosY + 10 + desc / 2, w, 10.0, fmStroke);
   pdfSetWordSpacing(PDF, 0.0);

   pdfSetTextScaling(PDF, (strRect / orgWidth) * 100);
   pdfWriteText(PDF, PosX, PosY + 20, TEST_TEXT2);
   w = pdfGetTextWidth(PDF, TEST_TEXT2);
   pdfRectangle(PDF, PosX, PosY + 20 + desc / 2, w, 10.0, fmStroke);
   pdfSetTextScaling(PDF, 100.0);

   pdfSetCharacterSpacing(PDF, 5.0);
   w = pdfGetTextWidth(PDF, TEST_TEXT2);
   pdfSetWordSpacing(PDF, (strRect - w) / SPACE_COUNT);
   pdfWriteText(PDF, PosX, PosY + 30, TEST_TEXT2);
   w = pdfGetTextWidth(PDF, TEST_TEXT2);
   pdfRectangle(PDF, PosX, PosY + 30 + desc / 2, w, 10.0, fmStroke);
   pdfSetCharacterSpacing(PDF, 0.0);
   pdfSetWordSpacing(PDF, 0.0);

   pdfSetCharacterSpacing(PDF, 3.0);
   pdfSetWordSpacing(PDF, 5.0);
   w = pdfGetTextWidth(PDF, TEST_TEXT2);
   pdfSetTextScaling(PDF, (strRect / w) * 100);
   pdfWriteText(PDF, PosX, PosY + 40, TEST_TEXT2);
   w = pdfGetTextWidth(PDF, TEST_TEXT2);
   pdfRectangle(PDF, PosX, PosY + 40 + desc / 2, w, 10.0, fmStroke);
   pdfSetCharacterSpacing(PDF, 0.0);
   pdfSetWordSpacing(PDF, 0.0);
   pdfSetTextScaling(PDF, 100.0);

   return (PosY + 60.0);
}

SI32 PDF_CALL EnumFontProc(const void* Data, const UI16* FamilyName, const char* PostScriptName, SI32 Style)
{
   struct TPDFFont* f;
   SI32 len;
   if (fPos == FontCount) return -1;
   len = pdfStrLenW(FamilyName);
   f = malloc(sizeof(struct TPDFFont));
   f->FamilyName = (UI16*)malloc(len *2 +2);
   memcpy(f->FamilyName, FamilyName, len * 2);
   f->FamilyName[len] = 0L;
   len = pdfStrLenA(PostScriptName);
   f->PostScriptName = (char*)malloc(len +1);
   strcpy(f->PostScriptName, PostScriptName);
   f->Style = Style;
   Fonts[fPos++] = f;
   return 0;
}

void TestFontMethods(const void* PDF, TCodepage CP, BYTE AllFonts)
{
   char title[128] = "Test font methods (code page ";
   char headText[156];
   struct TPDFFont* font;
   SI32 i;
   double posY = 50.0;

   // We change the font search order to make sure that the standard fonts will be selected
   TFontBaseType searchOrder[4] = {fbtStdFont, fbtDisabled, fbtDisabled, fbtDisabled};
   pdfSetFontSearchOrder(PDF, searchOrder);
   pdfSetFontSelMode(PDF, m_SelMode);

   strcat(title, GetCodepageAsStr(CP));
   strcat(title, ")");

   pdfAppend(PDF);
   pdfSetStrokeColor(PDF, PDF_BLACK);
   pdfSetLineWidth(PDF, 0.5);
   pdfSetFillColor(PDF, PDF_NAVY);

   if (m_SelMode == smFamilyName)
      pdfSetFont(PDF, "Helvetica", fsRegular | fsItalic | fsUnderlined, 20.0, true, cp1252);
   else
      pdfSetFont(PDF, "Helvetica-Oblique", fsUnderlined, 20.0, true, cp1252);

   pdfWriteText(PDF, 50.0, posY, title);
   posY += 30.0;
   pdfSetFont(PDF, "Helvetica", fsRegular, 12.0, false, cp1252);
   pdfSetFillColor(PDF, PDF_BLACK);
   pdfWriteText(PDF, 50.0, posY, "The rectanlge over the following output strings is always calculated with GetTextWidth().");
   posY += 20;

   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Helvetica"), "Helvetica", fsRegular, CP);
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Helvetica"), "Helvetica-Bold", fsBold, CP);
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Helvetica"), "Helvetica-Oblique", fsItalic, CP);
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Helvetica"), "Helvetica-BoldOblique", fsItalic | fsBold, CP);
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Courier"), "Courier", fsRegular, CP);
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Courier"), "Courier-Bold", fsBold, CP);
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Courier"), "Courier-Oblique", fsItalic, CP);
   WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Courier"), "Courier-BoldOblique", fsBold | fsItalic, CP);
   pdfEndPage(PDF);

   pdfAppend(PDF);
   posY = 50.0;
   pdfSetLineWidth(PDF, 0.5);
   pdfSetFillColor(PDF, PDF_NAVY);

   if (m_SelMode == smFamilyName)
      pdfSetFont(PDF, "Helvetica", fsItalic + fsUnderlined, 20.0, true, cp1252);
   else
      pdfSetFont(PDF, "Helvetica-Oblique", fsUnderlined, 20.0, true, cp1252);

   pdfWriteText(PDF, 50.0, posY, title);
   pdfSetFillColor(PDF, PDF_BLACK);
   posY += 30;
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Times"), "Times-Roman", fsRegular, CP);
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Times"), "Times-Bold", fsBold, CP);
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Times"), "Times-Italic", fsItalic, CP) ;
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Times"), "Times-BoldItalic", fsBold | fsItalic, CP);

   // We cannot emulate a font style when trying to select the font with the postscript name.
   m_SelMode = smFamilyName;
   pdfSetFontSelMode(PDF, m_SelMode);
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"ZapfDingbats"), "ZapfDingbats", fsRegular, CP);
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"ZapfDingbats"), "ZapfDingbats-Bold (emulated)", fsBold, CP);
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"ZapfDingbats"), "ZapfDingbats-Italic (emulated)", fsItalic, CP);
   WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"ZapfDingbats"), "ZapfDingbats-BoldItalic (emulated)", fsBold | fsItalic, CP);
   pdfEndPage(PDF);

   pdfAppend(PDF);
   posY = 50.0;
   pdfSetLineWidth(PDF, 0.5);
   pdfSetFillColor(PDF, PDF_NAVY);

   if (m_SelMode == smFamilyName)
      pdfSetFont(PDF, "Helvetica", fsRegular | fsItalic + fsUnderlined, 20.0, true, cp1252);
   else
      pdfSetFont(PDF, "Helvetica-Oblique", fsUnderlined, 20.0, true, cp1252);

   pdfWriteText(PDF, 50.0, posY, title);
   pdfSetFillColor(PDF, PDF_BLACK);
   posY += 30;
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Symbol"), "Symbol", fsRegular, CP);
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Symbol"), "Symbol-Bold (emulated)", fsBold, CP);
   posY = WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Symbol"), "Symbol-Italic (emulated)", fsItalic, CP);
   WritePropertyLine(PDF, 50.0, posY, ToUTF16(PDF, L"Symbol"), "Symbol-BoldItalic (emulated)", fsBold | fsItalic, CP);
   pdfEndPage(PDF);

   if (AllFonts == 0) return;

   // Reset the search order to the default order
   pdfSetFontSearchOrder(PDF, NULL);

   m_SelMode = smPostScriptName;
   pdfSetFontSelMode(PDF, m_SelMode);

   i = 0;
   while (i < FontCount)
   {
      pdfAppend(PDF);
      posY = 50.0;
      pdfSetLineWidth(PDF, 0.5);
      pdfSetFillColor(PDF, PDF_NAVY);

      if (m_SelMode == smFamilyName)
         pdfSetFont(PDF, "Helvetica", fsRegular | fsItalic | fsUnderlined, 20.0, true, cp1252);
      else
         pdfSetFont(PDF, "Helvetica-Oblique", fsUnderlined, 20.0, true, cp1252);

      sprintf(headText, "%s Index: %d", title, i);
      pdfWriteText(PDF, 50.0, posY, headText);
      pdfSetFillColor(PDF, PDF_BLACK);
      posY += 30;
      while (i < FontCount && posY < 780.0)
      {
         font = Fonts[i];
         posY = WritePropertyLine(PDF, 50.0, posY, font->FamilyName, font->PostScriptName, font->Style, CP) + 10.0;
         i++;
      }
      pdfEndPage(PDF);
   }
}

void DrawShapes(const void* PDF, TDrawDirection Direction, TPageCoord Coords, const char* Text)
{
   char title[] = "Vector graphics test";
   double posY = 50.0;
   double posX = 130.0;

   pdfAppend(PDF);
   if (Coords == pcBottomUp) posY = pdfGetPageHeight(PDF) -70;
   pdfSetDrawDirection(PDF, Direction);
   pdfSetPageCoords(PDF, Coords);
   pdfSetLineWidth(PDF, 0.5);
   pdfSetFillColor(PDF, PDF_NAVY);
   pdfSetFont(PDF, "Helvetica", fsItalic | fsUnderlined, 20.0, false, cp1252);
   pdfWriteText(PDF, 50.0, posY, title);
   if (Coords == pcBottomUp) posY -= 50.0; else posY += 50.0;
   pdfSetFillColor(PDF, PDF_BLACK);
   pdfSetFont(PDF, "Helvetica", fsRegular, 12.0, false, cp1252);
   pdfWriteText(PDF, posX, posY, Text);
   if (Coords == pcBottomUp) posY -= 60.0; else posY += 20.0;

   pdfSetFillColor(PDF, PDF_MOGREEN);
   pdfSetStrokeColor(PDF, PDF_BLUE);
   pdfRectangle(PDF, posX, posY, 100.0, 50.0, fmStroke);
   pdfRectangle(PDF, posX + 110.0, posY, 100.0, 50.0, fmFill);
   pdfRectangle(PDF, posX + 220.0, posY, 100.0, 50.0, fmFillStroke);

   if (Coords == pcBottomUp) posY -= 60.0; else posY += 60.0;

   pdfRoundRect(PDF, posX, posY, 100.0, 50.0, 20.0, fmStroke);
   pdfRoundRect(PDF, posX + 110.0, posY, 100.0, 50.0, 20.0, fmFill);
   pdfRoundRect(PDF, posX + 220.0, posY, 100.0, 50.0, 20.0, fmFillStroke);

   if (Coords == pcBottomUp) posY -= 60.0; else posY += 60.0;

   pdfRoundRectEx(PDF, posX, posY, 100.0, 50.0, 40.0, 20.0, fmStroke);
   pdfRoundRectEx(PDF, posX + 110.0, posY, 100.0, 50.0, 40.0, 20.0, fmFill);
   pdfRoundRectEx(PDF, posX + 220.0, posY, 100.0, 50.0, 40.0, 20.0, fmFillStroke);

   if (Coords == pcBottomUp) posY -= 60.0; else posY += 60.0;

   pdfEllipse(PDF, posX, posY, 100.0, 50.0, fmStroke);
   pdfEllipse(PDF, posX + 110.0, posY, 100.0, 50.0, fmFill);
   pdfEllipse(PDF, posX + 220.0, posY, 100.0, 50.0, fmFillStroke);

   if (Coords == pcBottomUp) posY -= 35.0; else posY += 85.0;

   pdfDrawCircle(PDF, posX + 50, posY, 25.0, fmStroke);
   pdfDrawCircle(PDF, posX + 160, posY, 25.0, fmFill);
   pdfDrawCircle(PDF, posX + 270, posY, 25.0, fmFillStroke);

   if (Coords == pcBottomUp) posY -= 60.0; else posY += 60.0;

   pdfDrawChord(PDF, posX + 50.0, posY, 100.0, 50.0, 150.0, 30.0, fmStroke);
   pdfDrawChord(PDF, posX + 160.0, posY, 100.0, 50.0, 150.0, 30.0, fmFill);
   pdfDrawChord(PDF, posX + 270.0, posY, 100.0, 50.0, 150.0, 30.0, fmFillStroke);

   if (Coords == pcBottomUp) posY -= 60.0; else posY += 60.0;

   pdfDrawPie(PDF, posX + 50.0, posY, 100.0, 50.0, 150.0, 30.0, fmStroke);
   pdfDrawPie(PDF, posX + 160.0, posY, 100.0, 50.0, 150.0, 30.0, fmFill);
   pdfDrawPie(PDF, posX + 270.0, posY, 100.0, 50.0, 150.0, 30.0, fmFillStroke);

   if (Coords == pcBottomUp) posY -= 60.0; else posY += 60.0;

   pdfDrawArc(PDF, posX + 50.0, posY, 25.0, 150.0, 30.0);
   pdfStrokePath(PDF);
   pdfDrawArcEx(PDF, posX + 160.0, posY, 50.0, 50.0, 150.0, 30.0);
   pdfStrokePath(PDF);
   pdfDrawArcEx(PDF, posX + 270.0, posY, 100.0, 50.0, 150.0, 30.0);
   pdfStrokePath(PDF);

   if (Coords == pcBottomUp) posY -= 85.0; else posY += 35.0;

   pdfTriangle(PDF, posX, posY, posX +100.0, posY, posX +50.0, posY +50.0, fmStroke);
   posX += 110.0;
   pdfTriangle(PDF, posX, posY, posX +100.0, posY, posX +50.0, posY +50.0, fmFill);
   posX += 110.0;
   pdfTriangle(PDF, posX, posY, posX +100.0, posY, posX +50.0, posY +50.0, fmFillStroke);
   pdfEndPage(PDF);
}

void TestVectorGraphicMethods(const void* PDF)
{
   // Because we use standard fonts in this example, we change the font search order
   // so that standard fonts have a higher search priority than system fonts
   TFontBaseType searchOrder[4] = {fbtStdFont, fbtDisabled, fbtDisabled, fbtDisabled};
   pdfSetFontSearchOrder(PDF, searchOrder);
   pdfSetFontSelMode(PDF, smFamilyName);

   DrawShapes(PDF, ddCounterClockwise, pcTopDown, "Top Down Coordinates (draw direction counterclockwise)");
   DrawShapes(PDF, ddClockwise, pcTopDown, "Top Down Coordinates (draw direction clockwise)");

   DrawShapes(PDF, ddCounterClockwise, pcBottomUp, "Bottom Up Coordinates (draw direction counterclockwise)");
   DrawShapes(PDF, ddClockwise, pcBottomUp, "Bottom Up Coordinates (draw direction clockwise)");
}

void CreateTestPDF(const void* PDF, const char* FileName, BYTE UseFontList)
{
 #ifdef _WIN32
   TimeStart = GetTickCount();
#endif
   pdfSetOnErrorProc(PDF, NULL, PDFError);
   pdfSetDocInfo(PDF, diSubject, "DynaPDF function test");
   pdfSetDocInfo(PDF, diTitle, "DynaPDF function test");
   pdfSetViewerPreferences(PDF, vpDisplayDocTitle, avNone);

   pdfSetPageCoords(PDF, pcTopDown);
   pdfSetCompressionLevel(PDF, clDefault);
   pdfCreateNewPDF(PDF, FileName);
}

void EndTest(const void* PDF, const char* FileName)
{
   pdfCloseFile(PDF);
#ifdef _WIN32
   TimeStart = GetTickCount() - TimeStart;
   printf("\nProcessing time: %d ms\n", TimeStart);
   printf("\nPDF file \"%s\" created!\n", FileName);
   ShellExecute(0, "open", FileName, NULL, NULL, SW_SHOWMAXIMIZED);
#else
   printf("\nPDF file \"%s\" created!\n", FileName);
#endif
}

int PrintMenu(const char* FileName)
{
   int num = 1;
   printf("\n%d. Standard font test\n", num++);
   printf("%d. Test font methods (standard fonts only)\n", num++);
   printf("%d. Test font methods (all fonts)\n", num++);
   printf("%d. Test vector graphics\n", num++);
   printf("%d. Set output file name (default: %s)\n", num++, FileName);
   printf("%d. Display output file name\n", num++);
   printf("%d. Exit\n", num++);
   printf("\nEnter option: ");
   if (scanf("%s", LineBuffer))
      return LineBuffer[0];
   return 0;
}

int main(void)
{
   char fileName[512];
   int i, retval;
   struct TPDFFont* font;
   void* pdf = pdfNewPDF();
   if (!pdf)
   {
      printf("Out of memory!\n");
      return 2;
   }
   // set the license key here

   FontCount = pdfEnumHostFonts(pdf, NULL, NULL);
   fPos = 0;
   if (FontCount <= 0)
   {
      printf("No fonts found!\n");
      pdfDeletePDF(pdf);
      return 0;
   }else if (Fonts == NULL)
   {
      printf("Found count: %d\n", FontCount);
      Fonts = malloc(FontCount * sizeof(void*));
      FontCount = pdfEnumHostFonts(pdf, NULL, (TEnumFontProc*)EnumFontProc);
   }

   strcpy(fileName, "font_test.pdf");
   retval = PrintMenu(fileName);
   for (;;)
      switch(retval)
      {
         case '1':
            CreateTestPDF(pdf, fileName, false);
            TestStandardFonts(pdf, cp1252);
            EndTest(pdf, fileName);
            retval = PrintMenu(fileName);
            break;
         case '2':
            CreateTestPDF(pdf, fileName, false);
            TestFontMethods(pdf, cp1252, false);
            EndTest(pdf, fileName);
            retval = PrintMenu(fileName);
            break;
         case '3':
            printf("\nRunning test please wait...\n\n");
            CreateTestPDF(pdf, fileName, true);
            TestFontMethods(pdf, cp1252, true);
            EndTest(pdf, fileName);
            retval = PrintMenu(fileName);
            break;
         case '4':
            printf("\nRunning test please wait...\n\n");
            CreateTestPDF(pdf, fileName, true);
            TestVectorGraphicMethods(pdf);
            EndTest(pdf, fileName);
            retval = PrintMenu(fileName);
            break;
         case '5':
            printf("\nEnter file name: \n");
            if (scanf("%s", fileName))
               printf("\nNew file name: %s\n", fileName);
            retval = PrintMenu(fileName);
            break;
         case '6':
            printf("\n%s\n", fileName);
            retval = PrintMenu(fileName);
            break;
         case '7':
         {
           for (i = 0; i < FontCount; i++)
           {
               font = (struct TPDFFont*)Fonts[i];
               free(font->FamilyName);
               free(font->PostScriptName);
               free(font);
           }
           free(Fonts);
           Fonts = NULL;
           pdfDeletePDF(pdf);
           return 0;
         }
         default:
         {
            printf("\nUnknown option!\n");
            retval = PrintMenu(fileName);
            break;
         }
      }
}



