/*
 * printThis v1.9.0
 * @desc Printing plug-in for jQuery
 * @author Jason Day
 *
 * Resources (based on) :
 *              jPrintArea: http://plugins.jquery.com/project/jPrintArea
 *              jqPrint: https://github.com/permanenttourist/jquery.jqprint
 *              Ben Nadal: http://www.bennadel.com/blog/1591-Ask-Ben-Print-Part-Of-A-Web-Page-With-jQuery.htm
 *
 * Licensed under the MIT licence:
 *              http://www.opensource.org/licenses/mit-license.php
 *
 * (c) Jason Day 2015
 *
 * Usage:
 *
 *  $("#mySelector").printThis({
 *      debug: false,               * show the iframe for debugging
 *      importCSS: true,            * import page CSS
 *      importStyle: false,         * import style tags
 *      printContainer: true,       * grab outer container as well as the contents of the selector
 *      loadCSS: "path/to/my.css",  * path to additional css file - us an array [] for multiple
 *      pageTitle: "",              * add title to print page
 *      removeInline: false,        * remove all inline styles from print elements
 *      printDelay: 333,            * variable print delay
 *      header: null,               * prefix to html
 *      footer: null,               * postfix to html
 *      base: false,                * preserve the BASE tag, or accept a string for the URL
 *      formValues: true            * preserve input/form values
 *      canvas: false               * copy canvas elements (experimental)
 *      doctypeString: '...'        * enter a different doctype for older markup
 *  });
 *
 * Notes:
 *  - the loadCSS will load additional css (with or without @media print) into the iframe, adjusting layout
 *
 */
