API Name: global.GeneralPDF

/**
* Provides an API for dynamically building a PDF document. Can program the
* document global page properties i.e. header/footer, document dimensions, and
* add content generated by any compatible external source.
*
* Uses com.itextpdf API Commands to create the PDF Document and content.
*
*/

var GeneralPDF = Class.create();
GeneralPDF.LETTER = 'letter';
GeneralPDF.GENERAL_PDF_PAGE_SIZE = 'general.pdf.page.size';
GeneralPDF.A4 = 'a4';
GeneralPDF.ATTACHMENT_TYPE = 'application/pdf';
GeneralPDF.prototype = {
initialize : function(pdfDoc, css, glideRecord) {
this.document = null;
this.savedDoc = null;
this.writer = null;
this.outputStream = new GeneralFormJava.ByteArrayOutputStream();

this.footerImage = null;
this.headerImage = null;
this.footnote = null;
this.headerPosition = null;
this.footerPosition = null;
this.pageSize = null;

this.pdfDoc = null;
this.glideRecord = null;
this.htmlWorker = null;
this.styles = null;
this.pdfElements = [];

//if (glideRecord) {
// this.glideRecord = glideRecord;
//}

if (pdfDoc) {
this._loadPDFDoc(pdfDoc);
}

// if (css) {
// this._loadStyles(css);
// }

// this.page = 1;
this.total = null;
this.BaseFnt = new iTextPDFUtil().getFont();
},

setDocTempleInfo : function(headerImage, footerImage, footnote, headerPosition, footerPosition, pageSize){
this.headerImage = headerImage;
this.footerImage = footerImage;
this.footnote = footnote;
this.headerPosition = headerPosition;
this.footerPosition = footerPosition;
this.pageSize = pageSize;

},


_loadPDFDoc : function(pdfDoc) {
this.pdfDoc = pdfDoc;

// this.document is used here to create a write in _connectOutputStream()
// then, this.cocument will be reassigned to GeneralPDF
this.document = this.pdfDoc.get();
this.savedDoc = this.document;
this._connectOutputStream();
},

_loadStyles : function(css1) {

/**
* Unsupported Styles
*
*/

// this.styles.loadStyle('value_col_annotation', 'display', 'none');
// this.styles.loadStyle('value_col_annotation', 'visibility',
// 'hidden');
// this.styles.loadTagStyle('td', 'background-color', 'blue;');
// this.styles.loadStyle('label_col', 'width', '50px');
/**
* this.styles.loadStyle('label_col', 'color', 'green'); // Load from
* sheet // TODO: testing var css2 = new SSAQuoteCSS().get();
*
* for ( var className in css2) { if (css2.hasOwnProperty(className)) {
* gs.print(className); var styles = css2[className]; for ( var style in
* styles) { if (styles.hasOwnProperty(style)) {
*
*
* gs.print('Loading className ' + className + ' , Style Attribute '
* +style + ' , Style ' + styles[style] + '\n');
*
* this.styles.loadStyle(className, style, styles[style]); } } } }
*/


},

/**
* Dynamically program PDF content
*/

_generate : function() {
// Open the document for writing
this.document.open();

// Write to the document
this.document.add(this.pdfDoc.body);

// Close the document
this.document.close();
this.writer.close();
},

/**
* This will open the document for writing and run anything we need for the
* stream writer or the iTextPDF API. All of this runs and is prepared
* before any kind of HTML form generation takes place at all. This will
* specifically prepare GeneralPDF for a certain kind of HTML parsing when
* generating the HTML. Which is to parse GeneralFormElement(s) one at a time.
* This creates an API for changing the stream writer or iTextPDF API based
* on GeneralElement types.
*
*
*/

startHTMLParser : function() {
this._loadStyles();

// setValue method on PDFTemplate may be used to add any property
// to the template that can then be read by the header, footer,
// watermark, etc.
if (this.glideRecord) {
this.PDFTemplate.setValue('glideRecord' , this.glideRecord);
}

this.writer.setPageEvent(this.headerImage, this.footerImage, this.footnote, this.headerPosition, this.footerPosition, this.pageSize);

// Add any viewer preferences
//
// Set the Print Scaling
var PdfName = iTextPDFUtil.PdfName;
var pn = new PdfName();
var PRINTSCALING = pn.getPdfName('PRINTSCALING');
var NONE = pn.getPdfName('NONE');
this.writer.addViewerPreference(PRINTSCALING, NONE);

// Open document for writing
this.document.open();

// Since this is for parsing it should not be initialized as part
// of creating a GeneralPDF. Inside this _parse() method is a good
this.htmlWorker = new iTextPDFUtil.HTMLWorker(this.document);

// Use style sheet
//this.htmlWorker.setStyleSheet(this.styles);
//this.htmlWorker.setStyleSheet(["font-family: journal, Times", "border-color:blue", "color:red", "width:100%"]);

// Basically at this point in the form generation process we use
// this.addHTML() while iterating over GeneralFormElement(s) within
// GeneralFormTable.
// Then we just stop the parser with stopHTMLParser() and use get() to
// retrieve the final PDF file ready to be attached or download
},

stopHTMLParser : function() {

// Add all of the elements that have been collected to the document. The pdfElements is null
// for ( var i = 0; i < this.pdfElements.length; i += 1) {
// var element = this.pdfElements[i];
// this.document.add(element);
// }

this.document.close();
this.writer.close();
},

/**
* Automate PDF generation by parsing HTML/CSS
*/

/*
_parse : function() {
var isValid = new GeneralFormJava.GlideXMLUtil()
.isValidHTML(this.pdfDoc.html);

if (!isValid) {
// this.writer.close();

gs.print('HTML is not valid');

// return;
} else {
gs.print('HTML is valid');

// We had to escape the HTML from the WYSIWYG elements to render in
// the UI Page.
// Undo that here so we get the proper render in the PDF.
// TODO: Use the DOM to target just elements that can have escaped
// data
this.pdfDoc.html = GeneralForm2.getStringUtil().unEscapeHTML(
this.pdfDoc.html);

gs.print(this.pdfDoc.html);
}

try {
this._loadStyles();

// Use a template for the page event
//this.writer.setPageEvent(this.PDFTemplate);

// Add any viewer preferences
//
// Set the Print Scaling
var PdfName = iTextPDFUtil.PdfName;
var pn = new PdfName();
this.writer.addViewerPreference(pn.getPdfName('PRINTSCALING'), pn.getPdfName('NONE'));

// Open document for writing
this.document.open();

// Start writing content to the document
var contentReader = new GeneralFormJava.StringReader(
this.pdfDoc.html + '');

// Since this is for parsing it should not be initialized as part
// of creating a GeneralPDF. Inside this _parse() method is a good
this.htmlWorker = new iTextPDFUtil.HTMLWorker(this.document);

// Use style sheet
// htmlWorker.setStyleSheet(this.styles);

// Parse 1
this.htmlWorker.parse(contentReader);

// parse 2
// this.addHTML(this.pdfDoc.html);

this.document.close();
this.writer.close();

} catch (e) {
gs.print('Failed to created PDF Document. Exception: ' + e);
return;
}
},
*/


/**
* This is used to add blocks of HTML anywhere in a PDF document object
*
* @param html
*/

addHTML : function(html) {

var isValid = new GeneralFormJava.GlideXMLUtil().isValidHTML(html);

if (!isValid) {
// this.writer.close();

this.debug.log('HTML is not valid');

// return;
} else {
this.debug.log('HTML is valid');

// We had to escape the HTML from the WYSIWYG elements to render in
// the UI Page.
// Undo that here so we get the proper render in the PDF.
// TODO: Use the DOM to target just elements that can have escaped
// data

// html = GeneralForm2.getStringUtil().unEscapeHTML(html);
html = GeneralFormJava.GlideStringUtil.unEscapeHTML(html);

}

try {
var contentReader = new GeneralFormJava.StringReader(html + '');

// Use style sheet
//this.htmlWorker.setStyleSheet(this.styles);

// Parse 1
//this.htmlWorker.parse(contentReader);

var objects = this.htmlWorker.parseToList(contentReader);

for ( var i = 0; i < objects.size(); i += 1) {
var element = objects.get(i);
this.document.addParagraph(element, this.BaseFnt);
}

} catch (e) {
this.debug.log('Failed to created PDF Document. Exception: ' + e);
this.debug.write();
return;
}
},

addNewPage: function(){
this.document.addNewPage();
},

addCells: function(cells, row_length){
var table = new iTextPDFUtil.PDFTable(row_length);
table.setWidthPercentage(100);
table.setBorderWidth(0);
table.setPadding(0);
table.setSpacing(0);
for(var i=0;i<cells.length;i++){
var row = parseInt(i/row_length);
var font = new iTextPDFUtil().getFont(null, (row == 0) ? 1 :null,(cells[i].color)? new iTextPDFUtil.Color((cells[i].color == 'text-success') ? 0xFF5CB85C: 0xFFD9534F) : null, null);
var pdfCell = new iTextPDFUtil.PDFCell(new iTextPDFUtil.PDFPhrase(cells[i].text, font));
if(row%2 == 0)
pdfCell.setBackgroundColor();
pdfCell.setCellProperties();
table.addCell(pdfCell);
}
this.document.add(table);
},

addSVG: function(svg, position){
svg = svg.replaceAll("[^\\x20-\\x7e]", "");
new iTextPDFUtil.SvgToPdf().createPdf(this.writer, this.document, svg, position);
},

_connectOutputStream : function() {
try {

//this.writer = iTextPDFUtil.PdfWriter.getInstance(this.document, this.outputStream);
this.writer = new iTextPDFUtil.PdfWriter(this.document, this.outputStream);

this.writer.setStrictImageSequence(true);

} catch (e) {
gs.log(e, 'DocumentException');
}
},

_properties : function(document) {
document.addAuthor('');
document.addCreationDate();
document.addProducer();
document.addCreator('');
document.addTitle('');
},

_header : function(document) {
// TODO: Simple example
},

setPDFDoc : function(pdfDoc) {
this._loadPDFDoc(pdfDoc);
},

setProperties : function(properties) {
this._properties = properties;
},

setHeader : function(header) {
//GeneralPDF.prototype._header.apply(this, [this.writer, this.document]);

},

setFooter : function(footer) {
//GeneralPDF.prototype._footer.apply(this, [this.writer, this.document]);
},

setWatermark : function(watermark) {
GeneralPDF.prototype._watermark = watermark;
},

/**
* Returns the input stream from the output document.
*
* @returns {ByteArrayInputStream}
*/

get : function() {
var ret = null;

if (this.document) {

/**
* if (this.pdfDoc.html) { this._parse(); } else if
* (this.pdfDoc.body) { this._generate(); }
*/


ret = new GeneralFormJava.ByteArrayInputStream(this.outputStream
.toByteArray());
}

return ret;
},

type : 'GeneralPDF'
};

