// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

// default print style
_p.def_print_style_body = "html, body, div, span, td, p { \
		font-family: inherit; \
		font-size: inherit; \
	}\
	.page-settings {\
		font-family: Helvetica, 'Open Sans', sans-serif;\
		font-size: 9pt;\
	}\
	pre { margin:0; padding:0;}";

_p.def_print_style_other = "\n.simpletable, .noborder { \
		border-collapse: collapse;\
		margin-bottom: 10px;\
	}\
	.simpletable td {\
		border: 1pt solid #777;\
		vertical-align: top;\
		padding: 4px;\
	}\
	.noborder td {\
		vertical-align: top;\
	}";

_p.go = function(html) {
	var w = _p.preview(html);
	w.print();
	w.close();
}

_p.preview = function(html) {
	var w = window.open();
	if(!w) {
		msgprint(__("Please enable pop-ups"));
		return;
	}
	w.document.write(html);
	w.document.close();
	return w
}

_f.get_value = function(dt, dn, fn) {
	if(locals[dt] && locals[dt][dn])
		return locals[dt][dn][fn];
}

// _p can be referenced as this inside $.extend
$.extend(_p, {
	show_dialog: function() {
		if(!_p.dialog) {
			_p.make_dialog();
		}
		_p.dialog.show();
	},

	make_dialog: function() {
		// Prepare Dialog Box Layout
		var dialog = new frappe.ui.Dialog({
			title: "Print Formats",
			fields: [
				{fieldtype:"Select", label:"Print Format", fieldname:"print_format", reqd:1},
				{fieldtype:"Check", label:"No Letter Head", fieldname:"no_letterhead"},
				{fieldtype:"HTML", options: '<p style="text-align: right;">\
					<button class="btn btn-primary btn-print">Print</button>\
					<button class="btn btn-default btn-preview">Preview</button>\
				</p>'},
			]
		});

		dialog.$wrapper.find(".btn-print").click(function() {
			var args = dialog.get_values();
			_p.build(
				args.print_format, // fmtname
				_p.go, // onload
				args.no_letterhead // no_letterhead
			);
		});

		dialog.$wrapper.find(".btn-preview").click(function() {
			var args = dialog.get_values();
			_p.build(
				args.print_format, // fmtname
				_p.preview, // onload
				args.no_letterhead // no_letterhead
			);
		});

		dialog.on_page_show = function() {
			var $print = dialog.fields_dict.print_format.$input;
			$print.empty().add_options(cur_frm.print_preview.print_formats);

			if(cur_frm.$print_view_select && cur_frm.$print_view_select.val())
				$print.val(cur_frm.$print_view_select.val());
		}

		_p.dialog = dialog;
	},

	// Define formats dict
	formats: {},

	/* args dict can contain:
			+ fmtname --> print format name
			+ onload
			+ no_letterhead
			+ only_body
	*/
	build: function(fmtname, onload, no_letterhead, only_body, no_heading) {
		if(!fmtname) {
			fmtname= "Standard";
		}

		args = {
			fmtname: fmtname,
			onload: onload,
			no_letterhead: no_letterhead,
			only_body: only_body
		};

		if(!cur_frm) {
			msgprint(__("No document selected"));
			return;
		}

		if(!frappe.model.can_print(cur_frm.doctype, cur_frm)) {
			msgprint(__("You are not allowed to print this document"));
			return;
		}

		// Get current doc (record)
		var doc = locals[cur_frm.doctype][cur_frm.docname];
		if(args.fmtname == 'Standard') {
			args.onload(_p.render({
				body: _p.print_std(args.no_letterhead, no_heading),
				style: _p.print_style,
				doc: doc,
				title: doc.name,
				no_letterhead: args.no_letterhead,
				no_heading: no_heading,
				only_body: args.only_body
			}));
		} else {
			var print_format_doc = locals["Print Format"][args.fmtname];
			if(!print_format_doc) {
				msgprint(__("Unknown Print Format: {0}", [args.fmtname]));
				return;
			}
			args.onload(_p.render({
				body: print_format_doc.html,
				style: '',
				doc: doc,
				title: doc.name,
				no_letterhead: args.no_letterhead,
				no_heading: no_heading,
				only_body: args.only_body
			}));
		}
	},

	render: function(args) {
		var container = document.createElement('div');
		var stat = '';

		if(!args.no_heading) {
			// if draft/archived, show draft/archived banner
			stat += _p.show_draft(args);
			stat += _p.show_archived(args);
			stat += _p.show_cancelled(args);
		}

		// Append args.body's content as a child of container
		container.innerHTML = args.body;

		// Show letterhead?
		_p.show_letterhead(container, args);

		_p.run_embedded_js(container, args.doc);

		var style = _p.consolidate_css(container, args);

		_p.render_header_on_break(container, args);

		return _p.render_final(style, stat, container, args);
	},


	head_banner_format: function() {
		return "\
			<div style = '\
					text-align: center; \
					padding: 8px; \
					background-color: #CCC;'> \
				<div style = '\
						font-size: 20px; \
						font-weight: bold;'>\
					{{HEAD}}\
				</div>\
				{{DESCRIPTION}}\
			</div>"
	},

	/*
		Check if doc's status is not submitted (docstatus == 0)
		and submission is pending

		Display draft in header if true
	*/
	show_draft: function(args) {
		var is_doctype_submittable = 0;
		var plist = locals['DocPerm'];
		for(var perm in plist) {
			var p = plist[perm];
			if((p.parent==args.doc.doctype) && (p.submit==1)){
				is_doctype_submittable = 1;
				break;
			}
		}

		if(args.doc && cint(args.doc.docstatus)==0 && is_doctype_submittable) {
			draft = _p.head_banner_format();
			draft = draft.replace("{{HEAD}}", "DRAFT");
			draft = draft.replace("{{DESCRIPTION}}", "This box will go away after the document is submitted.");
			return draft;
		} else {
			return "";
		}
	},


	/*
		Check if doc is archived
		Display archived in header if true
	*/
	show_archived: function(args) {
		if(args.doc && args.doc.__archived) {
			archived = _p.head_banner_format();
			archived = archived.replace("{{HEAD}}", "ARCHIVED");
			archived = archived.replace("{{DESCRIPTION}}", "You must restore this document to make it editable.");
			return archived;
		} else {
			return "";
		}
	},


	/*
		Check if doc is cancelled
		Display cancelled in header if true
	*/
	show_cancelled: function(args) {
		if(args.doc && args.doc.docstatus==2) {
			cancelled = _p.head_banner_format();
			cancelled = cancelled.replace("{{HEAD}}", "CANCELLED");
			cancelled = cancelled.replace("{{DESCRIPTION}}", "You must amend this document to make it editable.");
			return cancelled;
		} else {
			return "";
		}
	},


	consolidate_css: function(container, args) {
		// Extract <style> content from container
		var body_style = '';
		var style_list = container.getElementsByTagName('style');
		while(style_list && style_list.length>0) {
			for(i in style_list) {
				if(style_list[i] && style_list[i].innerHTML) {
					body_style += style_list[i].innerHTML;
					var parent = style_list[i].parentNode;
					if(parent) {
						parent.removeChild(style_list[i]);
					} else {
						container.removeChild(style_list[i]);
					}
				}
			}
			style_list = container.getElementsByTagName('style');
		}

		// Concatenate all styles
		style_concat =  (args.only_body ? '' : _p.def_print_style_body)
				+ _p.def_print_style_other + args.style + body_style;

		return style_concat;
	},


	// This is used to calculate and substitude values in the HTML
	run_embedded_js: function(container, doc) {
		var script_list = $(container).find("script");

		for(var i=0, j=script_list.length; i<j; i++) {
			var element = script_list[i];
			var code = element.innerHTML;
			try {
				var new_html = code ? (eval(code) || "") : "";
			} catch(e) {
				console.log("Error in Custom Script:" + e + "\n" + code);
				console.trace(e);
				throw e;
			}
			if(in_list(["string", "number"], typeof new_html)) {
				$(element).replaceWith(this.add_span(new_html + ""));
			}
		}

		// remove scripts once executed
		$(container).find("script").remove();
	},

	add_span: function(html) {
		var tags = ["<span", "<p", "<div", "<br", "<table"];
		var match = false;
		for(var i=0; i<tags.length; i++) {
			if(html.match(tags[i])) {
				match = true;
				break;
			}
		}

		if(!match) {
			html = "<span>" + html + "</span>";
		}

		return html;
	},


	// Attach letterhead at top of container
	show_letterhead: function(container, args) {
		if(!args.no_letterhead) {
			container.innerHTML = '<div style="max-width: 100%">'
				+ _p.get_letter_head() + '</div>'
				+ container.innerHTML;
		}
	},


	render_header_on_break: function(container, args) {
		var page_set = container.getElementsByClassName('page-settings');
		if(page_set.length) {
			for(var i = 0; i < page_set.length; i++) {
				var tmp = '';
				// if draft/archived, show draft/archived banner
				tmp += _p.show_draft(args);
				tmp += _p.show_archived(args);
				_p.show_letterhead(page_set[i], args);
				page_set[i].innerHTML = tmp + page_set[i].innerHTML;
			}
		}
	},


	// called by _p.render for final render of print
	render_final: function(style, stat, container, args) {
		if(!args.only_body) {
			var header = '<!DOCTYPE html>\
<html>\
	<head>\
		<meta charset="utf-8" />\
		<title>' + args.title + '</title>\
		<style>' + style + '</style>\
	</head>\
	<body>';
			var footer = '\
	</body>\
</html>';
		} else {
			var header = '';
			var footer = '';
		}
		var finished =  header
			+ '<div class="page-settings">'
			+ stat
			+ container.innerHTML
			+ '</div>'
			+ footer;


		// replace relative links by absolute links
		var prefix = window.location.href.split("desk")[0]
		// find unique matches
		var matches = $.unique(finished.match(/src=['"]([^'"]*)['"]/g) || []);

		$.each(matches, function(i, v) {
			if(v.substr(0,4)=="src=") {
				var v = v.substr(5, v.length-6);
				if(v.substr(0,4)!="http") {
					finished = finished.split(v).join(prefix + lstrip(v, "/"));
				}

			}
		});

		return finished;
	},


	// fetches letter head from current doc or control panel
	get_letter_head: function() {
		var lh = '';
		if(cur_frm.doc.letter_head) {
			lh = cstr(frappe.boot.letter_heads[cur_frm.doc.letter_head]);
		} else if (frappe.boot.sysdefaults.default_letter_head_content) {
			lh = frappe.boot.sysdefaults.default_letter_head_content;
		}
		return lh;
	},

	// common print style setting
	print_style: "\
		.datalabelcell { \
			padding: 2px 0px; \
			width: 38%; \
			vertical-align: top; \
			} \
		.datainputcell { \
			padding: 2px 0px; \
			width: 62%; \
			text-align: left; \
			}\
		.sectionHeading { \
			font-size: 16px; \
			font-weight: bold; \
			margin: 8px 0px; \
			} \
		.columnHeading { \
			font-size: 14px; \
			font-weight: bold; \
			margin: 8px 0px; \
			}",

	print_std: function(no_letterhead, no_heading) {
		// Get doctype, docname, layout for a doctype
		var docname = cur_frm.docname;
		var doctype = cur_frm.doctype;
		var data = frappe.get_children("DocType", doctype, "fields");
		var layout = _p.add_layout(doctype);
		this.pf_list = [layout];
		var me = this;
		me.layout = layout;

		$.extend(this, {
			build_head: function(data, doctype, docname) {
				// Heading
				var h1_style = {
					fontSize: '22px',
					marginBottom: '8px'
				}
				var h1 = $a(me.layout.cur_row.header, 'h1', '', h1_style);

				// Get print heading
				if (cur_frm.pformat[docname]) {
					// first check in cur_frm.pformat
					h1.innerHTML = cur_frm.pformat[docname];
				} else {
					// then check if select print heading exists and has a value
					var val = null;
					for (var i = 0; i < data.length; i++) {
						if (data[i].fieldname === 'select_print_heading') {
							val = _f.get_value(doctype, docname, data[i].fieldname);
							break;
						}
					}
					// if not, just have doctype has heading
					h1.innerHTML = val ? val : __(doctype);
				}

				var h2_style = {
					fontSize: '16px',
					color: '#888',
					marginBottom: '8px',
					paddingBottom: '8px',
					borderBottom: (me.layout.with_border ? '0px' :
						'1px solid #000')
				}
				var h2 = $a(me.layout.cur_row.header, 'div', '', h2_style);
				h2.innerHTML = docname;

				if(cur_frm.state_fieldname && !cur_frm.fields_dict[cur_frm.state_fieldname].df.print_hide) {
					$a(h2, 'br');
					var span = $a(h2, 'span', '',
						{padding: "3px", color: "#fff", backgroundColor: "#777",
							display:"inline-block"});
					span.innerHTML = cur_frm.doc[cur_frm.state_fieldname];
				}
			},

			build_data: function(data, doctype, docname) {
				// Start with a row and a cell in that row
				if(data[0] && data[0].fieldtype != "Section Break") {
					me.layout.addrow();
					if(data[0].fieldtype != "Column Break") {
						me.layout.addcell();
					}
				}

				$.extend(this, {
					generate_custom_html: function(field, doctype, docname) {
						var container = $a(me.layout.cur_cell, 'div');
						container.innerHTML = cur_frm.pformat[field.fieldname](locals[doctype][docname]);
					},

					render_normal: function(field, data, i) {
						switch(field.fieldtype) {
							case 'Fold': break;
							case 'Section Break':
								me.layout.addrow();

								// Add column if no column break after this field
								if(data[i+1] && data[i+1].fieldtype !=
										'Column Break') {
									me.layout.addcell();
								}
								break;

							case 'Column Break':
								me.layout.addcell(field.width, field.label);
								break;

							case 'Table':
								var table = print_table(
										doctype, // dt
										docname, // dn
										field.fieldname,
										field.options, // tabletype
										null, // cols
										null, // head_labels
										null, // widths
										null); // condition
								me.layout = _p.print_std_add_table(table, me.layout, me.pf_list, doctype, no_letterhead);
								break;

							case 'HTML':
								var div = $a(me.layout.cur_cell, 'div');
								div.innerHTML = cstr(field.options);
								break;

							case 'Code':
								var div = $a(me.layout.cur_cell, 'div');
								var val = _f.get_value(doctype, docname,
									field.fieldname);
								div.innerHTML = '<div>' + __(field.label) +
									': </div><pre style="font-family: Courier, Fixed;">' + (val ? val : '') +
									'</pre>';
								break;

							case 'Text Editor':
								var div = $a(me.layout.cur_cell, 'div');
								var val = _f.get_value(doctype, docname,
									field.fieldname);
								div.innerHTML = val ? val : '';
								break;

							default:
								// Add Cell Data
								_p.print_std_add_field(doctype, docname, field, me.layout);
								break;
						}
					}
				});

				// Then build each field
				for(var i = 0; i < data.length; i++) {
					var fieldname = data[i].fieldname ? data[i].fieldname :
						data[i].label;
					var field = fieldname ?
						frappe.meta.get_docfield(doctype, fieldname, docname) : data[i];
					if(!field.print_hide) {
						if(cur_frm.pformat[field.fieldname]) {
							// If there is a custom method to generate the HTML, then use it
							this.generate_custom_html(field, doctype, docname);
						} else {
							// Do the normal rendering
							this.render_normal(field, data, i);
						}
					}
				}
				me.layout.close_borders();
			},

			build_html: function() {
				var html = '';
				for(var i = 0; i < me.pf_list.length; i++) {
					if(me.pf_list[i].wrapper) {
						html += me.pf_list[i].wrapper.innerHTML;
					} else if(me.pf_list[i].innerHTML) {
						html += me.pf_list[i].innerHTML;
					} else {
						html += me.pf_list[i];
					}
				}
				this.pf_list = [];
				return html;
			}
		});

		if(!no_heading) {
			this.build_head(data, doctype, docname);
		}

		this.build_data(data, doctype, docname);

		var html = this.build_html();
		return html;
	},

	add_layout: function(doctype) {
		var layout = new Layout();
		layout.addrow();

		if(locals['DocType'][doctype].print_outline == 'Yes') {
			layout.with_border = 1
		}

		return layout;
	},

	print_std_add_table: function(t, layout, pf_list, dt, no_letterhead) {
		if(t.appendChild) {
			// If only one table is passed
			layout.cur_cell.appendChild(t);
		} else {
			page_break = '\n\
				<div style = "page-break-after: always;" \
				class = "page_break"></div><div class="page-settings"></div>';

			// If a list of tables is passed
			for(var i = 0; i < t.length-1; i++) {
				// add to current page
				layout.cur_cell.appendChild(t[i]);
				layout.close_borders();

				pf_list.push(page_break);

				// Create new page
				layout = _p.add_layout(dt, no_letterhead);
				pf_list.push(layout);

				layout.addrow();
				layout.addcell();

				var div = $a(layout.cur_cell, 'div');
				div.innerHTML = 'Continued from previous page...';
				div.style.padding = '4px';
			}

			// Append last table
			layout.cur_cell.appendChild(t[t.length-1]);
		}
		return layout;
	},

	print_std_add_field: function(dt, dn, f, layout) {
		var val = _f.get_value(dt, dn, f.fieldname);
		if(f.fieldtype!='Button') {
			if(val || in_list(['Float', 'Int', 'Currency'], f.fieldtype)) {
				// If value or a numeric type then proceed

				// Add field table
				row = _p.field_tab(layout.cur_cell);

				// Add label
				row.cells[0].innerHTML = __(f.label ? f.label : f.fieldname);
				row.cells[1].innerHTML = frappe.format(val, f, {for_print: true});

				// left align currency in normal display
				if(f.fieldtype == 'Currency') {
					$y(row.cells[1], { textAlign: 'left' });
				}

			}
		}
	},

	field_tab: function(layout_cell) {
		var tab = $a(layout_cell, 'table', '', {width:'100%'});
		var row = tab.insertRow(0);
		_p.row = row; // Don't know this line's purpose
		row.insertCell(0);
		row.insertCell(1);
		row.cells[0].className = 'datalabelcell';
		row.cells[0].style.width = "38%";
		row.cells[1].className = 'datainputcell';
		return row;
	}
});