( function ( $ ) {
	var opt;
	$.fn.printThis = function ( options ) {
		opt = $.extend( {}, $.fn.printThis.defaults, options );
		var $element = this instanceof jQuery ? this : $( this );

		var strFrameName = 'printThis-' + new Date().getTime();

		if ( window.location.hostname !== document.domain && navigator.userAgent.match( /msie/i ) ) {
			// Ugly IE hacks due to IE not inheriting document.domain from parent
			// checks if document.domain is set by comparing the host name against document.domain
			var iframeSrc =
				'javascript:document.write("<head><script>document.domain=\\"' +
				document.domain +
				'\\";</s' +
				'cript></head><body></body>")';
			var printI = document.createElement( 'iframe' );
			printI.name = 'printIframe';
			printI.id = strFrameName;
			printI.className = 'MSIE';
			document.body.appendChild( printI );
			printI.src = iframeSrc;
		} else {
			// other browsers inherit document.domain, and IE works if document.domain is not explicitly set
			var $frame = $( "<iframe id='" + strFrameName + "' name='printIframe' />" );
			$frame.appendTo( 'body' );
		}

		var $iframe = $( '#' + strFrameName );

		// show frame if in debug mode
		if ( ! opt.debug )
			$iframe.css( {
				position: 'absolute',
				width: '0px',
				height: '0px',
				left: '-600px',
				top: '-600px',
			} );

		// $iframe.ready() and $iframe.load were inconsistent between browsers
		setTimeout( function () {
			// Add doctype to fix the style difference between printing and render
			function setDocType( $iframe, doctype ) {
				var win, doc;
				win = $iframe.get( 0 );
				win = win.contentWindow || win.contentDocument || win;
				doc = win.document || win.contentDocument || win;
				doc.open();
				doc.write( doctype );
				doc.close();
			}
			if ( opt.doctypeString ) {
				setDocType( $iframe, opt.doctypeString );
			}

			var $doc = $iframe.contents(),
				$head = $doc.find( 'head' ),
				$body = $doc.find( 'body' ),
				$base = $( 'base' ),
				baseURL;

			// add base tag to ensure elements use the parent domain
			if ( opt.base === true && $base.length > 0 ) {
				// take the base tag from the original page
				baseURL = $base.attr( 'href' );
			} else if ( typeof opt.base === 'string' ) {
				// An exact base string is provided
				baseURL = opt.base;
			} else {
				// Use the page URL as the base
				baseURL = document.location.protocol + '//' + document.location.host;
			}

			$head.append( '<base href="' + baseURL + '">' );

			// import page stylesheets
			if ( opt.importCSS )
				$( 'link[rel=stylesheet]' ).each( function () {
					var href = $( this ).attr( 'href' );
					if ( href ) {
						var media = $( this ).attr( 'media' ) || 'all';
						$head.append(
							"<link type='text/css' rel='stylesheet' href='" + href + "' media='" + media + "'>"
						);
					}
				} );

			// import style tags
			if ( opt.importStyle )
				$( 'style' ).each( function () {
					$( this ).clone().appendTo( $head );
				} );

			// add title of the page
			if ( opt.pageTitle ) $head.append( '<title>' + opt.pageTitle + '</title>' );

			// import additional stylesheet(s)
			if ( opt.loadCSS ) {
				if ( $.isArray( opt.loadCSS ) ) {
					jQuery.each( opt.loadCSS, function ( index, value ) {
						$head.append( "<link type='text/css' rel='stylesheet' href='" + this + "'>" );
					} );
				} else {
					$head.append( "<link type='text/css' rel='stylesheet' href='" + opt.loadCSS + "'>" );
				}
			}

			// print header
			if ( opt.header ) $body.append( opt.header );

			if ( opt.canvas ) {
				// add canvas data-ids for easy access after the cloning.
				var canvasId = 0;
				$element.find( 'canvas' ).each( function () {
					$( this ).attr( 'data-printthis', canvasId++ );
				} );
			}

			// grab $.selector as container
			if ( opt.printContainer ) $body.append( $element.outer() );
			// otherwise just print interior elements of container
			else
				$element.each( function () {
					$body.append( $( this ).html() );
				} );

			if ( opt.canvas ) {
				// Re-draw new canvases by referencing the originals
				$body.find( 'canvas' ).each( function () {
					var cid = $( this ).data( 'printthis' ),
						$src = $( '[data-printthis="' + cid + '"]' );

					this.getContext( '2d' ).drawImage( $src[ 0 ], 0, 0 );

					// Remove the mark-up from the original
					$src.removeData( 'printthis' );
				} );
			}

			// capture form/field values
			if ( opt.formValues ) {
				// loop through inputs
				var $input = $element.find( 'input' );
				if ( $input.length ) {
					$input.each( function () {
						var $this = $( this ),
							$name = $( this ).attr( 'name' ),
							$checker = $this.is( ':checkbox' ) || $this.is( ':radio' ),
							$iframeInput = $doc.find( 'input[name="' + $name + '"]' ),
							$value = $this.val();

						// order matters here
						if ( ! $checker ) {
							$iframeInput.val( $value );
						} else if ( $this.is( ':checked' ) ) {
							if ( $this.is( ':checkbox' ) ) {
								$iframeInput.attr( 'checked', 'checked' );
							} else if ( $this.is( ':radio' ) ) {
								$doc
									.find( 'input[name="' + $name + '"][value="' + $value + '"]' )
									.attr( 'checked', 'checked' );
							}
						}
					} );
				}

				// loop through selects
				var $select = $element.find( 'select' );
				if ( $select.length ) {
					$select.each( function () {
						var $this = $( this ),
							$name = $( this ).attr( 'name' ),
							$value = $this.val();
						$doc.find( 'select[name="' + $name + '"]' ).val( $value );
					} );
				}

				// loop through textareas
				var $textarea = $element.find( 'textarea' );
				if ( $textarea.length ) {
					$textarea.each( function () {
						var $this = $( this ),
							$name = $( this ).attr( 'name' ),
							$value = $this.val();
						$doc.find( 'textarea[name="' + $name + '"]' ).val( $value );
					} );
				}
			} // end capture form/field values

			// remove inline styles
			if ( opt.removeInline ) {
				// $.removeAttr available jQuery 1.7+
				if ( $.isFunction( $.removeAttr ) ) {
					$doc.find( 'body *' ).removeAttr( 'style' );
				} else {
					$doc.find( 'body *' ).attr( 'style', '' );
				}
			}

			// print "footer"
			if ( opt.footer ) $body.append( opt.footer );

			setTimeout( function () {
				if ( $iframe.hasClass( 'MSIE' ) ) {
					// check if the iframe was created with the ugly hack
					// and perform another ugly hack out of neccessity
					window.frames[ 'printIframe' ].focus();
					$head.append( '<script>  window.print(); </s' + 'cript>' );
				} else {
					// proper method
					if ( document.queryCommandSupported( 'print' ) ) {
						$iframe[ 0 ].contentWindow.document.execCommand( 'print', false, null );
					} else {
						$iframe[ 0 ].contentWindow.focus();
						$iframe[ 0 ].contentWindow.print();
					}
				}

				// remove iframe after print
				if ( ! opt.debug ) {
					setTimeout( function () {
						$iframe.remove();
					}, 1000 );
				}
			}, opt.printDelay );
		}, 333 );
	};

	// defaults
	$.fn.printThis.defaults = {
		debug: false, // show the iframe for debugging
		importCSS: true, // import parent page css
		importStyle: false, // import style tags
		printContainer: true, // print outer container/$.selector
		loadCSS: '', // load an additional css file - load multiple stylesheets with an array []
		pageTitle: '', // add title to print page
		removeInline: false, // remove all inline styles
		printDelay: 333, // variable print delay
		header: null, // prefix to html
		footer: null, // postfix to html
		formValues: true, // preserve input/form values
		canvas: false, // Copy canvas content (experimental)
		base: false, // preserve the BASE tag, or accept a string for the URL
		doctypeString: '<!DOCTYPE html>', // html doctype
	};

	// $.selector container
	jQuery.fn.outer = function () {
		return $( $( '<div></div>' ).html( this.clone() ) ).html();
	};
} )( jQuery );
