/* global jsPDF, rasterizeHTML, html2canvas */
/**
 * jsPDF addHTML PlugIn
 * Copyright (c) 2014 Diego Casorran
 *
 * Licensed under the MIT License.
 * http://opensource.org/licenses/mit-license
 */

(function (jsPDFAPI) {
    'use strict';

    /**
     * Renders an HTML element to canvas object which added to the PDF
     *
     * This feature requires [html2canvas](https://github.com/niklasvh/html2canvas)
     * or [rasterizeHTML](https://github.com/cburgmer/rasterizeHTML.js)
     *
     * @returns {jsPDF}
     * @name addHTML
     * @param element {Mixed} HTML Element, or anything supported by html2canvas.
     * @param x {Number} starting X coordinate in jsPDF instance's declared units.
     * @param y {Number} starting Y coordinate in jsPDF instance's declared units.
     * @param options {Object} Additional options, check the code below.
     * @param callback {Function} to call when the rendering has finished.
     * NOTE: Every parameter is optional except 'element' and 'callback', in such
     *       case the image is positioned at 0x0 covering the whole PDF document
     *       size. Ie, to easily take screenshots of webpages saving them to PDF.
     * @deprecated This is being replace with a vector-supporting API. See
     * [this link](https://cdn.rawgit.com/MrRio/jsPDF/master/examples/html2pdf/showcase_supported_html.html)
     */
    jsPDFAPI.addHTML = function (element, x, y, options, callback) {
        'use strict';

        if(typeof html2canvas === 'undefined' && typeof rasterizeHTML === 'undefined')
            throw new Error('You need either '
                +'https://github.com/niklasvh/html2canvas'
                +' or https://github.com/cburgmer/rasterizeHTML.js');

        if(typeof x !== 'number') {
            options = x;
            callback = y;
        }

        if(typeof options === 'function') {
            callback = options;
            options = null;
        }


        if(typeof callback !== 'function') {
            callback = function () {};
        }

        var I = this.internal, K = I.scaleFactor, W = I.pageSize.getWidth(), H = I.pageSize.getHeight();

        options = options || {};
        options.onrendered = function(obj) {
            x = parseInt(x) || 0;
            y = parseInt(y) || 0;
            var dim = options.dim || {};
            var margin = Object.assign({top: 0, right: 0, bottom: 0, left: 0, useFor: 'content'}, options.margin);
            var h = dim.h || Math.min(H,obj.height/K);
            var w = dim.w || Math.min(W,obj.width/K) - x;

            var format = options.format || 'JPEG';
            var imageCompression = options.imageCompression || 'SLOW';
            
            var notFittingHeight = obj.height > (H - margin.top - margin.bottom);

            if(notFittingHeight && options.pagesplit) {
                var cropArea = function (parmObj, parmX, parmY, parmWidth, parmHeight) {
                    var canvas = document.createElement('canvas');
                    canvas.height = parmHeight;
                    canvas.width = parmWidth;
                    var ctx = canvas.getContext('2d');
                    ctx.mozImageSmoothingEnabled = false;
                    ctx.webkitImageSmoothingEnabled = false;
                    ctx.msImageSmoothingEnabled = false;
                    ctx.imageSmoothingEnabled = false;
                    ctx.fillStyle = options.backgroundColor || '#ffffff';
                    ctx.fillRect(0,0,parmWidth,parmHeight);
                    ctx.drawImage(parmObj,parmX,parmY,parmWidth,parmHeight,0,0,parmWidth,parmHeight);
                    return canvas;
                };

                var crop = function() {
                    var cy = 0;
                    var cx = 0;
                    var position = {};
                    var isOverWide = false;
                    var width; 
                    var height; 
                    var canvas;
                    var args;
                    while(1) {
                        cx = 0;
                        position.top = (cy !== 0) ? margin.top: y;
                        position.left = (cy !== 0) ? margin.left: x;
                        isOverWide = (W - margin.left - margin.right)*K < obj.width;
                        if (margin.useFor === "content") {
                            if (cy === 0) {
                                width = Math.min((W - margin.left)*K,obj.width);
                                height = Math.min((H - margin.top)*K,obj.height - cy);
                            } else {
                                width = Math.min((W)*K,obj.width);
                                height = Math.min((H)*K,obj.height - cy);
                                position.top = 0;
                            }
                        } else {
                            width = Math.min((W - margin.left - margin.right)*K,obj.width);
                            height = Math.min((H - margin.bottom - margin.top)*K,obj.height - cy);
                        }
                        if (isOverWide) {
                            while (1) {
                                if (margin.useFor === "content") {
                                    if (cx === 0) {
                                        width = Math.min((W - margin.left)*K,obj.width);
                                    } else {
                                        width = Math.min((W)*K,obj.width - cx);
                                        position.left = 0;
                                    }
                                }
                                canvas = cropArea(obj, cx, cy, width, height);
                                args = [canvas, position.left,position.top,canvas.width/K,canvas.height/K, format,null,imageCompression];
                                this.addImage.apply(this, args);
                                cx += width;
                                if (cx >= obj.width) {
                                    break;
                                }
                                this.addPage();    
                            }
                        } else {
                            canvas = cropArea(obj, 0, cy, width, height);
                            args = [canvas, position.left,position.top,canvas.width/K,canvas.height/K, format,null,imageCompression];
                            this.addImage.apply(this, args);
                        }
                        cy += height;
                        if(cy >= obj.height) {
                            break;
                        }
                        this.addPage();
                    }
                    callback(w,cy,null,args);
                }.bind(this);
                if(obj.nodeName === 'CANVAS') {
                    var img = new Image();
                    img.onload = crop;
                    img.src = obj.toDataURL("image/png");
                    obj = img;
                } else {
                    crop();
                }
            } else {
                var alias = Math.random().toString(35);
                var args = [obj, x,y,w,h, format,alias,imageCompression];

                this.addImage.apply(this, args);

                callback(w,h,alias,args);
            }
        }.bind(this);

        if(typeof html2canvas !== 'undefined' && !options.rstz) {
            return html2canvas(element, options);
        }

        if(typeof rasterizeHTML !== 'undefined') {
            var meth = 'drawDocument';
            if(typeof element === 'string') {
                meth = /^http/.test(element) ? 'drawURL' : 'drawHTML';
            }
            options.width = options.width || (W*K);
            return rasterizeHTML[meth](element, void 0, options).then(function(r) {
                options.onrendered(r.image);
            }, function(e) {
                callback(null,e);
            });
        }

        return null;
    };
})(jsPDF.API);
