// MakePDF.cpp : Defines the entry point for the console application.
//

#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "DocVisitor.h"
#include "DocTemplate.h"
#include "DocOutput.h"
#include "DocSVG.h"
#include "Util.h"

//#include "document.h"
#include "html.h"
#include "tinyxml.h"


#ifndef _WIN32
#  include <unistd.h>
//#  define __cdecl
#else
   extern "C" void __stdcall Sleep(unsigned int);
#endif


#ifdef GUI_APP
#  include "ui.h"
#endif


#define DEF_IUNIT        1024
#define DEF_OUNIT        64
#define DEF_MAX_NESTING  16


extern void runTests();


struct Context
{
	const char* title;
	const char* inFileName;
	const char* outFileName_PDF;
	const char* outFileName_HTML;
	DocOutputDevice* doc;
	hoedown_buffer *inputBuffer;
	hoedown_buffer *outputBuffer;
};


static void RemoveFile(const char* fileName)
{
#ifdef _WIN32
	FILE* tmpF = 0;
	bool first = true;
	do
	{
		fopen_s(&tmpF, fileName, "rb");
		if (tmpF)
		{
			fclose(tmpF);
			_unlink(fileName);
			::Sleep(100);
			if (first)
				printf("waiting for output file to be removed.");
			else
				printf(".");
			first = false;
			fflush(stdout);
		}
	} while (tmpF != 0);
#else
	unlink(fileName);
#endif
}


hoedown_buffer *ReadInWholeFile(const char* inputFileName)
{
	// Read in the markdown file
	FILE* f = 0;
	fopen_s(&f, inputFileName, "rt"); // text or binary? Can it be utf8, and if so, do I need to read in binary mode?
	if (!f)
		return 0;
	/*
	fseek(f, 0L, SEEK_END);
	long fileSize = ftell(f);
	fseek(f, 0L, SEEK_SET);
	uint8_t* inputBuffer = (uint8_t*)malloc(fileSize);
	size_t inputBufferSize = fread(inputBuffer, 1, fileSize, f);
	*/
	hoedown_buffer *ib = hoedown_buffer_new(DEF_IUNIT);
	if (hoedown_buffer_putf(ib, f))
		fprintf(stderr, "I/O errors found while reading input.\n");

	fclose(f);
	return ib;
}


hoedown_buffer *ConvertMarkdownToHTML(uint8_t* inputBuffer, size_t inputBufferSize)
{
	hoedown_html_flags flags = (hoedown_html_flags)(HOEDOWN_HTML_ESCAPE | HOEDOWN_HTML_HARD_WRAP | HOEDOWN_HTML_USE_XHTML);
	hoedown_renderer *renderer = hoedown_html_renderer_new(flags, 0);
	hoedown_buffer *ob = hoedown_buffer_new(DEF_OUNIT);
	hoedown_document *document = hoedown_document_new(renderer, HOEDOWN_EXT_SPACE_HEADERS, DEF_MAX_NESTING);
	hoedown_document_render(document, ob, inputBuffer, inputBufferSize);
	hoedown_document_free(document);
	hoedown_html_renderer_free(renderer);
	return ob;
}


void SVGTest(const char* a_fileName, double scale, DocOutputDevice* outputDoc)
{
	hoedown_buffer* inputBuffer = ReadInWholeFile(a_fileName);
	if (!inputBuffer)
		return;
	// SVG xml parse
	TiXmlDocument parser;
	parser.Parse((char*)inputBuffer->data);
	DocSVG visitor(scale);
	parser.Accept(&visitor);
	visitor.DumpOperations();
	visitor.WriteTo(outputDoc);
	hoedown_buffer_free(inputBuffer);
}


void ConvertHTMLToPDF(uint8_t* inputBuffer, DocOutputDevice* outputDoc)
{
	// xml parse
	DocStyle style;
	DocTemplate templ;
	TiXmlDocument parser;

	templ.ReadTemplateFile("test.tmpl");
	parser.Parse((char*)inputBuffer);
	DocVisitor visitor(outputDoc, &style, &templ);
	parser.Accept(&visitor);

    //SVGTest("test/triangle.svg", 0.02, outputDoc);
	//SVGTest("test/ArcTest.svg", 1.0, outputDoc);
}


void SaveHTML(const char* fileName, const uint8_t* data, size_t dataSize)
{
	RemoveFile(fileName);
	FILE* f = 0;
	fopen_s(&f, fileName, "wb");
	if (!f)
		return;
	const char *CSSText = "<!DOCTYPE html><html><head><title>test</title><link rel=\"stylesheet\" type=\"text/css\" href=\"base.css\"></head><body>";
	fwrite(CSSText, 1, strlen(CSSText), f);
	fwrite(data, 1, dataSize, f);
	fclose(f);
}


int ProcessConversionContext(Context* context)
{
	context->inputBuffer = ReadInWholeFile(context->inFileName);
	if (!context->inputBuffer)
		return -1;
	context->outputBuffer = ConvertMarkdownToHTML(context->inputBuffer->data, context->inputBuffer->size);
	//free(inputBuffer);
	hoedown_buffer_free(context->inputBuffer);
	ConvertHTMLToPDF(context->outputBuffer->data, context->doc);
	SaveHTML(context->outFileName_HTML, context->outputBuffer->data, context->outputBuffer->size);
	hoedown_buffer_free(context->outputBuffer);
	RemoveFile(context->outFileName_PDF);
	context->doc->finalize(context->outFileName_PDF);
	return 0;
}


int main(int argc, char* argv[])
{
    DocOutputDevice outputDoc;
    Context context = {
        "Test Markdown to PDF",
        "test/test.md",
        "test/test.pdf",
        "test/test.html",
        &outputDoc
    };
    ProcessConversionContext(&context);

/*
    // Qt MDI Example does this:

    Q_INIT_RESOURCE(mdi);
    QApplication app(argc, argv);
    QCoreApplication::setApplicationVersion(QT_VERSION_STR);
    QCommandLineParser parser;
    parser.setApplicationDescription("Qt MDI Example");
    parser.addHelpOption();
    parser.addVersionOption();
    parser.addPositionalArgument("file", "The file to open.");
    parser.process(app);

    MainWindow mainWin;
    foreach (const QString &fileName, parser.positionalArguments())
        mainWin.openFile(fileName);
    mainWin.show();
    return app.exec();
*/

#ifdef GUI_APP
    QApplication app(argc, argv);
    UiContext ui;
    ui.setupUi();
    //YQ_LOG_DEBUG("This is a test message");
    //runTests();
    app.exec();
#endif


/*
	fprintf(stderr, "HERE!\n\n\n");
	QApplication app2(argc, argv);
	QLabel l(0);
	l.setText("Hello!");
	l.show();
	app2.exec();
*/


	return 0;
}

