<?php
defined( 'ABSPATH' ) or exit;   // show a blank page if try to access this file directly

require_once( EWZ_PLUGIN_DIR . 'classes/ewz-exception.php' );
require_once( EWZ_PLUGIN_DIR . 'classes/ewz-user.php' );
require_once( EWZ_PLUGIN_DIR . 'includes/ewz-webforms-helptext.php' );
require_once( EWZ_PLUGIN_DIR . 'classes/ewz-webform.php' );
require_once( EWZ_PLUGIN_DIR . 'classes/validation/ewz-webform-input.php' );
require_once( EWZ_PLUGIN_DIR . 'classes/validation/ewz-CSV-input.php' );
require_once( EWZ_PLUGIN_DIR . 'includes/ewz-admin-list-items.php' );
require_once( EWZ_CUSTOM_DIR . 'ewz-custom-data.php' );


/**
 * Store the per-item info in an uploaded csv file for a webform
 *
 * Checks to make sure item is attached to webform - otherwise, webform param is not
 * used, but seems a good idea to force a separate upload for each form.
 *
 * @param   int    $webform_id    webform
 * @return  string success message
 */
function ewz_process_uploaded_admin_data( $webform_id )
{

    // needed for Windows files ???
    // ini_set('auto_detect_line_endings', true);  // Deprecated since php8.1

   if( !isset( $_FILES['itmcsv_data'] ) ){
       return( "No uploaded files");
   }
   $csvfile_data = $_FILES['itmcsv_data'];

   //Browsers don't always get the type right
   //if( 'text/csv' != $csvfile_data['type'] ){
   //    throw new EWZ_Exception( "File type is " . $csvfile_data['type'] . ", should be text/csv" );
   //}

   if( $csvfile_data['error'] ){
       throw new EWZ_Exception( 'Failed to upload .csv file of item data: '  . ewz_upload_errmsg( $csvfile_data['error']) );
   }

   $file_tmp_name = $csvfile_data['tmp_name'];
   if ( !is_readable($file_tmp_name) ) {
       throw new EWZ_Exception( 'Failed to read uploaded .csv file of item data' );
   }

   $fh = fopen($file_tmp_name, 'r');
   if ( false === $fh ) {
       throw new EWZ_Exception( 'Failed to open uploaded .csv file of item data' );
   }
   fclose( $fh );

   $f_h = fopen($file_tmp_name, "r");
   $n = 0;
   $errs = '';
   while (( $data = fgetcsv($f_h, 1000 ))){
       if( isset( $data[0] ) ){
           $item_id = array_shift( $data );
           try{
               if( !is_numeric( $item_id ) ){
                   throw new EWZ_Exception( "File is not in correct format - please read help." );
               }
               $item = new Ewz_Item( intval( $item_id ) );
               if( $item->webform_id == $webform_id ){
                   // set_uploaded_admin_data sanitizes the data and converts to ASCII
                   $item->set_uploaded_admin_data( $data[0] );
                   $item->save();
                   ++$n;
               } else {
                   // item_id is part of user-generated input, so include it in error message
                   throw new EWZ_Exception( "Item $item_id not found in this webform" );
               }
           } catch( Exception $e ) {
               $errs .= "Item $item_id: ". $e->getMessage() . "\n";
           }
       }
   }
   fclose( $f_h );
   return $errs . "Item data for $n items successfully saved";
}



/**
 * Batch upload entry data for insertion into ewz_item
 *
 * @param    int $webform_id    webform
 * @param    string $entry_radio
 * @return   string message showing success or error
 */
function ewz_process_uploaded_entry_data( $webform_id, $entry_radio )
{

    //ini_set('auto_detect_line_endings',TRUE);  // Deperecated since php 8.1

    $do_check = ( $entry_radio == 'check' );
    // needed for Mac/Windows files
   // ini_set('auto_detect_line_endings', true); // Deperecated since php 8.1
   if( !isset( $_FILES['entry_data'] ) ){
       return( "No uploaded files");
   }
   $csvfile_data = $_FILES['entry_data'];
   if( $csvfile_data['error'] ){
       throw new EWZ_Exception( 'Failed to upload .csv file of entry data: ' . ewz_upload_errmsg( $csvfile_data['error'] ) );
   }

   $file_tmp_name = $csvfile_data['tmp_name'];
   if ( !is_readable($file_tmp_name) ) {
       throw new EWZ_Exception( 'Failed to read uploaded .csv file of entry data' );
   }
   $f_h = fopen($file_tmp_name, 'r');
   if ( false === $f_h ) {
       throw new EWZ_Exception( 'Failed to open uploaded .csv file of entry data' );
   }

   $webform = new Ewz_Webform($webform_id);
   $layout = new Ewz_Layout( $webform->layout_id);

   // read header line and set fields, is_img and is_bool arrays
   try{
       $headers = fgetcsv($f_h, 1000 );
       // remove empty columns at end, often generated by excel
       while ('' === end($headers)) {
           array_pop($headers);
       }

       $field_data = ewz_read_headers( $headers, $layout, $do_check );
       if( $field_data['errors'] ){
           return "Header Line Errors: <br>" . $field_data['errors'];
       }
   } catch( Exception $e ) {
       return $e->getMessage();
   }

   $msgs = '';
   if( $do_check ){
       $msgs = ewz_check_entry_data( $f_h, $webform, $layout, $field_data  );
   } else {
       $msgs = ewz_load_entry_data( $f_h, $webform, $layout,  $field_data  );
   }
   fclose( $f_h );
   return $msgs;
}

