'use strict';
var popupN;  // used for id of popup
var EXIF;

jQuery(function() {
    init_ewz_upload(window);
});

// the OnLoad function
// allows for more than one form on a page.  Each has an ewzG object ewzG_{webform_id}
function init_ewz_upload(ewz_win) {
    var name, wkey1, wkey;
    popupN = 0;
    fixConsole();
    if (ewz_win.RuntimeObject) {   // IE 8 or earlier
        wkey = RuntimeObject('ewzG*');
        for (name in wkey)
        {
            if (wkey.hasOwnProperty(name)) {
                //window.console && console.log('RuntimeObject: ', name, typeof wkey[name], ' >>> ',  wkey[name]);
                do_setup(wkey[name]);
            }
        }
    } else {
        // window.console && console.log( ewz_win );
        for (wkey1 in ewz_win) {
            if (ewz_win.hasOwnProperty(wkey1)) {
                if (wkey1.substring(0, 5) === 'ewzG_') {
                    // window.console && console.log( 'this: ', wkey1, typeof ewz_win[wkey1], ' >>> ',  ewz_win[wkey1] );
                    do_setup(ewz_win[wkey1]);
                }
            }
        }
    }
    jQuery('input[name="ewzuploadnonce"]').each(function(index) {
        jQuery(this).attr('id', 'ewzuploadnonce' + index);
    });


    // Bind the onchange event of the inputs to flag the inputs as being "ewzdirty".
    jQuery(":input").on("change",
        function() {
            // Add ewzdirty flag to the input in question (whose value has changed).
            jQuery(this).addClass("ewzdirty");
        }
    );
}

function do_setup( ewzG ) {
    // ewzG is null if not logged in
    // make any change in any item create the Clear button if it doesn't exist
    jQuery("#ewz_item_table_" + ewzG.webform_id).on("change keydown paste input", ":input:not(:button)",
                                              function() {
                                                  do_changed( ewzG, jQuery(this), ewzG.webform_id );
                                              });

    // make any change in any input enable the "submit" button
    jQuery("#ewz_form_" + ewzG.webform_id).on("change keydown paste input", ":input:not(:button)",
                                              function() {
                                                  jQuery(this).closest('form').find('button[id^="ewz_fsubmit"]').prop("disabled", false);
                                              });

    if( ewzG.do_warn ){
        window.addEventListener("beforeunload", function (e) {
            var enabled = jQuery('#ewz_fsubmit_' + ewzG.webform_id + ':enabled').length;
            if( enabled > 0 ){
                // dummy -- in newer browsers the message cannot be overwritten

                (e || window.event).returnValue = ewzG.confirm_msg; //Gecko + IE
                return ewzG.confirm_msg;                            //Webkit, Safari, Chrome
            }
        });
    }

    // show the user any message coming from the server
    if (ewzG.errmsg) {
        ewz_alert('U001', ewzG.errmsg.replace(/;;.*?$/gm,'').replace(/~/g,"<br>"), ++popupN);
    }

    check_table_width(ewzG.webform_id);
    var ewz_throttled = false;
    jQuery( window ).on("resize", function() {
            if( !ewz_throttled ){
                ewz_throttled = true;
                check_table_width(ewzG.webform_id);
                setTimeout(function() {
                    ewz_throttled = false;
                }, 500 );
            }
            clearTimeout(ewz_resizing);
            var ewz_resizing = setTimeout( function() {
                check_table_width(ewzG.webform_id);
            }, 250 );
        });
}


/* After a change, create the Clear button for the row if it doesnt exist */
function do_changed( ewzG, jitem, webform_id ) {
    var jrow = jitem.closest('tr');
    var jtable = jrow.closest('table');
    var jhead = jtable.find('thead');
    var jbody = jtable.find('tbody');
    // header row
    if( jhead.find('th.ewz-btn').length === 0  ){
        jhead.children().has('th').append('<th class="ewz-btn"></th>');
        jbody.children().has('td').append('<td class="ewz-btn"></td>' );
    }
    // changed row
    var    jlastcol = jrow.children().last();

    var    jrownum;
    if (jlastcol.find('button').length === 0) {
        jrownum = jrow.attr("id").replace("row", "").replace(/_\d*$/, '');
        jlastcol.append('<button  type="button" id="clear' + jrownum +
                        '"  onClick="clear_row(this, ' + webform_id + ' )">' + ewzG.clear_msg + '</button>');
    }
}

