// This is some Prince HTML-to-PDF converter Javascript. It's not executed by the browser, but during the
// Prince HTML-to-PDF conversion process. See https://www.princexml.com/doc/javascript/
// turn on box tracking API
Prince.trackBoxes = true;

// once the first pass of rendering is finished, let's make the "pmb-dynamic-resize" images take up the rest of the
// page they're on. Prince will then need to re-render.
Prince.registerPostLayoutFunc(function() {
    pmb_continue_image_resizing();
    pmb_extend_to_bottom();
});

/**
 * Resizes images in blocks with CSS class "pmb-dynamic-resize".
 * Gutenberg image blocks with no alignment: the top-level block has the class and is the figure.
 * But if they're floating, the top-level block is a div which contains the figure (which floats).
 * The image's initial height effectively becomes the minimum height. The maximum height
 */
function pmb_continue_image_resizing(){
    var resized_something = false;

    // To make this more efficient, grab the first image from each section followed by a pagebreak
    if(pmb.page_per_post){
        var dynamic_resize_blocks = document.getElementsByClassName('pmb-section');
        for(var i=0; i<dynamic_resize_blocks.length; i++){
            var resized_element = pmb_resize_an_image_inside(dynamic_resize_blocks[i]);
            if(resized_element){
                resized_something = true;
            }
        }
    } else {
        if(pmb_resize_an_image_inside(document)){
            resized_something = true;
        }
    }


    if(resized_something){
        Prince.registerPostLayoutFunc(pmb_continue_image_resizing);
    }
}

/**
 * Grabs a "pmb-dynamic-resize" element inside here and resizes it and returns it.
 * (If none are found, returns null)
 * @param element
 * @return boolean
 */