/**
 * Check each data row in the uploaded entry file by calling  Ewz_Upload_Input::check_rdata
 * Called by ewz_process_uploaded_entry_data
 *
 * @param resource     $f_h         open filehandle ( header line should already have been read )
 * @param Ewz_Webform  $webform     the Ewz_Webform object
 * @param Ewz_Layout   $layout      the Ewz_Layout object
 * @param array<mixed>  $field_data   with indexes field_ids, is_img, is_bool generated by reading the header line
 * @return string message showing all errors
 */
function ewz_check_entry_data( $f_h, $webform, $layout, $field_data  )
{
   $errs = '';
   $n = 0;
   $prev_user_id = "0";
   $rdata = array();
   $row_data = array();
   while (( $raw_csv_data = fgetcsv($f_h, 1000 ))){
       if($raw_csv_data[0]){   // ignore blank lines
           while ( ( '' === end($raw_csv_data) ) && ( count($raw_csv_data) > count($field_data['field_ids'])) ) {
               // ignore trailing blanks
               array_pop($raw_csv_data);
           }
           ++$n;
           // set up a single item row, convert the data to ASCII
           $row_data = ewz_get_entry_data_for_check(  $raw_csv_data,
                                                array( 'fids'    => $field_data['field_ids'],
                                                       'is_img'  => $field_data['is_img'],
                                                       'is_bool' => $field_data['is_bool'],
                                                    'upload_dir' => EWZ_IMG_UPLOAD_DIR . '/' . $webform->webform_ident,
                                                    'upload_url' => EWZ_IMG_UPLOAD_URL . '/' . $webform->webform_ident,
                                                    'webform_id' => $webform->webform_id
                                                    ));
           // if it's a new user, run the check on the accumulated rdata from the previous one
           if( $row_data['user_id'] !== $prev_user_id  ){
               if( $prev_user_id  !== "0" ){
                   try{
                       Ewz_Upload_Input::check_rdata( $rdata, $layout, $webform->num_items );
                   } catch( Exception $e ){
                       $errs .= "Data Errors For User $prev_user_id:<br> &nbsp; " . $e->getMessage() . '<br>' ;
                   }
                   $rdata = array();
               }
           }
            if( $row_data['ERRS'] ){
               $errs .= $row_data['user_id'] . " Item #$n:<br>" .  $row_data['ERRS'];
           }
           $rdata[] = $row_data['input_data'];   // append row to rdata array
           $prev_user_id = $row_data['user_id'];
       }
   }
   try{
       // run the check on the last user
       Ewz_Upload_Input::check_rdata( $rdata, $layout, $webform->num_items  );
   } catch( Exception $e ){
       $errs .= "Data Errors For User User $prev_user_id:<br> &nbsp; " . $e->getMessage() . '<br>' ;
   }
   return "<br>$errs<br><b>Entry data for $n items checked</b>";
}

/**
 * Save each row in the input file into the Ewz_Item table
 * Called by ewz_process_uploaded_entry_data
 *
 * @param resource     $f_h         open filehandle ( header line should already have been read )
 * @param Ewz_Webform  $webform     the Ewz_Webform object
 * @param Ewz_Layout   $layout
 * @param array<mixed>  $field_data  with indexes field_ids, is_img, is_bool generated by reading the header line
 * @return string      message showing errors and number of items saved
 */