/* Return an array of values entered by the user                               */
/* Each item is an array whose first entry is the entered value,               */
/* and whose second entry contains additional data depending on the input type */
function get_values(ewzG, webform_id ){
    var row, fvalues, i, jelem, sel;
    fvalues = [];
    for (row = 0; row < ewzG.num_items; ++row) {
        fvalues[row] = {};
        for (i in ewzG.layout.fields) {
            if (!ewzG.layout.fields.hasOwnProperty(i)) { continue; }
            if( ewzG.layout.fields[i].all_items ){
                jelem = jQuery("#rdata1_" + ewzG.layout.fields[i].field_id + "__" + webform_id );
            } else {
                jelem = jQuery("#rdata_" + row + "__" + ewzG.layout.fields[i].field_id + "__" + webform_id );
            }
            if (jelem.length > 0) {
                switch(ewzG.layout.fields[i].field_type){
                case 'str':
                    fvalues[row][i] = [ jelem.val(), jelem.val() ];
                    break;
                case 'img':
                    if( jelem.prop("src") ) {
                        fvalues[row][i] = [ jelem.attr("src"), 'old' ];
                    } else {
                        fvalues[row][i] = [ jelem.val(), 'new' ];
                    }
                    break;
                case 'opt':
                    // second value is displayed to user if max rules are broken
                    // "no more than N items may have " + field_header + second value
                    sel = jelem.find(":selected");
                    fvalues[row][i] = [ sel.val(), sel.text() ];  // need value for code and text for message
                    break;
                case 'rad':
                    // second value never used here
                    if( jelem.prop("checked") ){
                        fvalues[row][i] = [ "checked", 'checked' ];
                    } else {
                        fvalues[row][i] = [ '', 'checked' ];
                    }
                    break;
                case 'chk':
                    if( jelem.prop("checked") ){
                        // second value is used in user error message if max rules are broken
                        // "no more than N items may have " + field_header + second value
                        fvalues[row][i] = [  "checked", 'checked' ];
                    } else {
                        fvalues[row][i] = [  "", 'checked'  ];
                    }
                    break;
                case 'lab':
                    fvalues[row][i] = [ jelem.val(), jelem.val() ];
                    break;
                }
            } else {
                fvalues[row][i] = [ '', '' ];
            }
        }
    }
    return fvalues;
}

/* return a list of all required fields that are missing */
function missing_check( ewzG, fvalues, use_row ){
    var missing, status, row, row1, i;
    missing = '';
    status = true;
    for (row = 0; row < ewzG.num_items; ++row) {
        if( !use_row[row] ){ continue; }
        row1 = row + 1;   // for user display
        for (i in ewzG.layout.fields) {
            if (ewzG.layout.fields.hasOwnProperty(i)) {
                if( ewzG.layout.fields[i].required  && isblank( fvalues[row][i][0] ) ){
                    if (missing) {
                        missing += ", ";
                    }
                    missing += " row " + row1 + ": " + ewzG.layout.fields[i].field_header;
                    status = false;
                }
            }
        }
    }
    if( !status && ewzG.jsvalid ){
        ewz_alert('U002', ewzG.req_msg_err + "<br>" + missing, ++popupN);
    }
    return status;
}

/* Check any max rules on drop-down option selections */
function options_check(  ewzG, fvalues, use_row ){
    var optcount, msg, status, textvals, row, sel_val, key, maxn, field_id, ftype, text;
    msg = '';
    status = true;
    for (field_id in ewzG.layout.fields) {
        if (!ewzG.layout.fields.hasOwnProperty(field_id)) { continue; }
        ftype = ewzG.layout.fields[field_id].field_type;
        if (ftype === 'opt' || ftype === 'chk') {
            optcount = {};
            textvals = {};
            for (row = 0; row < ewzG.num_items; ++row) {
                if( !use_row[row] ){ continue; }
                sel_val = fvalues[row][field_id][0];
                if ( sel_val  ) {
                    textvals[ sel_val ] = fvalues[row][field_id][1];  // for display to user
                    if (optcount[ sel_val ] === undefined) {
                        optcount[ sel_val ] = 1;
                    } else {
                        ++optcount[ sel_val ];
                    }
                }
            }
            for ( key in optcount ) {
                if(!optcount.hasOwnProperty(key)){ continue; }
                if( ftype === 'opt' ){
                    maxn = ewzG.layout.fields[field_id].Xmaxnums[key];
                    text = 'equal to ';
                } else {
                    maxn = ewzG.layout.fields[field_id].fdata.chkmax;
                    text = ' ';
                }
                if ( ( maxn > 0 ) && ( optcount[key] > maxn ) ) {
                    if( msg ){
                        msg += "<br>";
                    }
                    msg += ewzG.nomorethan.replace('%d', maxn) +  ewzG.layout.fields[field_id].field_header + " " + text + textvals[key];
                    status = false;
                }
            }
        }
    }
    if( !status && ewzG.jsvalid ){
        ewz_alert('U003',  msg, ++popupN );
    }
    return status;
}