/**
* Commit the generated PDF document as an attachment in the database
* @param {GeneralPDF.Attachment}
* sa @ return {String} sys_id for the newly created attachment
*/

GeneralPDF.attach = function(sa) {
var SysAttachment = new GeneralFormJava.SysAttachment();
var type = GeneralPDF.ATTACHMENT_TYPE;
if (sa.type) {
type = sa.type;
}

var aId = SysAttachment.write(sa.tableId, sa.tableName, sa.name, type, sa.body);
return aId + '';
};

/**
* Interface for an attachment file.
* @param tableId
* @param tableName
* @param name
* @param body
* @param type
*/

GeneralPDF.Attachment = function(tableId, tableName, name, body, type) {
this.tableId = '';
this.tableName = '';
this.name = '';
this.type = null;
this.body = null;
this.html = null;

this.setTableId = function(ti) {
this.tableId = ti;
};
this.setTableName = function(tn) {
this.tableName = tn;
};
this.setName = function(na) {
this.name = na;
};
this.setType = function(ty) {
this.type = ty;
};
this.setBody = function(bo) {
this.body = bo;
};

if (tableId) {
this.setTableId(tableId);
}
if (tableName) {
this.setTableName(tableName);
}
if (name) {
this.setName(name);
}
if (type) {
this.setType(type);
}
if (body) {
this.setBody(body);
}
};