function ewz_load_entry_data( $f_h, $webform, $layout, $field_data  )
{
   $errs = '';
   $renames = array();
   $n = 0;
   $upload_dir = EWZ_IMG_UPLOAD_DIR . '/' . $webform->webform_ident;

   // read each line and split on ',' into array $csv_data
   while (( $raw_csv_data = fgetcsv($f_h, 1000 ))){
       if($raw_csv_data[0]){   // ignore blank lines
           while ( ( '' === end($raw_csv_data) ) && ( count($raw_csv_data) > count($field_data['field_ids'])) ) {
               // ignore trailing blanks
               array_pop($raw_csv_data);
           }
           $csv_data = array();
           for( $i=0; $i < count($raw_csv_data); ++$i ){
               // excel does not easily handle non-ascii characters when generating csv, so convert.
               if( Ewz_Settings::get_ewz_option('csv_ascii') ){
                   $csv_data[$i] = mb_convert_encoding( $raw_csv_data[$i],'ASCII');
               } else {
                   $csv_data[$i] = $raw_csv_data[$i];
               }
               // change any filenames containing invalid characters
               if( isset($field_data['is_img'][$i]) && $field_data['is_img'][$i] ){
                   $olddata = $csv_data[$i];
                   $renamed_data = ewz_rename_files( $upload_dir, $olddata );
                       // returns $olddata, or array( fname:thumbname, new_fname:new_thumbname ) if files renamed.
                   if( $renamed_data != $olddata ){
                       $csv_data[$i] = $renamed_data[1];
                       array_push( $renames, $renamed_data );
                   }
               }
           }
           $row_data = array();
           try{
               // format the data for instantiating an Ewz_Item
               $row_data = ewz_get_entry_data_for_save(  $csv_data,
                                                array( 'fids'    => $field_data['field_ids'],
                                                       'is_img'  => $field_data['is_img'],
                                                       'is_bool' => $field_data['is_bool'],
                                                    'upload_dir' => EWZ_IMG_UPLOAD_DIR . '/' . $webform->webform_ident,
                                                    'upload_url' => EWZ_IMG_UPLOAD_URL . '/' . $webform->webform_ident,
                                                    'webform_id' => $webform->webform_id ));
           } catch( Exception $e ){
               $errs .= "<br>" . $e->getMessage();
           }
           try{
               $item = new Ewz_Item( $row_data );
               // item->save args are nodelete, nocountcheck
               // never delete on failure in batch mode, and don't do an item count check for the user if no userid
               $item->save( true, !$field_data['has_userid'] );
               ++$n;
           } catch( Exception $e ){
               $errs .= "<br>" . $e->getMessage();
           }
       }
   }
   $returnMsg = "<b>Entry data for $n items saved</b><br>";
   if( $renames ){
       $date = current_time( 'Ymd_Hi' );      // for filename ewz_{$date}_{$rand}.csv of spreadsheet within archive
       $outpath = $upload_dir . "/ewz_renamed_{$date}.csv";
       $out = fopen( $outpath, 'w' );
       if( !$out ){
           throw new EWZ_Exception( "Failed to open csv file for writing");
       }
       foreach( $renames as $rename ){
           fputcsv( $out, $rename );
       }
       fclose( $out );
       chmod( $outpath, 0644 );
   }

   if( $errs ){
       $returnMsg .= "**** ERRORS ***<br>$errs";
   }
   if( $renames ){
       $returnMsg .= "<br>". count($renames) . " Filenames were changed.<br>";
       $returnMsg .= "A .csv list of the changed filenames below has been placed in the image folder.<br><br>";
       foreach( $renames as $rename ){
           $returnMsg .= "'$rename[0]'" . " was changed to " . $rename[1] ."<br>";
       }
   }
   return "$returnMsg<br>";
}


/**
 * Read the input file and thumbnail names, which should be of form
 *  "filename:thumbname"  or just "filename" ( in which case the thumbnail should be "filename-thumb.jpg"
 * If they are not valid file names, change the data and change the filenames themselves to match
 *
 * @param string   $upload_dir
 * @param string   $imgdata
 * @return array<string>   $newdata
 */
function ewz_rename_files( $upload_dir, $imgdata ){

    $newdata = $imgdata;
    $imgfiles = explode(':',  trim( $imgdata ));
    if( !isset($imgfiles[1] )){
        // otherwise, assume thumbnail is filename followed by "-thumb"
        $imgfiles[1] = preg_replace( '/.jpg$/', '-thumb.jpg', $imgfiles[0] );
    }
    // replace quotes and special characters in filenames
    $newfilename = ewz_uniq_fname(
        ewz_to_valid_fname( $imgfiles[0],
        false
        ) );
    $newthumbname = ewz_uniq_fname(
        ewz_to_valid_fname( $imgfiles[1],
        false
        ) );
    if( $newfilename != $imgfiles[0] || $newthumbname != $imgfiles[1] ){
        if( $newfilename != $imgfiles[0] && is_file( $upload_dir . '/' . $imgfiles[0] ) ){
            rename(  $upload_dir . '/' . $imgfiles[0], $upload_dir . '/' . $newfilename );
        }
        if( $newthumbname != $imgfiles[1] && is_file( $upload_dir . '/' . $imgfiles[1]) ){
            rename(  $upload_dir . '/' . $imgfiles[1], $upload_dir . '/' . $newthumbname );
        }

        $newdata = array( "$imgfiles[0]:$imgfiles[1]", "$newfilename:$newthumbname");
    }
    return $newdata;
}


/**
 * Parse the header line of an entry upload file
 * Called by ewz_process_uploaded_entry_data
 * Throws an exception if a header is not a valid field identifier, or if do_check is true and there is no LoginName column.
 *
 * @param    array<string>      $headers    of data produced by fgetcsv from the first line of the file
 * @param    Ewz_Layout $layout    the Ewz_Layout
 * @param    boolean    $do_check  true if this is a data check, false if an actual save is to be done
 * @return   array<mixed> containing the field_id for each column, and whether it is a boolean or an image filename.
 */