/* If any restrictions are not satisfied, show an alert and return false */
/* Otherwise, return true                                                */
function restrictions_check( ewzG, fvalues, use_row ){
    var row, matches_restr, row1, field_id, restr1;
    for (row = 0; row < ewzG.num_items; ++row) {
        if ( !use_row[row] ) { continue; }
        row1 = row + 1;   // for user display

        for (restr1 in ewzG.layout.restrictions) {
            if (!ewzG.layout.restrictions.hasOwnProperty(restr1)) { continue; }

            matches_restr = true;      // initialize

            // set matches_restr for the row to false if any field does not match
            for ( field_id in ewzG.layout.fields) {
                if (!ewzG.layout.fields.hasOwnProperty(field_id)) { continue; }
                matches_restr = matches_restr &&
                    field_matches_restr( ewzG.layout.restrictions[restr1][ewzG.layout.fields[field_id].field_id], fvalues[row][field_id][0]);
            }

            // if matches_restr is still true, alert and return false
            if ( matches_restr && ewzG.jsvalid  ) {
                ewz_alert('U004', ewzG.row_err.replace('%d', row1) + ": " + ewzG.layout.restrictions[restr1].msg, ++popupN);
                return false;
            }
        }
    }
    return true;
}


/* validation                                           */
function check_data(ewzG, webform_id) {
    var status, fvalues, use_row, row, field_id, except;
    fvalues = get_values(ewzG, webform_id );
    use_row = {};
    for (row = 0; row < ewzG.num_items; ++row) {
        for (field_id in ewzG.layout.fields) {
            if (!ewzG.layout.fields.hasOwnProperty(field_id)) { continue; }
            // ignore all-items and fixed-text fields when checking which rows are used
            if( !ewzG.layout.fields[field_id].all_items && ( ewzG.layout.fields[field_id].field_type !== 'lab' ) ){
                if( fvalues[row][field_id][0] ){
                    use_row[row] = true;
                }
            }
        }
    }
    try {
        status = true;
        status = status && missing_check(  ewzG, fvalues, use_row );
        status = status && options_check(  ewzG, fvalues, use_row );
        status = status && restrictions_check(  ewzG, fvalues, use_row );

        if (status) {
            disable_unused_rows( webform_id, ewzG, use_row );
        }
        return status;

    } catch (except) {
        ewz_alert('U005', except.message, ++popupN);
        return false;
    }
}

// handling the unused rows on the server gets too complicated
function disable_unused_rows( webform_id, ewzG, use_row ){
    var row, fld_id, idstr;
    for (row = 0; row < ewzG.num_items; ++row) {
        if (!use_row[row]) {
            for (fld_id in ewzG.layout.fields) {
                if( !ewzG.layout.fields.hasOwnProperty(fld_id) ){ continue; }
                idstr = "#rdata_" + row + "__" + ewzG.layout.fields[fld_id].field_id + "__" + webform_id;
                jQuery(idstr).prop("disabled", true);
            }
        }
    }
}

// Does the ajax call to delete an item on the server
// On success, calls clear_row
function delete_item(button, webform_id) {
    var ewzG = window['ewzG_' + webform_id],
               jbutton = jQuery(button),
               item_id = jbutton.siblings('[name^="item_id"]').val(),
               jrow = jbutton.closest('tr'),
               del_nonce = jrow.closest('form').find('[name="ewzuploadnonce"]').val(),
               jqxhr;
    ewz_confirm("Really delete the item? This action cannot be undone.",
        function() {
            jbutton.after('<div id="temp_load_' + webform_id +'" class="ewz_progress"><img alt="please wait" src="' + ewzG.load_gif + '"/></div>');
            jqxhr = jQuery.post(ewzG.ajaxurl,
                            {
                                action: 'ewz_del_item',
                                item_id: item_id,
                                ewzdelnonce: del_nonce
                            },
                            function(response) {
                                jQuery("#temp_load_" + webform_id).remove();
                                if (response == '1') {
                                    clear_row(button, webform_id);
                                } else {
                                    ewz_alert('U006', response + "<br>" + ewzG.refresh_msg, ++popupN);
                                }
                            }).fail( function( jqXHr, textStatus, errorThrown ){
                                    ewz_alert( 'U014', ewzG.server_err + jqXHr.responseText +
                                                       '<br>' + ewzG.refresh_msg, ++popupN );} );
         },
         null,
         ++popupN );
}

