function amr_build_col_headings($s)
{
    // get the user column nice names, which could be combo fields
    global $aopt, $amain, $amr_current_list, $amr_nicenames;
    $line = array();
    $line[0] = 'ID';
    // must be first
    foreach ($s as $is => $cl) {
        // for each selected and sorted
        $colno = (int) $cl;
        $value = agetnice($is);
        if (!empty($line[$colno])) {
            $line[$colno] = $line[$colno] . ' ' . $value;
        } else {
            $line[$colno] = $value;
        }
    }
    return $line;
}
function amr_build_user_data_maybe_cache($ulist = '1')
{
    //returns the lines of data, including the headings
    global $amr_refreshed_heading;
    // seems heading not used right when we are filtering. workaround for now.
    /* Get the fields to use for the chosen list type */
    global $aopt, $amrusers_fieldfiltering;
    global $amain;
    global $wp_post_types;
    global $time_start;
    global $cache;
    global $amr_current_list;
    $amr_current_list = $ulist;
    if (get_transient('amr_users_cache_' . $ulist)) {
        track_progress('Stop - run for ' . $ulist . ' in progress already according to transient');
        return false;
    }
    //else track_progress('Set in progress flag for '.$ulist);
    set_transient('amr_users_cache_' . $ulist, true, 10);
    // 10 seconds allowed for now
    $network = ausers_job_prefix();
    //	track_progress('Getting data for network='.$network);
    register_shutdown_function('amr_shutdown');
    set_time_limit(360);
    // should we make this an option....
    $time_start = microtime(true);
    ameta_options();
    $date_format = get_option('date_format');
    $time_format = get_option('time_format');
    add_filter('pub_priv_sql_capability', 'amr_allow_count');
    // checked by the get_posts_by_author_sql
    if (!isset($amrusers_fieldfiltering)) {
        $amrusers_fieldfiltering = false;
    }
    if (function_exists('amr_check_for_realtime_filtering')) {
        amr_check_for_realtime_filtering($ulist);
    }
    if (empty($aopt['list'][$ulist])) {
        track_progress('No configuration for list ' . $ulist);
        return false;
    }
    $l = $aopt['list'][$ulist];
    /* *get the config  with any additional filtering */
    $rptid = amr_rptid($ulist);
    if (!$amrusers_fieldfiltering) {
        // then do cache stuff
        /* now record the cache attempt  */
        $cache = new adb_cache();
        $r = $cache->clear_cache($rptid);
        //		If (!($r)) echo '<br />Cache does not exist or not cleared for '.$rptid;
        $r = $cache->record_cache_start($rptid, $amain['names'][$ulist]);
        //		If (!($r)) echo '<br />Cache start not recorded '.$rptid;
        //		$cache->log_cache_event(sprintf(__('Started cacheing report %s','amr-users'),$rptid));
    }
    // end cache
    //track_progress('before get all users needed');
    $list = amr_get_alluserdata($ulist);
    /* keyed by user id, and only the non excluded main fields and the ones that we asked for  */
    $total = count($list);
    //track_progress('after get all user data'.$total);
    $head = '';
    $tablecaption = '';
    if ($total > 0) {
        if (isset($l['selected']) and count($l['selected']) > 0) {
            $head .= PHP_EOL . '<div class="wrap" style ="clear: both; text-align: center; font-size:largest;"><!-- heading wrap -->' . PHP_EOL . '<strong>' . $amain['names'][$ulist] . '</strong>';
            /* to look like wordpress */
            $tablecaption .= '<caption> ' . $amain['names'][$ulist] . '</caption>';
            $head .= '<ul class="report_explanation" style="list-style-type:none;">';
            /* check for filtering */
            if (isset($l['excluded']) and count($l['excluded']) > 0) {
                /* do headings */
                $head .= '<li><em>' . __('Excluding where:', 'amr-users') . '</em> ';
                foreach ($l['excluded'] as $k => $ex) {
                    if (is_array($ex)) {
                        $head .= ' ' . agetnice($k) . '=' . implode(__(' or ', 'amr-users'), $ex) . ',';
                    } else {
                        $head .= ' ' . agetnice($k) . '=' . $ex . ', ';
                    }
                    if (empty($list)) {
                        return;
                    }
                    foreach ($list as $iu => $user) {
                        if (isset($user[$k])) {
                            /* then we need to check the values and exclude the whole user if necessary  */
                            if (is_array($ex)) {
                                if (in_array($user[$k], $ex)) {
                                    unset($list[$iu]);
                                }
                            } else {
                                if ($user[$k] == $ex) {
                                    unset($list[$iu]);
                                }
                            }
                        }
                    }
                }
                $head = rtrim($head, ',');
                $head .= '</li>';
            }
            if (isset($l['excludeifblank']) and count($l['excludeifblank']) > 0) {
                $head .= '<li><em>' . __('Exclude if blank:', 'amr-users') . '</em> ';
                foreach ($l['excludeifblank'] as $k => $tf) {
                    $head .= ' ' . agetnice($k) . ',';
                    if (empty($list)) {
                        return;
                    }
                    foreach ($list as $iu => $user) {
                        /* now check each user */
                        if (empty($user[$k])) {
                            /* if does not exists or empty then we need to check the values and exclude the whole user if necessary  */
                            unset($list[$iu]);
                        }
                    }
                }
                $head = rtrim($head, ',');
                $head .= '</li>';
            }
            //if (WP_DEBUG) track_progress('after excluding users:'.count($list));
            if (isset($l['includeonlyifblank']) and count($l['includeonlyifblank']) > 0) {
                $head .= '<li><em>' . __('Include only if blank:', 'amr-users') . '</em> ';
                foreach ($l['includeonlyifblank'] as $k => $tf) {
                    $head .= ' ' . agetnice($k) . ',';
                    if (empty($list)) {
                        return;
                    }
                    foreach ($list as $iu => $user) {
                        /* now check each user */
                        if (!empty($user[$k])) {
                            /* if does not exists or empty then we need to check the values and exclude the whole user if necessary  */
                            unset($list[$iu]);
                        }
                    }
                }
                $head = rtrim($head, ',');
                $head .= '</li>';
            }
            //if (WP_DEBUG) track_progress('after checking include if blank:'.count($list));
            if (isset($l['included']) and count($l['included']) > 0) {
                $head .= '<li><em>' . __('Including where:', 'amr-users') . '</em> ';
                foreach ($l['included'] as $k => $in) {
                    //if (WP_DEBUG) {echo '<br />Check include:'.$k;var_dump($in);}
                    $inc = implode(__(' or ', 'amr-users'), $in);
                    $head .= ' ' . agetnice($k) . '=' . $inc . ',';
                    //if (WP_DEBUG) {echo '<br />'.$head;}
                    if (!empty($list)) {
                        foreach ($list as $iu => $user) {
                            /* for each user */
                            if (isset($user[$k])) {
                                /* then we need to check the values and include the user if a match */
                                // user[k] could be csv multiple values
                                // inclusions an array, so need to do a like? or a
                                $is_in = false;
                                //if (WP_DEBUG) {echo '<br />Check user:'******',');
                $head .= '</li>';
            }
            //if (WP_DEBUG) {	track_progress('after checking includes '.count($list));//echo '<br />'.$head;				}
            if (isset($l['sortby']) and count($l['sortby']) > 0) {
                $head .= '<li class="sort"><em>' . __(' Cache sorted by: ', 'amr-users') . '</em>';
                /* class used to replace in the front end sort info */
                asort($l['sortby']);
                // sort the sortbys first, so that $cols is in right order
                $cols = array();
                foreach ($l['sortby'] as $sbyi => $sbyv) {
                    if (isset($l['sortdir'][$sbyi])) {
                        //$cols[$sbyi] = array(SORT_DESC);  20111214
                        $cols[$sbyi] = SORT_DESC;
                    } else {
                        //$cols[$sbyi] =  array(SORT_ASC);  20111214
                        $cols[$sbyi] = SORT_ASC;
                    }
                    $head .= agetnice($sbyi) . ',';
                }
                //track_progress('after sortby '.$ulist);
                $head = rtrim($head, ',');
                $head .= '</li>';
                //track_progress('before msort cols =  '.count($cols));
                if (!empty($cols)) {
                    $list = auser_multisort($list, $cols);
                }
                //track_progress('after msort '.$ulist);
            }
            unset($cols);
            if (empty($list)) {
                $tot = 0;
            } else {
                $tot = count($list);
            }
            //track_progress('after sorting '.$tot.' users');
            if ($tot === $total) {
                $text = sprintf(__('All %1s Users processed.', 'amr-users'), $total);
            } else {
                $text = sprintf(__('%1s Users processed from total of %2s', 'amr-users'), $tot, $total);
            }
            //$tottext = 	sprintf(__('%1s records in list', 'amr-users'), $tot);
            $head .= '<li class="selected">' . $text . '</li>';
            $head .= '</ul>' . PHP_EOL . '</div><!-- heading wrap -->' . PHP_EOL;
            //if (WP_DEBUG) {echo '<br />'.$head;}
            $html = $head;
            if (empty($amr_refreshed_heading)) {
                $amr_refreshed_heading = $head;
            } else {
                $amr_refreshed_heading = $head . $amr_refreshed_heading;
            }
            $html = $head;
            $count = 0;
            //now make the fields into columns
            if ($tot > 0) {
                //if (empty($list)) echo '<br />1What happened list is empty ';
                if (!empty($l['grouping'][1])) {
                    $grouping_field = $l['grouping'][1];
                }
                $sel = $l['selected'];
                asort($sel);
                /* get the selected fields in the display  order requested */
                foreach ($sel as $s2 => $sv) {
                    if ($sv > 0) {
                        $sel2[$s2] = $sv;
                    }
                }
                // here we can jump in and save the filter values, if we are NOT already doing a real timefilter
                // if do filtering , then build up filter for values now
                if (!$amrusers_fieldfiltering and function_exists('amr_save_filter_fieldvalues')) {
                    $combofields = amr_get_combo_fields($ulist);
                    if (empty($list)) {
                        echo '<br />What happened list is empty ';
                    }
                    amr_save_filter_fieldvalues($ulist, $list, $combofields);
                }
                /* get the col headings ----------------------------*/
                $lines[0] = amr_build_cols($sel2);
                // tech headings
                $lines[1] = amr_build_col_headings($sel2);
                // the headings lines
                foreach ($lines[1] as $jj => $kk) {
                    if (empty($kk)) {
                        $lines[1][$jj] = '""';
                    } else {
                        $lines[1][$jj] = '"' . str_replace('"', '""', $kk) . '"';
                    }
                    /* Note for csv any quote must be doubleqouoted */
                }
                if (!$amrusers_fieldfiltering) {
                    // then do cache stuff
                    /* cache the col headings ----------------------------*/
                    //$csv = implode (",", $iline);
                    $cache->cache_report_line($rptid, 0, $lines[0]);
                    /* cache the internal column headings */
                    //					$cols = amr_users_get_column_headings  ($ulist, $line, $iline);
                    //$csv = implode (",", $line);
                    $cache->cache_report_line($rptid, 1, $lines[1]);
                    /* cache the column headings */
                    //unset($cols);
                    //unset($line);unset($iline);
                    unset($lines);
                    //track_progress('before cacheing list');
                }
                $count = 1;
                if (!empty($list)) {
                    foreach ($list as $j => $u) {
                        //if (WP_DEBUG) echo '<br />Building list add: '.$j; var_dump($u);;
                        $count = $count + 1;
                        unset($line);
                        if (!empty($u['ID'])) {
                            $line[0] = $u['ID'];
                        } else {
                            $line[0] = '';
                        }
                        foreach ($sel2 as $is => $v) {
                            /* defines the column order */
                            $colno = (int) $v;
                            if (!isset($u[$is])) {
                                $value = '';
                            } else {
                                $value = $u[$is];
                            }
                            /* unfortunately for fields, this must be done here */
                            if (!empty($value)) {
                                if (!empty($l['before'][$is])) {
                                    $value = html_entity_decode($l['before'][$is]) . $value;
                                }
                                if (!empty($l['after'][$is])) {
                                    $value = $value . html_entity_decode($l['after'][$is]);
                                }
                            }
                            if (!empty($line[$colno])) {
                                $line[$colno] .= $value;
                            } else {
                                $line[$colno] = $value;
                            }
                        }
                        if (function_exists('ausers_build_format_column')) {
                            // code to call extra function added as per andy.bounsall request, not yet fully tested by me
                            foreach ($line as $colno => $value) {
                                $line[$colno] = ausers_build_format_column($ulist, $colno, $value);
                            }
                        }
                        /* ******  PROBLEM - ok now? must be at end*/
                        /* *** amr - can we save the grouping field value similar to the index maybe ? */
                        if (!empty($grouping_field) and !empty($u[$grouping_field])) {
                            $line[99998] = $u[$grouping_field];
                        }
                        //							else
                        //								$line[99998] = '';
                        // save the index value if have it
                        if (!empty($u['index'])) {
                            $line[99999] = $u['index'];
                        } else {
                            $line[99999] = '';
                        }
                        $lines[$count] = $line;
                        unset($line);
                    }
                }
                if (empty($lines)) {
                    echo '<br / >Problem - no lines';
                }
                //else if (WP_DEBUG) {echo '<br />'; var_dump($lines);}
                unset($list);
                // do not need list, we got the lines now
                if (!$amrusers_fieldfiltering) {
                    // then do cache stuff
                    $cache->cache_report_lines($rptid, 2, $lines);
                }
            } else {
                $html .= sprintf(__('No users found for list %s', 'amr-users'), $ulist);
            }
        } else {
            $html .= '<h2 style="clear:both; ">' . sprintf(__('No fields chosen for display in settings for list %s', 'amr-users'), $ulist) . '</h2>';
        }
    } else {
        $html .= __('No users in database! - que pasar?', 'amr-users');
    }
    unset($s);
    //track_progress('nearing end');
    if (!$amrusers_fieldfiltering) {
        // if we are not just doing a real time filtering where we will not have full data then do cache stuff
        $cache->record_cache_end($rptid, $count - 1);
        $cache->record_cache_peakmem($rptid);
        $cache->record_cache_headings($rptid, $html);
        $time_end = microtime(true);
        $time = $time_end - $time_start;
        $cache->log_cache_event('<em>' . sprintf(__('Completed %s in %s microseconds', 'amr-users'), $rptid, number_format($time, 2)) . '</em>');
    }
    if (!empty($amain['public'][$ulist])) {
        // returns url if set to go to file
        $csvurl = amr_generate_csv($ulist, true, false, 'csv', '"', ',', chr(13) . chr(10), true);
    }
    delete_transient('amr_users_cache_' . $ulist);
    // so another can run
    //track_progress('Release in progress flag for '.$ulist);
    delete_transient('amr-users-html-for-list-' . $ulist);
    // to force use of new one
    // we built up the html when filtering, but then trashed again ?
    if (!empty($lines)) {
        return $lines;
    } else {
        return false;
    }
}