function ewz_read_headers( $headers, $layout, $do_check )
{

   $field_ids = array();
   $is_img = array();
   $is_bool = array();
   $errs = '';

   if(!$headers){
       throw new EWZ_Exception( 'Uploaded file is empty.');
   }
   $has_userid = false;
   for( $i=0; $i < count($headers); ++$i ){
       if( $headers[$i] == 'LoginName' ){
           $field_ids[$i] = -1;
           $is_img[$i] = false;
           $is_bool[$i] = false;
           $has_userid = true;
       } else {
           foreach($layout->fields as $field){
               if( $field->field_ident == $headers[$i] ){
                   $field_ids[$i] = $field->field_id;
                   $is_img[$i] = ( $field->field_type == 'img' );
                   $is_bool[$i] = in_array( $field->field_type, array( 'chk','rad' ));
               }
           }
       }
       if(!isset($field_ids[$i])){
           $errs .= " &nbsp; Header '$headers[$i]' is not a valid field identifier for the layout<br>";
       }
   }
   if( $do_check && !$has_userid ){
       $errs .= " &nbsp; A LoginName column is required for checking data<br>";
   }
   return array( 'field_ids' => $field_ids,
                 'is_img'    => $is_img,
                 'is_bool'   => $is_bool,
                 'has_userid'=> $has_userid,
                 'errors'    => $errs,
               );
}

/**
 * Parses the data from the entry .csv file into a structure usable for instatiating Ewz_Item
 * Called by ewz_load_entry_data
 *
 * @param  array<mixed>    $csv_data   of data  produced by fgetcsv from a line of the input file
 * @param  array<mixed>    $finfo     array of field info produced by ewz_read_headers
 * @return  array<mixed>   usable for instatiating Ewz_Item
 */
function ewz_get_entry_data_for_save( $csv_data, $finfo ){

    $uid = '';
    $itmdata = array();
    $itmfiles = array();
    for( $i=0; $i < count($csv_data); ++$i ){
        $fid = $finfo['fids'][$i];
        if( $fid == -1 ){
            $uid = get_user_by('login', $csv_data[$i])->ID;
        } else {
            if( $finfo['is_img'][$i] ){
                $value = 'ewz_img_upload';
                // if data contains ':', assume it separates image file from thumbnail
                $imgfiles = explode(':',  trim( $csv_data[$i] ));
                // $size = getimagesize( "{$finfo['upload_dir']}/" . $imgfiles[0] );
                $fname = "{$finfo['upload_dir']}/" . $imgfiles[0];
                if( is_file($fname) ){
                    $size = getimagesize( $fname );
                } else {
                    $size =array(0,0);
                }

                if( !isset($imgfiles[1] )){
                    // otherwise, assume thumbnail is filename followed by "-thumb"
                    $imgfiles[1] = preg_replace( '/.jpg$/', '-thumb.jpg', $imgfiles[0] );
                }
                // full path required here, is removed just before saving
                $itmfiles[$fid] = array( 'field_id' => $fid,
                                         'thumb_url' => "{$finfo['upload_url']}/" . $imgfiles[1],
                                         'fname' =>  "{$finfo['upload_dir']}/" . $imgfiles[0],
                'type'=>"image/jpg",
                'width' => $size[0],
                'height' => $size[1],
                'orient' => ( $size[0] >= $size[1] ) ? 'L' : 'P'
                );
            } elseif( is_bool($csv_data[$i]) ){
                $value = (bool)$csv_data[$i];
            } else {
                $value = $csv_data[$i];
            }
            $itmdata[$fid] = array( 'field_id'=>$fid, 'value'=>$value );
        }
    }
    return array( 'user_id' => $uid ? $uid : get_current_user_id() ,
               'webform_id' => $finfo['webform_id'],
                'item_data' => $itmdata,
               'item_files' => $itmfiles );
}
/**
 * Parses the data from the entry .csv file into a structure usable for instantiating Ewz_Upload_Input
 * Called by ewz_check_entry_data
 *
 * @param  array<mixed>     $raw_csv_data   of data  produced by fgetcsv from a line of the input file
 * @param  array<mixed>     $finfo          array of field info produced by ewz_read_headers
 * @return array<mixed>     of 'input_data' - usable for instatiating Ewz_Upload_Input, plus 'user id'
 */