// Clear input previously entered
// Remove all images, hidden inputs
// Set select, text values to '', uncheck checkboxes and radio buttons
// Remove 'ewzdirty' flag and hidden inputs
// Remove the 'clear' button
// Disable submit if no other data
function clear_row(button, webform_id) {
    var jrow = jQuery(button).closest('tr'),
        jtable, jform;
    // img input cell will contain either 1: image alone, with id ^rdata  or 2: file input with id ^rdata, alone or with a data div
    // Note must specify file type, there are other inputs ^rdata.
    jrow.find("input[id^='rdata'][type='file'], img[id^='rdata']").each(function() {
        var oldid = jQuery(this).attr("id"),
        oldname = jQuery(this).attr("name"),
        jcell = jQuery(this).closest('div[class="fdisplay"]');
        jcell.html(empty_img_info(oldid, oldname,webform_id ));
    });

    jrow.find("img").remove();
    // reset both properties and attributes for non-image items
    jrow.find("input:text").val('').attr("value", '');
    jrow.find("input:radio").prop("checked", false ).attr("checked", false );
    jrow.find("input:checkbox").prop("checked", false ).attr("checked", false );
    jrow.find("option").prop("selected", false ).attr("selected", false ).prop("disabled", false);
    jrow.find("select").val('');
    jrow.find("textarea").val('').attr("value", '');
    jrow.find("input[class='ewzdirty']").removeClass("ewzdirty");
    jrow.find('input').filter(':hidden').remove();
    jrow.find("button").remove();

    // remove last column if no items left
    jtable = jrow.closest('table');
    if( jtable.find('tr td.ewz-btn').has("button").length === 0 ) {
        if( jQuery('#ewz_all_table_' + webform_id ).find(':disabled').length > 0 ){
            // to deal with the case of all-items fields used in prefix
            document.location.reload(true);
        }
        jtable.find('tr td.ewz-btn').remove();
        jtable.find('tr th.ewz-btn').remove();
    }
    jform = jtable.closest('form');
    if (jform.find(":input[class='ewzdirty']").length > 0 || jform.find("button[id^='delete']:enabled").length > 0 ) {
        jQuery("#ewz_fsubmit_" + webform_id).prop({ disabled: false });
    } else {
        jQuery("#ewz_fsubmit_" + webform_id).prop({ disabled: true });
    }
}

// display the data as modifiable instead of just the summary
function show_modify(button, webform_id) {
    button.style.display = "none";
    document.getElementById("ewz_modify_" + webform_id).style.display = "block";
    document.getElementById("ewz_stored_" + webform_id).style.display = "none";
    document.getElementById("ewz_change_" + webform_id).style.display = "none";

    // disable submit until changes made, then enable - needed to indicate a deletion was actually done on server
    jQuery("#ewz_fsubmit_" + webform_id).prop({
        disabled: true
    });
    check_table_width(webform_id);

}

function check_table_width(webform_id){
    var ewzG = window['ewzG_' + webform_id];
    var tablew = jQuery('#ewz_item_table_' + webform_id).outerWidth();
    var scrollw = jQuery('#scrollablediv_' + webform_id).innerWidth();
    var jwarn = jQuery('#ewz_warn_' + webform_id);
    if ( parseInt( scrollw, 10 ) < parseInt( tablew, 10 ) - 2 ){
        if( jwarn.text().indexOf(ewzG.toonarrow_err) < 0 ){
            var did = '<i>' + ewzG.toonarrow_err + '</i>' ;
            jwarn.html(did);
        }
    } else {
         jQuery('#ewz_warn_' + webform_id).text('');
    }
}