/**
* Create a PDF Document object set the body/content page orientation and
* margins for the document.
* @param landscape
* @param meta
* @param body
*/

GeneralPDF.Document = function(landscape, meta, body, html, pageSize, headerImage) {

var ps = new iTextPDFUtil.PageSize();

this.rectangle = ps.getPageSize(pageSize);

this.landscape = false;

var leftMargin = 72;
var rightMargin = 72;
var topMargin = 36;
var bottomMargin = 36;
var headerImageHeight = 50;

// This is the default body that just ensures we do get a complete PDF
// Document
// if you call this object and do nothing to it. Setting the actual body
// content
// is the responsibility of the caller.
// this inline function won't be executed
this.body = function(document) {
if (document.isNil()){
gs.logError('GeneralPDF() Input parameter "document" should not be null.');
}
var table = new iTextPDFUtil.PDFTable(1);
table.setBorderWidth(0);
table.setPadding(0);
table.setSpacing(0);
table.addCell("All systems are a go! Default body, Replace Me");
document.add(table);
};

//this.html;

this.setLandscape = function(la) {
this.landscape = la;
};

this.setBody = function(bo) {
this.body = bo;
};

this.setHTML = function(html) {
this.html = html;
};

if (landscape) {
this.setLandscape(landscape);
}

if (body) {
this.setBody(body);
}

if (html) {
this.setHTML(html);
}

this.get = function() {
var ret = null;

if (headerImage) {
ret = new iTextPDFUtil.Document(this.rectangle, leftMargin, rightMargin, topMargin + headerImageHeight, bottomMargin);
} else {

ret = new iTextPDFUtil.Document(this.rectangle, leftMargin, rightMargin, topMargin, bottomMargin);
}

return ret;
};

this.type = 'GeneralPDF.Document';
};