function ewz_get_entry_data_for_check( $raw_csv_data, $finfo ){

    $login = '';
    $tdata = array();
    $errs = '';
    for( $i=0; $i < count($raw_csv_data); ++$i ){
        if( Ewz_Settings::get_ewz_option('csv_ascii') ){
            $csv_data[$i] = mb_convert_encoding( $raw_csv_data[$i],'ASCII');
        } else {
            $csv_data[$i] = $raw_csv_data[$i];
        }
        $fid = $finfo['fids'][$i];
        if( $fid == -1 ){
             $login = $csv_data[$i];
             if( !username_exists( $login ) ){
                 $errs .= " &nbsp; &nbsp; Invalid login name: $login<br>";
             }
        } else {
            if( $finfo['is_img'][$i] ){
                $tdata[$fid] = 'ewz_img_upload';
                // if data contains ':', assume it separates image file from thumbnail
                $imgfiles = explode(':',  trim( $csv_data[$i] ) );
                if( !isset($imgfiles[1] )){
                    // otherwise, assume thumbnail it filename followed by "-thumb"
                    $imgfiles[1] = str_replace( '.jpg', '-thumb.jpg',  $imgfiles[0] );
                }
                if( !is_file( "{$finfo['upload_dir']}/" . $imgfiles[0]  ) ){
                    $errs .= " &nbsp; &nbsp; Missing file: {$finfo['upload_dir']}/" . $imgfiles[0] . "<br>";
                }
               if( !is_file( "{$finfo['upload_dir']}/" . $imgfiles[1]  ) ){
                    $errs .=  " &nbsp; &nbsp; Missing file: {$finfo['upload_dir']}/" . $imgfiles[1] . "<br>";
                }
            } elseif( is_bool($csv_data[$i]) ){
                $tdata[$fid] = (bool)$csv_data[$i];
            } else {
                $tdata[$fid] = $csv_data[$i];
            }
        }
    }
    $ret = array('input_data' => $tdata, 'user_id' => $login, 'ERRS' => $errs );
    return $ret;
}

/**
 * Store the per-image info in an uploaded csv file for a webform
 *
 * Checks to make sure item is attached to webform - otherwise, webform param is not
 * used, but seems a good idea to force a separate upload for each form.
 *
 * @param    int    $webform_id    webform
 * @return   string success message
 */
function ewz_process_uploaded_csv( $webform_id )
{
    // needed for Windows files ???
    //ini_set('auto_detect_line_endings', true);  // Deperecated since php 8.1
   if( !isset( $_FILES['imgcsv_data'] ) ){
       return( "No uploaded files");
   }

   $csvfile_data = $_FILES['imgcsv_data'];
   //Browsers don't always get the type right
   //if( 'text/csv' != $csvfile_data['type'] ){
   //    throw new EWZ_Exception( "File type is " . $csvfile_data['type'] . ", should be text/csv" );
   //}

   if( $csvfile_data['error'] ){
       throw new EWZ_Exception( 'Failed to upload .csv file of image data: ' . ewz_upload_errmsg( $csvfile_data['error'] ) );
   }

   $file_tmp_name = $csvfile_data['tmp_name'];
   if ( !is_readable($file_tmp_name) ) {
       throw new EWZ_Exception( 'Failed to read uploaded .csv file of image data' );
   }
   $f_h = fopen($file_tmp_name, 'r');
   if ( false === $f_h ) {
       throw new EWZ_Exception( 'Failed to open uploaded .csv file of image data' );
   }

   $n = 0;
   $errs = '';
   while (( $data = fgetcsv($f_h, 1000 ))){

       if( isset( $data[0] ) ){
           // remove empty columns at end, often generated by excel
           while ('' === end($data)) {
               array_pop($data);
           }
           $item_id = array_shift( $data );
           try{
               if( !is_numeric( $item_id ) ){
                   throw new EWZ_Exception( "File is not in correct format - please read help." );
               }
               $item = new Ewz_Item( intval( $item_id ) );
               if( $item->webform_id == $webform_id ){
                   // set_uploaded_info converts to ASCII for safety
                   $item->set_uploaded_info( array_pad( $data, 4, '' ) );
                   $item->save();
                   ++$n;
               } else {
                   // item_id is part of user-generated input, so include it in error message
                   throw new EWZ_Exception( "Item $item_id not found in this webform" );
               }
           } catch( Exception $e ) {
               $errs .= "Item $item_id: ". $e->getMessage() . "\n";
           }
       }
   }
   fclose( $f_h );
   return $errs . "Image Data for $n items successfully saved";
}


/**
 * Report on any discrepancies between the uploaded image files in ewz_img_uploads for the webform
 * and the references to image file paths in the database.
 *
 * @return string  message showing success or any discrepancies
 */