////////////////// Image File Info ////////////////
// an image file has been selected, display it's thumbnail and info
function fileSelected(field_id, input_id, webform_id) {
    var pathre = /([^\\\/:]+)$/,
        ewzG = window['ewzG_' + webform_id],
        freader,
        files,oFile,fields,limits,rFilter;

    jQuery('#upload_response_' + webform_id).hide();

    if (window.FileReader !== undefined) {
        freader = new FileReader();
        freader.onload = function(fileref) {
            fileref.preventDefault();  // prevent display of full image on drag-drop

            // remove any existing image thumbnail, create the new img
            jQuery('#' + input_id).closest('.fdisplay').find('img').remove();

            var html = '<img style="max-height: ' + ewzG.thumb_dim['h'] + 'px; ';
            html += 'max-width: ' + ewzG.thumb_dim['w'] + 'px;" ';
            html += ' id="im_' + input_id + '"  src="' + fileref.target.result + '">';
            jQuery('#dv_' + input_id).append(html);

            var theImage = document.getElementById('im_' + input_id);
            theImage.onload = function() {

                // by the time this is run, oFile has been defined as files[0]
                var errmsg = invalid_image(field_id, theImage, webform_id);
                ewzG.sResultFileSize = bytesToSize(oFile.size);

                var ewz_cs = exifCS(theImage);

                if (errmsg && ewzG.jsvalid ) {
                    ewz_alert('U007', '** ' + oFile.name + ":<br>" +
                              "<br>" + ewzG.size_msg  + ewzG.sResultFileSize + "<br>" +  ewzG.type_msg + oFile.type +
                              '<br>' + ewzG.cspace_msg + ewz_cs +
                              "<br>" + ewzG.width_msg + theImage.naturalWidth + "<br>" + ewzG.height_msg + theImage.naturalHeight + "<br><br>" +
                              errmsg, ++popupN);
                    clear_file_input( input_id );
                    return;
                }

                if ( ewzG.cs_warn && (ewz_cs == "Not determined" )) {
                     ewz_alert('U015', '** ' + oFile.name + ":<br>" +
                               "<br>Size: " + ewzG.sResultFileSize + "<br>" + ewzG.type_msg + oFile.type +
                               '<br>Colour Space: ' + ewz_cs +
                           "<br>" + ewzG.width_msg + theImage.naturalWidth + "<br>" + ewzG.height_msg + theImage.naturalHeight + "<br><br>" +
                           ewzG.colsp_warn, ++popupN);
                }

                jQuery('#dv_' + input_id).show();
                jQuery('#nm_' + input_id).text('Name: ' + pathre.exec(oFile.name)[1]);
                jQuery('#sz_' + input_id).text('Size: ' + ewzG.sResultFileSize);
                jQuery('#tp_' + input_id).text('Type: ' + oFile.type);
                jQuery('#cs_' + input_id).text('Colour Space: ' + ewz_cs);
                jQuery('#wh_' + input_id).text('Width: ' + theImage.naturalWidth + ' Height: ' + theImage.naturalHeight);
            };
        };

        files = document.getElementById(input_id).files;
        if ( ( files == null ) || ( files[0] === undefined ) || ( files[0] == null ) ) {
            jQuery('#dv_' + input_id).hide();
            jQuery('#nm_' + input_id).text('');
            jQuery('#sz_' + input_id).text('');
            jQuery('#tp_' + input_id).text('');

            jQuery('#cs_' + input_id).text('');

            jQuery('#wh_' + input_id).text('');

        } else {

            // get selected file element
            oFile = files[0];
            fields = ewzG.layout.fields[field_id];
            limits = fields.fdata;
            if (!limits.max_img_size) {
                limits.max_img_size = 1;
            }

            if( ewzG.jsvalid ){
                rFilter = new RegExp ( '^(' + limits.allowed_image_types.join('|').replace(/\//g, '\\\/') + ')$', 'i');

                if (!rFilter.test(oFile.type)) {
                    ewz_alert('U008', '** ' + oFile.name + ":<br><br>" + ewzG.notaccepted + '<br>' + ewzG.ftype_err, ++popupN);
                    clear_file_input( input_id );
                    return;
                }
                if (oFile.size > (limits.max_img_size * 1048576)) {
                    ewz_alert('U009', '** ' + oFile.name + ":<br><br>" + ewzG.notaccepted + '<br>' + ewzG.fsize_err.replace('%d', bytesToSize(oFile.size)) + limits.max_img_size + 'MB', ++popupN);
                    clear_file_input( input_id );
                    return;
                }
            }
            freader.readAsDataURL(oFile);
            if(freader.error){
                ewz_alert('U010', '** ' + oFile.name + ":<br><br>" + ewzG.cantread_msg, ++popupN);
                clear_file_input( input_id );
                return;
            }
        }
    }
}

/* Get rid of an invalid selected image file */
function clear_file_input( input_id ){
    jQuery('#' + input_id).val('');
    jQuery('#im_' + input_id).remove();
    jQuery('#dv_' + input_id).hide();
}


/* return an error message if the image does not fit the dimension limits */
function invalid_image(field_id, theImage, webform_id) {
    var scale, maxw, maxh, maxHeight, maxWidth, msg,
    ewzG = window['ewzG_' + webform_id],
    limits = ewzG.layout.fields[field_id].fdata,
    iwidth = theImage.naturalWidth,
    iheight = theImage.naturalHeight,              // actual height of image
    margin = parseInt( ewzG.margin );

    if ((iwidth === undefined || iwidth == null || iwidth == 0)) {

        return 'Unable to determine image dimensions.  It may be of a type not accepted by this application.';

    } else {
        // Max dimensions are always set for landscape mode.
        // If rotation allowed and image is in portrait format, interchange max width and height before running the checks
        if (limits.canrotate && (iheight > iwidth)) {
            maxHeight = limits.max_img_w;
            maxWidth = limits.max_img_h;
        } else {
            maxHeight = limits.max_img_h;
            maxWidth = limits.max_img_w;
        }
        // if either dimension exceeds the max, return an error
        if ( ( iwidth > maxWidth ) || ( iheight > maxHeight ) ) {
            msg = "<br>    Width:  <= " + maxWidth + ' ' +ewzG.pixels_msg + ",<br>" + '    Height: <= ' + maxHeight + ' ' + ewzG.pixels_msg;
            return  ewzG.notaccepted + '<br>' + ewzG.isize_err + msg;
        }
        // if mustfill is set, and both dimensions are less that the max, return an error
        if( limits.mustfill ){
            if( ( iwidth < ( maxWidth - margin ) ) && iheight < ( maxHeight - margin ) ){
                msg = "<br>    Width:  <= " + maxWidth + ' ' + ewzG.pixels_msg + ",<br>" + '    Height: ' + maxHeight + ' ' + ewzG.pixels_msg;
                return  ewzG.notaccepted + '<br>' + ewzG.margin_err + msg;
            }
        }

        var ilongest = Math.max(iwidth, iheight);
        if ( limits.min_longest_dim && ilongest < limits.min_longest_dim ) {

            // show the user how big the image could be and still fit the criteria
            scale = Math.min( ( maxHeight / iheight ), ( maxWidth / iwidth ) );
            maxw = Math.floor(scale * iwidth);
            maxh = Math.floor(scale * iheight);

            msg = ewzG.notaccepted + '<br>' + ewzG.ismall_err.replace('%d', limits.min_longest_dim);
            msg += '<br><br>' + ewzG.enlarge_err.replace( '%s',  maxw + " x " + maxh + ' ' +  ewzG.pixels_msg );

            return msg;
        }
        return '';
    }
}

function fix_radios( webform_id ){
    jQuery("#ewz_form_" + webform_id).find( 'input[type="radio"]' ).each( function(){
        var jrad = jQuery(this);
        // unused rows have been disabled by now
        if( !jrad.prop("disabled") ){
           if( jrad.prop( "checked" )){
               jrad.closest('form').append('<input type="hidden" name="' + jrad.val() + '" value="1" >');
           } else {
               jrad.closest('form').append('<input type="hidden" name="' + jrad.val() + '" value="0" >');
           }
           jrad.prop("disabled", true);
        }
    });
    jQuery("#ewz_form_" + webform_id).find( 'input[type="checkbox"]' ).each( function(){
        var jchk = jQuery(this);
        if( !jchk.prop("disabled") ){
            if( !jchk.prop( "checked" ) ){
                jchk.closest('form').append('<input type="hidden" name="' + jchk.prop("name") + '" value="0" >');
            }
        }
    });
}


/////////////////  Upload and Upload Progress Info  ///////////////////////////

function startUploading(webform_id) {
    var ewzG = window['ewzG_' + webform_id],
               status, xmlRequest, jresponse, jdivComplete, jdivProgress, form_data;
    jQuery("#ewz_fsubmit_" + webform_id).prop({
        disabled: true
    });
    if( ewzG.inProgress ){
        return;
    }
    // cleanup temp states
    ewzG.iPreviousBytesLoaded = 0;
    // do client-side validation (uses alerts), only upload if check is ok
    status = check_data(ewzG, webform_id );

    if (status || !ewzG.jsvalid ) {
        fix_radios( ewzG.webform_id );
        jresponse = jQuery('#upload_response_' + webform_id);
        if (window.FormData === undefined) {
            do_submit_form(jresponse, webform_id);
        } else {
            // create XMLHttpRequest object, adding few event listeners, and POSTing our data
            xmlRequest = new XMLHttpRequest();
            if (xmlRequest.upload === undefined) {
                do_submit_form(jresponse, webform_id);
            } else {
                ewzG.inProgress = true;
                jresponse.hide();

                jQuery('#progress_percent_' + webform_id).text('');

                jdivComplete = jQuery('#complete_' + webform_id);
                jdivComplete.show();
                jdivComplete.width('500px');

                jdivProgress = jQuery('#progress_bar_' + webform_id);
                jdivProgress.show();
                jdivProgress.width( '0px' );

                // get form data for POSTing
                form_data = new FormData(document.getElementById('ewz_form_' + webform_id));

                //* comment this out for testing look of progress bar:
                send_and_track(form_data);

                //* uncomment for testing look of progress bar:
                //* uploadProgress({ lengthComputable: 1, loaded:500, total:1000});
                //* uncomment for testing look of progress bar:
                //* doInnerUpdates();
            }
        }
    } else {
        jQuery("#ewz_fsubmit_" + webform_id).prop({
            disabled: false
        });
        return;
    }

    /* NB: this is a nested function within startUploading */
    function send_and_track(form_data){
        // set up event progress listeners (must be done before "open" call)
        xmlRequest.upload.addEventListener('progress', uploadProgress, false);
        xmlRequest.addEventListener('load', uploadFinish, false);
        xmlRequest.addEventListener('error', uploadError, false);
        xmlRequest.addEventListener('abort', uploadAbort, false);
        xmlRequest.open('POST', ewzG.ajaxurl + '?action=ewz_upload');

        xmlRequest.send(form_data);

        // set doInnerUpdates to run on timer
        ewzG.timer = setInterval( doInnerUpdates, 100);
    }

    /* NB: this is a nested function within startUploading */
    // For browsers not supporting XMLHttpRequest.upload
    function do_submit_form( jResponseDiv, webform_id ) {

        if ((window.console !== undefined) && window.console) {
            console.log("no html5 upload available.  webform " + webform_id);  // needed for admin
        }
        jResponseDiv.show();

        jResponseDiv.text(  ewzG.wait + ewzG.oldform );
        document.getElementById('ewz_form_' + webform_id).submit();
    }

    /* NB: this is a nested function within startUploading */
    // display upload progress bar and percent
    function uploadProgress(event) {
        var iPercentComplete, iBytesTransfered, jUploadResponse;

        if (event.lengthComputable) {
            ewzG.iBytesUploaded = event.loaded;
            ewzG.iBytesTotal = event.total;
            iPercentComplete = Math.round(event.loaded * 100 / event.total);
            iBytesTransfered = bytesToSize(ewzG.iBytesUploaded);

            jQuery('#progress_percent_' + webform_id).text( iPercentComplete.toString() + '%');
            jQuery('#b_transfered_' + webform_id).text( iBytesTransfered );
            jQuery('#progress_bar_' + webform_id).width( ( iPercentComplete * 5).toString() + 'px' );

            jUploadResponse = jQuery('#upload_response_' + webform_id);
            // when complete, display the  ewzG.complete message in upload_response area
            if (iPercentComplete === 100) {
                jUploadResponse.text( ewzG.complete );
            } else {
                jUploadResponse.text( ewzG.wait );
            }
            jUploadResponse.show();
        } else {
            jQuery('#progress_bar_' + webform_id).text( 'unable to calculate progress' );
        }
    }

    /* NB: this is a nested function within startUploading */
    //  display speed and time remaining
    function doInnerUpdates() {

        var iCB = ewzG.iBytesUploaded,
        iDiff = iCB - ewzG.iPreviousBytesLoaded,
        iBytesRem, secondsRemaining, iSpeed, nn;

        // if nothing new loaded - exit
        if (iDiff === 0) {
            return;
        }
        ewzG.iPreviousBytesLoaded = iCB;
        iDiff = iDiff * 2;
        iBytesRem = ewzG.iBytesTotal - ewzG.iPreviousBytesLoaded;
        secondsRemaining = iBytesRem / iDiff;

        iSpeed = iDiff.toString() + 'B/s';
        nn = 1024 * 1024;
        if (iDiff > nn) {
            iSpeed = (Math.round(iDiff * 100 / nn) / 100).toString() + 'MB/s';
        } else if (iDiff > 1024) {
            iSpeed = (Math.round(iDiff * 100 / 1024) / 100).toString() + 'KB/s';
        }

        jQuery('#speed_' + webform_id).text( iSpeed );
        jQuery('#remaining_' + webform_id).text( '| ' + secondsToTime(secondsRemaining) );
    }

    /* NB: this is a nested function within startUploading */
    // upload successfully finished, reload the page
    function uploadFinish(event) {

        if (event.target.responseText === '1') {
            document.location.reload(true);
        } else {
             ewz_alert_and_reload('U011', ewzG.upload_fail_msg + "<br> " +
                                          event.target.responseText + "<br><br>" + ewzG.will_reload_msg, ++popupN);
        }
    }

    /* NB: this is a nested function within startUploading */
    // upload error
    function uploadError(event) {

        ewz_alert('U012', ewzG.upload_ng_msg + ewzG.upload_err, ++popupN);
        clearInterval(ewzG.timer);
        ewzG.inProgress = false;
    }

    /* NB: this is a nested function within startUploading */
    // upload abort
    function uploadAbort(event) {
        ewz_alert('U013', ewzG.upload_abort_msg + ewzG.abort_err, ++popupN);
        clearInterval(ewzG.timer);
        ewzG.inProgress = false;
    }
}

////////////////// Utility Functions ////////////////

function secondsToTime(secs) {
    var hr = Math.floor(secs / 3600),
    min = Math.floor((secs - (hr * 3600)) / 60),
    sec = Math.floor(secs - (hr * 3600) - (min * 60));
    if (hr < 10) {
        hr = "0" + hr;
    }
    if (min < 10) {
        min = "0" + min;
    }
    if (sec < 10) {
        sec = "0" + sec;
    }
    if (hr) {
        hr = "00";
    }
    return hr + ':' + min + ':' + sec;
}

function bytesToSize(bytes) {
    var i,
    sizes = ['Bytes', 'KB', 'MB'];
    if (bytes === 0) {
        return 'n/a';
    }
    i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10);
    return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
}


function empty_img_info(idstr, namestr, webform_id) {
    if (namestr === undefined) {
        namestr = idstr.replace(/_\d+$/, '').replace('__', '][').replace('_', '[').replace('_', ']');
    }
    var re = /__([0-9]*)__/,
    field = idstr.match(re)[1],
    qid = "'" + idstr + "'",
    ret = '<input type="file" name="' + namestr + '" id="' + idstr + '" onchange="fileSelected(' + field + ', ' + qid + ', ' + webform_id + ')">';

    if (window.FileReader !== undefined) {
        ret += '<div id="dv_' + idstr + '" style="display:none">';
        ret += '<div id="nm_' + idstr + '"></div>';
        ret += '<div id="sz_' + idstr + '"></div>';
        ret += '<div id="tp_' + idstr + '"></div>';

        ret += '<div id="cs_' + idstr + '"></div>';

        ret += '<div id="wh_' + idstr + '"></div>';
        ret += '</div>';
    }
    return ret;
}

function field_matches_restr( restriction_val, entered_val ) {
    var ismatch = true;
    switch (restriction_val) {
    case  undefined:
        break;
    case  '~*~':
        break;
    case  '~-~':
        if (!isblank(entered_val)) {
            ismatch = false;
        }
        break;
    case  '~+~':
        if (isblank(entered_val)) {
            ismatch = false;
        }
        break;
    default:
        if (restriction_val !== entered_val) {
            ismatch = false;
        }
        break;
    }
    return ismatch;
}


function exifCS (img) {
    var EXIFColorSpace;
        EXIF.getData(img, function() {
                EXIFColorSpace = EXIF.getTag(this, "ColorSpace");
            if (EXIFColorSpace == 1) {
                EXIFColorSpace = "sRGB";
            } else {
                EXIFColorSpace = "Not determined";
            }
        });
    return EXIFColorSpace;
}