function pmb_resize_an_image_inside(element){
    var dynamic_resize_blocks = element.getElementsByClassName("pmb-dynamic-resize");

    // just grab one block at a time because how the first image is resized will affect the subsequentn ones
    // and subsequent ones' telemetry is only updated after re-rendering. So do one, then get Prince to re-render, then
    // do another... etc.
    var a_dynamic_resize_block = dynamic_resize_blocks[0];
    if(typeof a_dynamic_resize_block === 'undefined'){
        return null;
    }
    // when images are floating, the block had a div (with no height) because its contents are floating
    // in that case we want to resize the figure inside the block. So check if there's a figure inside it
    var figure_is_floating = true;
    var figure_to_resize = a_dynamic_resize_block.getElementsByTagName("figure")[0];

    if( typeof figure_to_resize === 'undefined'){
        // There's no figure inside it. The figure is the top-level element in the block.
        figure_to_resize = a_dynamic_resize_block;
        figure_is_floating = false;
    }
    // For floating images we need to also set the block's width (I can't figure out how to get CSS to set the width automatically)
    // so for that we need to figure out how much the image inside the figure got resized (non-trivial if there's a caption).
    var figure_image = figure_to_resize.getElementsByTagName('img')[0];

    // determine the caption's height
    var figure_caption = figure_to_resize.getElementsByTagName('figcaption')[0];
    var caption_height = 0;
    if(typeof(figure_caption) !== 'undefined'){
        var caption_box = figure_caption.getPrinceBoxes()[0];
        caption_height = caption_box.marginTop + caption_box.h + caption_box.marginBottom;
    }
    // If we can't find an image to resize, there's nothing to resize (which is weird but somehow happens?)
    if(typeof(figure_image) !== 'undefined') {
        var figure_image_box = figure_image.getPrinceBoxes()[0];
        var figure_image_height = figure_image_box.h;

        var figure_box = figure_to_resize.getPrinceBoxes()[0];
        var page_box = PDF.pages[figure_box.pageNum - 1];

        // don't forget to take the footnote height into account
        var footnotes_height = 0;
        for (var index in page_box['children']) {
            var box_on_page = page_box['children'][index];
            if (box_on_page['type'] === 'FOOTNOTES') {
                footnotes_height = box_on_page['h'];
            }
        }
        var max_allowable_height = pmb_px_to_pts(pmb.max_image_size);
        // page_box.y is the distance from the top of the page to the bottom margin;
        // page_box.h is the distance from the bottom margin to the top margin
        // figure_box.y is the distance from the top of the page to the bottom-left corner of the figure
        // see https://www.princexml.com/forum/post/23543/attachment/img-fill.html
        var top_margin = page_box.y - page_box.h;
        var remaining_vertical_space = figure_box.y - top_margin - 10 - footnotes_height;

        var max_height_because_of_max_width = page_box.w * figure_image_box.h / figure_image_box.w + caption_height;

        // also gather the maximum heights from the original image
        var max_height_from_resolution_y_of_image = 100000;
        if('height' in figure_image.attributes){
            max_height_from_resolution_y_of_image = pmb_px_to_pts(figure_image.attributes['height'].value);
        }

        // resolution_height px     max_height pts
        // ------------------  =  --------------   =>   max_height = max_width pts  * original_height px / original_width px
        // resolution_width px      max_width pts
        var max_height_from_resolution_x_of_image = 100000;
        if('width' in figure_image.attributes && 'height' in figure_image.attributes){
            max_height_from_resolution_x_of_image = (page_box.w * figure_image.attributes['height'].value / figure_image.attributes['width'].value) + caption_height;
        }
        Log.info('IMG:' + figure_image.attributes['src'].value);
        Log.info(' page width:' + page_box.w);
        Log.info('  pmb.max_image_size' + pmb.max_image_size);
        Log.info(' remaining_vertical_space ' + remaining_vertical_space + '(distance to bottom margin ' + page_box.y + ', figure bottom at ' + figure_box.y + ')');
        Log.info(' max_height_because_of_max_width' + max_height_because_of_max_width);
        Log.info(' max_height_from_resolution_y_of_image' + max_height_from_resolution_y_of_image);
        Log.info(' max_height_from_resolution_x_of_image' + max_height_from_resolution_x_of_image);
        Log.info(' caption height ' + caption_height);
        // put a limit on how big the image can be
        // use the design's maximum image size, which was passed from PHP

        var new_figure_height = Math.min(
            max_allowable_height,
            remaining_vertical_space,
            max_height_because_of_max_width,
            max_height_from_resolution_y_of_image,
            max_height_from_resolution_x_of_image
        );

        Log.info('New figure size is ' + new_figure_height);
        var max_class = 'pmb-dynamic-resize-limited-by-unknown';
        switch(new_figure_height){
            case max_allowable_height:
                max_class = 'pmb-dynamic-resize-limited-by-max_allowable_height';
                break;
            case remaining_vertical_space:
                max_class = 'pmb-dynamic-resize-limited-by-remaining_vertical_space';
                break;
            case max_height_because_of_max_width:
                max_class = 'pmb-dynamic-resize-limited-by-max_height_because_of_max_width';
                break;
            case max_height_from_resolution_y_of_image:
                max_class = 'pmb-dynamic-resize-limited-by-max_height_from_resolution_y_of_image';
                break;
            case max_height_from_resolution_x_of_image:
                max_class = 'pmb-dynamic-resize-limited-by-max_height_from_resolution_x_of_image';
                break;
        }
        Log.info('max height css class:'+ max_class);
        // Resize the block
        figure_to_resize.style.height = new_figure_height + "pt";
        if (figure_is_floating) {
            // Used some grade 12 math to figure out this equation.
            var new_image_height = new_figure_height - figure_box.h + figure_image_height;
            var resize_ratio = new_image_height / figure_image_height;
            figure_to_resize.style.width = (figure_box.w * resize_ratio) + 'pt';
        }
    }

    // Change the class so we know we don't try to resize this block again
    a_dynamic_resize_block.className = a_dynamic_resize_block.className.replace(/pmb-dynamic-resize/g, 'pmb-dynamic-resized') + ' ' + max_class;
    return a_dynamic_resize_block;
}

function pmb_extend_to_bottom(){
    Log.info('pmb_extend_to_bottom');
    // find all elements that should extend to bottom
    var dynamic_resize_elements = document.getElementsByClassName('pmb-fill-remaining-height');
    if(dynamic_resize_elements.length){
        Log.info('found something to resize');
        // find their distance to the bottom of the page
        var element = dynamic_resize_elements[0];
        var element_box = element.getPrinceBoxes()[0];
        var page_box = PDF.pages[element_box.pageNum - 1];
        Log.info('element to resize');
        pmb_print_props(element_box, 'element to resize box');
        pmb_print_props(page_box, 'page box');
        var remaining_vertical_space = element_box.y - (page_box.y - page_box.h) - 50;
        Log.info('resize to ' + remaining_vertical_space);
        // make the element fill that vertical height
        element.style.height = remaining_vertical_space + "pt";
        // remember not to do this one again
        element.className = element.className.replace(/pmb-fill-remaining-height/g, 'pmb-filled-remaining-height');
        // redraw and look again
        Prince.registerPostLayoutFunc(pmb_extend_to_bottom);
    } else {
        Log.info('nothing more to do');
    }
}

/**
 * From https://www.princexml.com/doc/cookbook/#how-and-where-is-my-box
 * @param pixels
 * @returns {number}
 */
function pmb_px_to_pts(pixels){
    return pixels * (72 / 96);
}

/**
 * A debugging function, especially useful for figuring out what's on these "box" objects
 * @param obj
 * @param label
 */
function pmb_print_props(obj, label){
    Log.info(label);
    for(var prop in obj){
        var val = obj[prop];
        Log.info(prop + ':' + val);
    }
}