function ewz_do_file_report(){
    if( !( isset($_POST['webform_id']) &&  isset($_POST['webform_ident']) ) ){
        throw new EWZ_Exception( "Missing id and identifier for file report");
    }
    $wf_id = $_POST['webform_id'];
    $wf_ident = $_POST['webform_ident'];
    $items = Ewz_Item::get_items_for_webform( $wf_id, Ewz_Item::GET_ALL_ITEMS );
    $db_files = array();
    $ids = array();
    foreach( $items as $item ){
        foreach( $item->item_files as $field_id => $ifiles ){
            $th_file =  preg_replace( "/^.*ewz_img_uploads\/$wf_ident\//", '', $ifiles['thumb_url']);
            $l_file =  preg_replace( "/^.*ewz_img_uploads\/$wf_ident\//", '', $ifiles['fname']);
            array_push($db_files, $th_file );
            array_push($db_files, $l_file);
            $ids[$th_file] = $item->item_id;
            $ids[$l_file] = $item->item_id;
        }
    }
    $files = array();
    if ($dh = opendir( EWZ_IMG_UPLOAD_DIR . "/" . $_POST['webform_ident'] )) {
        while (($file = readdir($dh)) !== false) {
            if( !preg_match( '/^\./', $file  ) && ($file != 'index.php' ) ){
                array_push($files, $file);
            }
        }
        closedir( $dh );
    } else {
        return "No matching folder '" . $_POST['webform_ident'] . "' for webform.";
    }
    $extrafiles =  array_diff( $db_files, $files );
    $missingfiles =  array_diff(  $files, $db_files );
    $result = '';
    if( $extrafiles ){
        $result .= "<b>Files referenced by an item in the database but not in the ewz_img_uploads/$wf_ident folder</b><br>";
        foreach( $extrafiles as $f ){
            $result .= "  $f ( item " . $ids[$f] . ")<br>";
        }
    }
    if( $missingfiles ){
        $result .= "<b>Files in ewz_img_uploads/$wf_ident folder not referenced by any item in the database::</b><br>";
        foreach( array_diff(  $files, $db_files) as $f ){
            $result .= "  $f <br>";
        }
    }
    if( $result ){
        return $result;
    } else {
        return 'OK - Folder contents match Database';
    }
}

/**
 * Check for popen and the 'zip' system function, which is faster than using php's ZipArchive.
 *
 * @return boolean
 */
function ewz_has_zip(){

    $disabled = array_map( 'trim', explode( ',', ini_get('disable_functions' )));

    // check for popen
    $has = function_exists( 'popen' ) &&  !in_array( 'popen', $disabled );
    if( $has ){
        // check for system zip function
        $fp = popen( "zip --version", 'r' );
        if( !$fp ){
            $has = false;
        } else {
            $has = ( (bool)fgets($fp, 255) );
        }
        pclose($fp);
    }
    return $has;
}


/** ************************** Main Webforms Function ********************************
 * Generates the main web form management page.
 *
 * Checks for POST data, validates, sanitizes and processes it
 * Then outputs the page
 * The output consists mainly of json data and javascript in order to save transmitting
 *       almost the same html for each possible webform.
 * The main javascript is found in "javascript/ewz-webforms.js", which is enqueued
 *
 * @return void
 */

function ewz_webforms_menu()
{

    if ( !Ewz_Permission::can_see_webform_page() ) {
        wp_die( "Sorry, you do not have permission to view this page" );
    }
    $message = '';
    /*************************************************************/
    /* First, process any changes -  sanitize, reformat and save */
    /*************************************************************/
    // $ewzpage = ewz_admin_control();
    if( isset( $_POST['ewzmode'] ) ){
       try {
           switch( $_POST['ewzmode'] ){
               // 'spread', 'download', 'images'  are caught by the ewz_echo_data
               // function in ewz_admin.php, which is hooked to plugins_loaded

           case  'webform':

               // validate all input data ( except uploaded files )
               $input = new Ewz_Webform_Input( array_merge( $_POST, $_GET ) );
               $webform = new Ewz_Webform( $input->get_input_data() );
                                     // text fields are sanitized before saving
               $webform->save();
               break;

           case 'imgcsv_data':
               // upload a csv of titles, content, etc for images
               // first validate $_POST, $_GET - raises exceptions on problems
               $input = new Ewz_CSV_Input( array_merge( $_POST, $_GET ) );
               $data = $input->get_input_data();
               // then process $_FILES
               $message = ewz_process_uploaded_csv( $data['webform_id'] );
               break;
           case 'itmcsv_data':
               // upload a csv of text data form items
               // first validate $_POST, $_GET - raises exceptions on problems
               $input = new Ewz_CSV_Input( array_merge( $_POST, $_GET ) );
               $data = $input->get_input_data();
               // then process $_FILES
               $message = ewz_process_uploaded_admin_data( $data['webform_id'] );
               break;
           case 'entrydata':
               // upload a csv of entries to be loaded into the webform
               // first validate $_POST, $_GET - raises exceptions on problems
               $input = new Ewz_CSV_Input( array_merge( $_POST, $_GET ) );
               $data = $input->get_input_data();

               // then process $_FILES
               $message = ewz_process_uploaded_entry_data( $data['webform_id'], $data['entry_radio'] );
               break;

           default:
               throw new EWZ_Exception( 'Invalid Input ', 'mode=' . preg_replace( '/[^a-z0-9 _-]/i', '_', $_POST['ewzmode'] ) );
           }
       } catch( Exception $e ) {
          $message .= $e->getMessage();
       }
    }
    try{

        /******************************************************/
        /* Get the user list, webforms and the layout options */
        /* Format the data for html output where necessary    */
        /******************************************************/

        $webforms = array_values( Ewz_Webform::get_all_webforms( 'can_view_webform', false ));
                 // list of users for whom the webform may be opened,
                 // or null if current user has no permission to list them

        $can_edit_all_webforms = Ewz_Permission::can_edit_all_webforms();
                                            // needed to create a new one

        $nonce_string = wp_nonce_field( 'ewzadmin', 'ewznonce', true, false );
        foreach ( $webforms as $webform ) {
            $webform->add_display_info();   // info needed for main webforms page, but not for other purposes
        }

        $hidden = Ewz_Webform::get_hidden_webforms_opt_array('can_view_webform');

        /*******************************/
        /* Pass the data to Javascript */
        /*******************************/
        $ewzG = array( 'webforms' => $webforms );
        $ewzG['hidden_webforms_options'] = ewz_option_list( $hidden );
        $ewzG['hidden_webforms_options_count'] = count( $hidden );
        $ewzG['list_page'] = admin_url( 'admin.php?page=entrywizlist' );
        // the webform that should start off open
        $openwebform_id = 0;
        if ( array_key_exists( 'openwebform', $_GET ) ){
            $formid = $_GET['openwebform'];
            if( preg_match( '/^[0-9]+$/', $formid ) && strlen( $formid ) < 10 ) {
                $openwebform_id = $formid;
            }
        }
        $ewzG['now'] = current_time('mysql');
        $ewzG['tz'] = get_option('timezone_string');
        $ewzG['time_opts_nosel'] = ewz_option_list(Ewz_Webform::get_time_opt_array(''));
        $ewzG['dateFormat'] = Ewz_Base::toDatePickerFormat( get_option( 'date_format' ) );

        $ewzG['openform_id'] = $openwebform_id;
        $ewzG['message'] = wp_kses( $message, array( 'br' => array(), 'b' => array() ) );
        $ewzG['base_options'] = ewz_option_list( Ewz_Layout::get_layout_opt_array( 'can_assign_layout' ) );

        $ewzG['ipp'] = get_user_meta( get_current_user_id(), 'ewz_itemsperpage', true );

        $ewzG['nonce_string'] = $nonce_string;
        $ewzG['can_edit_all'] = $can_edit_all_webforms;
        $ewzG['load_gif'] = plugins_url( 'images/loading.gif', dirname(__FILE__) ) ;
        $ewzG['helpIcon'] = plugins_url( 'images/help.png' , dirname(__FILE__) ) ;
        $ewzG['maxUploadMb'] = EWZ_MAX_SIZE_MB;

        $ewzG['canzip'] = ewz_has_zip();

        $ewzG['hasRating'] = defined( 'EWZ_RATING_VERSION' );
        $ewzG['errmsg'] = array(
            'saveforms' => esc_html__("Please save your unsaved Webforms before trying to rearrange them", 'entrywizard'),
            'nofile' => esc_html__('No file selected', 'entrywizard'),
            'unexpected' => esc_html__("Sorry, there was an unexpected error: ", 'entrywizard'),
            'server' => esc_html__('Sorry, there was a server error: ', 'entrywizard'),
            'unknown' => esc_html__('Sorry, there was an unknown error while saving the webform.', 'entrywizard'),
            'warn' => esc_html__('*** WARNING ***', 'entrywizard'),
            'reallydelete' => esc_html__('Really delete the entire webform?', 'entrywizard'),
            'noundo' => esc_html__('This action cannot be undone', 'entrywizard'),
            'hasitems' => esc_html__('Deleting this webform will also delete ALL its uploaded items.', 'entrywizard'),
            'formTitle' => esc_html__('Please enter a title for the webform.', 'entrywizard'),
            'formIdent' => esc_html__('Each webform must have an identifier ( max 15 characters ) that consists only of letters, digits, dashes and underscores.', 'entrywizard'),
            'formPrefix' => esc_html__('The prefix may contain only letters, digits, dashes, underscores
                and the special expressions listed in the help window. Make sure there are no spaces.', 'entrywizard'),
            'numPrefix' => esc_html__('The [~1] expression in the prefix is only valid if you are generating entire
                filenames for uploaded images. Either remove it or check "Generate a filename using the prefix"', 'entrywizard'),
            'spPrefix' => esc_html__('A space is not allowed in the prefix for files stored on the server. Either remove any spaces or uncheck "Apply prefix on upload"', 'entrywizard'),
            'needopentime' => esc_html__("Date and Time required For automatic opening.", 'entrywizard'),
            'needclosetime' => esc_html__("Date and Time required For automatic closing.", 'entrywizard'),
            'hasdata' => esc_html__("WARNING: This form has uploaded data. Changing the identifier, layout or prefix options now could cause major problems.", 'entrywizard'),
            'usedinrating' => defined( 'EWZ_RATING_VERSION' ) ? esc_html__("NOTE: If a webform is used in a Rating Form, its layout must match that of the scheme.", 'entrywizard') : ''
        );
        $ewzG['jsvalid'] = Ewz_Base::validate_using_javascript();
                           // normally true, set false to test server validation
        wp_localize_script( 'ewz-admin-webforms', 'ewzG1',  array( 'gvar'=>$ewzG ) );

    ?>
    <div class="wrap">
        <h2>EntryWizard Web Form Management</h2>
         <p><img alt="Help icon" class="ewz_ihelp" src="<?php print $ewzG['helpIcon']; ?>" onClick="ewz_help('shortcode');">
            &nbsp; A regular webform may be inserted into any page using the shortcode &nbsp;
                 <b>&#91;ewz_show_webform&nbsp;identifier="xxx"&#93;</b>
             &nbsp; where xxx is the identifier you created for the form</p><br>

   <div id="top-controls" >
      <?php ewz_get_webform_controls($ewzG, $hidden); ?>
  </div>
     <div id="ewz_actions">
        <?php if(count( $hidden ) > 0 ){ ?>
             <i><br>( <?php print count( $hidden ); ?> webforms are hidden and will not be selected )<br></i>
        <?php } ?>
        <div id="ewz_all_check"><input type="checkbox" id="ewz_all_forms" onClick="toggle_all_forms()"> Select All</div>

        <div id="ewz_bulk">
           <img alt="Help icon" class="ewz_ihelp" src="<?php print $ewzG['helpIcon']; ?>" onClick="ewz_help('cleanup');">
           <select name="action" id="bulk-action-selector">
              <option value="-1">--- Bulk Actions ---</option>
              <option value="ewz_batch_delete_webforms">Delete All Selected WebForms</option>
              <option value="ewz_batch_delete_items">Delete All Items From Selected WebForms</option>
              <option value="ewz_hide_webforms">Hide Selected WebForms</option>
           <?php if( !$ewzG['canzip'] ){ ?>
                 <option value="ewz_remove_zipfiles">Clean Up Folders For Selected WebForm </option>
           <?php } ?>
           </select>
           <button type="button" class="button-secondary" id="dobatch" onclick="do_batch()">Apply</button>
        </div>
     </div>

             <div id="ewz_management">
               <div id="ewz_numc"><?php print $ewzG['nonce_string']; ?></div>
               <br>
             </div>

      <?php ewz_show_webform_help($webforms); ?>

    </div> <!-- wrap -->

    <?php
    } catch( Exception $e ){
        wp_die( $e->getMessage() );
    }

}

// end function ewz_webforms_menu


/* * ********************** End Main Webforms Function ******************* */
  function ewz_get_webform_controls($ewzG, $hidden ){
        ?>
      <div style="float:right">
         <img alt="Help icon" class="ewz_ihelp" src="<?php print  $ewzG['helpIcon']; ?>" onClick="ewz_help('wfcompressed')"> &nbsp;
         Show Compressed View <input type="checkbox" onClick="wforms_compress_lines(this)">
      <br><br>

      <img alt="Help icon" class="ewz_ihelp" src="<?php print  $ewzG['helpIcon']; ?>" onClick="ewz_help('wfauto')">
      <button type="button" class="button-secondary" id="crons" onclick="get_crons()">List Scheduled Open/Close Events</button>
      <br><br>
      <?php if(count( $hidden ) > 0 ){ ?>
         <div class='ewz_hidden'>
             <img alt="Help icon" class="ewz_ihelp" src="<?php print  $ewzG['helpIcon']; ?>" onClick="ewz_help('wfhidden')">
            <button  type="button" class="button-secondary" id="webforms_unhide_" onClick="unhide_webforms()">Unhide Selected Webforms</button>
            <select multiple size="3" name="ewz_unhide" id="ewz_unhide">
               <?php print  ewz_option_list( $hidden ); ?>
            </select>
         </div>
      <?php   }?>
      </div>


      <img  class="ewz_ihelp" src="<?php print $ewzG['helpIcon']; ?>" onClick="ewz_help('wfnew')">&nbsp;
      <button  type="button" class="button-secondary" id="webform_add_" onClick="add_new_webform()">Add a New Web Form</button>
      <br><br>
      <div class='ewz_order'>
        Webforms may be dragged to rearrange.<br><br>
         <button  type="button"  class="button-secondary"  id="webforms_sort" onClick="sort_alpha()">Sort Webforms Alphabetically</button>
        <br><br>
          <button  type="button"  class="button-secondary" id="webforms_save1_" onClick="save_webform_order()">Save Order of Webforms</button>
      </div>

<?php }
