<?php
	
function amrmeta_validate_nicenames()	{
	global $amr_nicenames;
	
		if (empty ($amr_nicenames)) echo 'Unexpected problem - No nicenames !!!';
		
		$amr_nicenames['ID'] = '';
		
		if (isset($_POST['nn'])) { 
			
			if (is_array($_POST['nn'])) {
				foreach ($_POST['nn'] as $i => $v) {
					if (empty($v)) $amr_nicenames[$i] = '';
					else { 
						if	($s = esc_attr($v))  		
							$amr_nicenames[$i] = $s;
						else { 
							echo '<h2>Error in string:'.$s.'</h2>';
							return(false);
							}	
					}
					}
	
				}
			else {
				echo '<h2>Array of names not passed</h2>';
				return(false);
				}
			}
		ausers_update_option ('amr-users-nicenames', $amr_nicenames);		

		$excluded = array(); 
		if ((isset($_POST['nex'])) and (is_array($_POST['nex']))) {
			foreach ($_POST['nex'] as $i => $v) {
				if ($v) $excluded[$i] = true; 
			}
		}
		ausers_update_option('amr-users-nicenames-excluded', $excluded);	
		
		$showinwplist = array(); 
		if ((isset($_POST['wp'])) and (is_array($_POST['wp']))) {
			foreach ($_POST['wp'] as $i => $v) {
				if ($v) $showinwplist[$i] = true; 
			}
		}
		ausers_update_option('amr-users-show-in-wplist', $showinwplist);
		
		$ftypes = array(); 
		if ((isset($_POST['ftype'])) and (is_array($_POST['ftype']))) {
			foreach ($_POST['ftype'] as $i => $v) {
				if ($v) $ftypes[$i] = esc_attr($v); 
			}
		}
		
		ausers_update_option('amr-users-field-types', $ftypes);
		
		echo amr_users_message(__('Options Updated', 'amr-users')); 	
		return (true);	
	}

function ameta_listnicefield ($nnid, $nnval, $v, $v2=NULL) {
	
		echo "\n\t".'<li><label class="lists" for="nn'.$nnid.'"  '.(is_null($v2)?'>':' class="nested" >') .$v.' '.$v2.'</label>'
		.'<input type="text" size="50" id="nn'.$nnid.'"  name="nn['.$nnid.']"  value= "'.$nnval.'" /></li>'; 
	}

function alist_rebuild_names () {	
	return ('
	<div style="float:left; padding: 0 10px;" class="submit">
		<input type="hidden" name="action" value="save" />
		<input type="submit" class="button" name="rebuild" value="'. __('Find any new fields.', 'amr-users') .'" />
	</div>');
	}

function alist_rebuild_names_update () {	
	return ('
	<div style="float:left; padding: 0 10px;" class="submit">
		<input type="hidden" name="action" value="save" />
		<input class="button-primary" type="submit" name="update" value="'. __('Update', 'amr-users') .'" />
		 &nbsp;  &nbsp;  &nbsp;  &nbsp; 
		<input type="submit" class="button" name="rebuild" value="'. __('Find any new fields.', 'amr-users') .'" />
		 &nbsp;  &nbsp;  &nbsp;  &nbsp; 
		<input type="submit" class="button" name="resetnice" value="'. __('Reset and make new nice names', 'amr-users') .'" />
	</div>');
	}	

function ameta_list_nicenames_for_input($nicenames) {

	$fields_types_fixed = amr_fixed_fieldstypes(); //20170912 stop people messing up because they think its a format option
	
	/* get the standard names and then the  meta names  */
		if (!($excluded = ausers_get_option('amr-users-nicenames-excluded'))) 
			$excluded = array();
		if (!($showinwplist = ausers_get_option('amr-users-show-in-wplist')))
			$showinwplist = array();
			
		if (!($fields_types = ausers_get_option('amr-users-field-types')))
			$fields_types = $fields_types_defaults;
		
		
		$fieldtypes = amr_fieldtypes();	//the generic list
		
		//we need to allow manual exclusion of metakeys becuase of s2members strange time keys on access_cap_limits and who knows there might be others.	
		if (!($excluded_meta_keys = ausers_get_option('amr-users-excluded-meta-keys')))  
			$excluded_meta_keys = amr_default_excluded_metakeys();
		
		foreach ($excluded_meta_keys as $k=> $on) { // just get the excluded ones
			if (!$on) unset ($excluded_meta_keys[$k]);
		}		
			
		$orig_mk = ausers_get_option('amr-users-original-keys') ;	
		$wpfields = amr_get_usermasterfields();		
		foreach ($nicenames as $i=> $k) {
			// just in case, check exclude
			if (isset ($excluded_meta_keys[$i])) {
				if (!empty ($excluded_meta_keys[$i] )) {
					unset ($nicenames[$i]);
				}
			}
		}		
			
		ksort($nicenames);	
		//force excluded fields to the bottom
		foreach ($nicenames as $n => $nn) {
			if (empty($excluded[$n])) $sorttotop[$n] = true;
		}
		$nicenames =  auser_sortbyother($nicenames, $sorttotop);
		
		
		$total = count($nicenames);
		$totalex = count($excluded_meta_keys);
			
		echo PHP_EOL.'<div class="clear"> </div>'.PHP_EOL;	
		echo '<div><!-- nice names list-->';
		echo '<h2>'.__('Fields &amp; Nice Names', 'amr-users').' ('.$total.')  '
		.'</h2>'
		.'<p><a href="'.admin_url('admin.php?page=ameta-admin-meta-keys.php').'">'
		.sprintf(__('Note: %s meta keys excluded.','amr-users'),$totalex)
		.'</a> '
		.__('Some pseudo fields added','amr-users').'.'
		.' '
		//.'<h3>'.__('Nicer names for list headings','amr-users').'</h3>'
		//.'<ul>'
		//.'<li>'
		//.__('Extracts all user meta records (almost, some specifically excluded.)','amr-users')

		.' <strong>'.__('Sample data MUST exist!','amr-users').'</strong>'		
		.'</p>'
				
		// indicate additonal fields available
		.'<p>'
		.__('Roles and First bbpress Forum role','amr-users')

		.': <a title="'.__('Read more about multiple roles per users.','amr-users')
		.'" href="https://wpusersplugin.com/4799/roles-first-role-bbpress-forum-roles-s2member-levels/">'
		.__('Multiple roles per user?','amr-users')
		.'</a>: '
		.'<a title="'.__('Get plus addons to add more features and functionality','amr-users')
		.'" href="https://wpusersplugin.com/related-plugins/">'
		.__('Read about add-ons?','amr-users')
		.'</a>'
		.'</p>';
		
		//.'</li>'
		//.'<li>'
		//.__('Digs deep into composite records, to extract out "fields" that should have been simple meta.','amr-users')
		//	.'</li>'
		//.'<li>'
		//.__('Composite user meta are usually created by plugins who do not do things the way wordpress intended.','amr-users')
		//.'</li>'
		//.'<li>'		
		//.__('If the necessary add ons have been activated, will dig deeper or look further into other tables.','amr-users')
		//.'</li> '
		//.'</ul>' ;
		
		echo alist_rebuild_names_update();
		echo 
		'<table class="widefat">';
		echo '<tr><th>'
		.__('Technical Name','amr-users')
		.'</th><th>'
		.__('Nice Name','amr-users')
		.'</th>'
		.'<th>'
		.'<a title="'.__('Yes the main wordpress user list','amr-users').'" href="'.network_admin_url('users.php').'">'
		.__('Show in wp user list?','amr-users')
		.'</a>'
		.'<br /><em>'.__('wp fields only','amr-users').'</em>'
		.'</th>'
		.'<th>'
		.__('Exclude from all reports?','amr-users')
		.'</th>'
		.'<th>'
		.__('Field type','amr-users').'<br/>'.__('(Data type for format options)','amr-users')
		.'</th>'
		
		
		.'</tr>';
	
		foreach ($nicenames as $i => $v ) {
			if (!empty($excluded[$i])) $class = ' class="alternate striped" ';
			else $class = '';
			echo "\n\t".'<tr'.$class.'>'
			.'<td><label for="nn'.$i.'" >'.$i.'</label></td>';			
			
			echo '<td><input type="text" size="40" id="nn'.$i.'"  name="nn['.$i.']"  value= "'.$v.'" />';
			echo '</td>';


			echo '<td><input type="checkbox" id="wp'.$i.'"  name="wp['.$i.']"';
			if (!empty($showinwplist[$i])) echo ' value=true checked="checked" ';
			echo ' />';
				
			if ((empty($orig_mk[$i]) or (!($orig_mk[$i] == $i))) and
				(!in_array($i,$wpfields))){ 
				echo ' <a href="#" title="'.__('This field may/may not show in the wp list.  It is not a simple user meta field','amr-users').'">!</a> ';}
			echo '</td><td>';
			if ($i==='ID') echo ' ' ;
			else {
				echo '<input type="checkbox" id="nex'.$i.'"  name="nex['.$i.']"';
				if (!empty($excluded[$i])) echo ' value=true checked="checked" ';
				echo ' />';
			}
			
			echo '</td>';
			
			//20170112	
			$ftype='';
			$disabled = '';
			if (!empty($fields_types_fixed [$i])) {
					$ftype = $fields_types_fixed [$i];
					$disabled = ' disabled="disabled" ';
					}
			elseif (!empty($fields_types[$i]) ) { //20170912 default fieldtypes must not be changed, can only add new
					$ftype = $fields_types[$i];				
			}	
							
			echo '<td><select id="fieldtype'.$i.'" '
			.' name="ftype['.$i.']" '.$disabled.' >';
			echo '<option value=""></option>';
			foreach ($fieldtypes as $fti => $ft ) {
				 echo ' <option value="'.$fti.'" ';
				 
				 if (!empty ($ftype) and ($ftype === $fti ))  
					echo ' selected = "selected" ';
				 echo ' >'.$ft.'</option>';					
			}	
			echo '</select></td>';			
// end 20170112	
			
			
			echo '</tr>';
			
		}	
		echo "\n\t".'</table>'
		.PHP_EOL.
		'</div><!-- nice names list-->'.PHP_EOL;
		return;	
		
	}

function amrmeta_check_find_fields() {
global $amr_nicenames;

	$amr_nicenames = ausers_get_option ('amr-users-nicenames');  // refetch so have all includidng excluded
	
	if (is_wp_error($amr_nicenames) or (empty ($amr_nicenames))) { /* ***  Check if we have nicenames already built */
		echo '<h3 style="clear:both;">'.__('List of possible fields not yet built.', 'amr-users').'</h3>';
		track_progress('Before counting users');
		$result = count_users();
		track_progress('After counting users');
		$total_users = $result['total_users'];
		if ($total_users > 1000) { 
			amr_users_message(	__('You have many users. Please be patient when you rebuild.', 'amr-users'));
			echo '<p>';
			foreach ($result['avail_roles'] as $i => $t) {
				echo '<br />'.__($i).' '.$t;
			}
			echo '<p>';
			echo alist_rebuild_names();
			return;
		}
		else {
			echo '<h3 style="clear:both;">'.__('Automatically rebuilding list of possible fields now.', 'amr-users').'</h3>';
			track_progress('Before rebuilding names');
			$amr_nicenames = ameta_rebuildnicenames();
			
			track_progress('After rebuilding names');
			echo '<h3 style="clear:both;">'.__('List Rebuilt', 'amr-users').'</h3>';
		}
		ausers_update_option ('amr-users-nicenames', $amr_nicenames); 
	}
}

function amrmeta_nicenameshelp() {
// style="background-image: url(images/screen-options-right-up.gif);"

	$html = '<ol>'
	.'<li>'.__('Please exclude any meta keys you do not need. ', 'amr-users').__('Some plugins do weird things in their meta value content. ', 'amr-users')
	.'</li>'
	.'<li>'.__('If you are not seeing all the fields you expect to see, then rebuild the list. ', 'amr-users')
	.'</li>'
	.'<li>'
	.__('Please note that what you see is dependant on the data in your system. If there is no meta data for a field you are expecting to see, it is impossible for that field to appear.', 'amr-users').'</li>'
	.'<li>'.__('If you add another user related plugin that adds meta data, first add some data to at least one user.  Then you may need to rebuild the list of fields below and/or reconfigure your reports if you want to see the new data.', 'amr-users').'</li>'
	.'</ol>';
	return( $html);
}

function amr_get_alluserkeys(  ) {

global $wpdb,$amr_nicenames;

/*  get all user data and attempt to extract out any object values into arrays for listing  */
	$keys = array(
		'avatar'=>'avatar');
	
	if (!is_network_admin()) {	
		$keys['comment_count']	='comment_count';
		$keys['post_count']		='post_count';
			
		$post_types=get_post_types();  
		
		foreach ($post_types as $posttype) 
			$keys[$posttype] = $posttype.'_count';
	}		
	
	$all = amr_get_usermasterfields(); 

	//echo '<h3>'.sprintf(__('You have %s main user table fields', 'amr-users'),count($all)).'</h3>';

		foreach ($all as $i2 => $v2){	
			if (!amr_excluded_userkey($v2) ) {
				$keys[$v2] = $v2;	
				if (isset($keys[$v2])) {
					//echo ' &#10003;'.$v2;
				}
				//else echo '<br />'.__('Added to report DB:', 'amr-users').' '.$v2; 
			}	
			else {
				if (isset($keys[$v2])) unset($keys[$v2]);
				//echo '<br />'.__('Excluded:', 'amr-users').' "'.$v2.'"';
			}
		}
		/* Do the meta first  */
	if (!($excluded_meta_keys = ausers_get_option('amr-users-excluded-meta-keys')))  
			$excluded_meta_keys = amr_default_excluded_metakeys();
	
	$text = array();	//20170812
	foreach ($excluded_meta_keys as $key=>$on) {  // work out which not to bother with
		if ($on) $text[] = $key;
	}
	$string = "'".implode($text,"','")."'";
	
	$w = " WHERE meta_key NOT IN (".$string.")";
			
	$q =  "SELECT DISTINCTROW meta_key, meta_value FROM $wpdb->usermeta".$w;
	// need the meta value for those like ym where there is one key but there may be complex stuff in the meta.

	if ($mkeys = amr_get_next_level_keys( $q)) {
	
		//if (WP_DEBUG) {echo '<br />For Debug: next level keys'; var_dump($mkeys);} 

		if (is_array($mkeys)) {
			$keys = array_merge ($keys, $mkeys);	
			echo '<h3>'.count($mkeys).' distinct "fields" dug out from the meta key/value combination records. </h3>';
		}
		//if (WP_DEBUG) {echo '<br />For Debug: Merged keys'; var_dump($keys);} 
	}

	unset($mkeys);
	
	echo '<h3>'.__('Check for fields from non wp tables.', 'amr-users').__('..or extracted fields.', 'amr-users').'</h3>';
	$keys2 = apply_filters('amr_get_fields', $keys); //eg: 'avatar'=>'avatar',
	foreach ($keys2 as $k => $v) {
		if (!isset($keys[$k]) and !isset($amr_nicenames[$v])) 
			echo '"'.$v.'" added.<br />';
	}

	return($keys2);
}

function amr_get_next_level_keys( $q) {
/*  get all user data and attempt to extract out any object values into arrays for listing  */
global $wpdb, $orig_mk;

	if (!$orig_mk = ausers_get_option('amr-users-original-keys')) // the record of where the fields came from
		$orig_mk = array();
	
	$all = $wpdb->get_results($q, ARRAY_A); 
//	print_r ($all);
	if (is_wp_error($all)) {amr_flag_error ($all); return;}
	if (!is_array ($all)) return;

	sort($all);  // arrays of meta_key, meta_value
	
	echo '<br /><h3>'.sprintf(__('You have %u distinct meta key / meta value records. ','amr-users'),count($all)).'</h3>';
	_e('Permanently exclude some: ', 'amr-users');
	foreach ($all as $i2 => $v2) {
		if (amr_permanently_excluded_metakeys($v2['meta_key']) ){
			unset ($all[$i2]);
			echo '.';
		}
	}
	echo '<br />';
	_e('...Deserialising and rationalising...looking for new fields.', 'amr-users');
	foreach ($all as $i2 => $v2) {  /* array of meta key, meta value*/
			/* Exclude non useful stuff */
//			print_r ($v2);
			$mk = $v2['meta_key'];
			$mv = $v2['meta_value'];	

			if (!amr_excluded_userkey($mk) ) {
				
				if (!empty($mv)) {
					$temp = maybe_unserialize($mv);
					//$temp = maybe_unserialize($temp);  // have to double unserialise for gravity forms - why?
					//if (is_array($temp)) {if (WP_DEBUG) {echo '<br/>Got an array'; var_dump($temp);}}
					//if (WP_DEBUG) echo '<br />Did it unserialise: ';	var_dump($temp);
					$temp = objectToArray ($temp); /* *must do all so can cope with incomplete objects */
					$key = str_replace(' ','_', $mk); /* html does not like spaces in the names*/
				
			
					if ((is_array($temp)) and (!amr_is_assoc($temp) ) ){ 
							// its a numeric array  - for now just take the first value
						$temp = array_pop($temp);	
						
					}
					
					if ((is_array($temp)) and (amr_is_assoc($temp) ) ){
						foreach ($temp as $i3 => $v3) {
							
							if (is_array($v3) and function_exists('amr_dig_deeper')) { // *** needs work still
								//if (WP_DEBUG) echo'<br /> ** go down a level for '.$i3;
								$key2 = $key.'_'.str_replace(' ','_', $mk); /* html does not like spaces in the names*/	
								$subkeys = amr_get_next_level_down($mk, $key2, $v3);
								//if (WP_DEBUG) echo '<br /> **** got back '.$subkeys;
								$keys = array_merge($keys,$subkeys);
							}
							else {	

								$mkey = $key.'-'.str_replace(' ','_', $i3); /* html does not like spaces in the names*/
								$keys[$mkey] = $mkey;
								if (!isset($orig_mk[$mkey])) {
									$orig_mk[$mkey] = $mk;
									echo '<br />'.__('Added complex meta to report DB: ','amr-users').$mkey.'<br />';
								}
								else {
									//echo ' &#10003;'.$mkey;
								}
							}
						}
					}
					else { // not an array
						$keys[$key] = $key; 
						if (!isset($orig_mk[$key])) { // was !empty before
							$orig_mk[$key] = $mk;
							//echo '<br />'.__('Added meta to report DB: ','amr-users').$key.'<br />';
						}
						else {  
							 //echo ' .'; // &#10003;'.$key.' '; // already had this, just indicate volume perhaps
						}
					}
				}	
				else { // the value is empty so we cannot dig down
					if (!isset ($keys[$mk])) {
					//if (!isset ($orig_mk[$key])) {
						$keys[$mk] = $mk;
						if (!isset($orig_mk[$mk])) {
							$orig_mk[$mk] = $mk;			// same same			
							//echo '<br />'.__('Added to report DB: ','amr-users').$mk.'<br />';
						}
						//else echo ' &#10003;';					
					}
				}
			}
			
	}		
	unset($all);
	//if (WP_DEBUG) {echo '<br />In Debug Only: Original keys mapping: '; var_dump($orig_mk);}
	ausers_update_option('amr-users-original-keys', $orig_mk);
	echo '<br />';
	//if (WP_DEBUG) {echo '<br />For Debug: Merged keys'; var_dump($keys);} 
return ($keys);	
}

function ameta_rebuildnicenames (){
	global $wpdb,$amr_nicenames;
/*  */
//	amr_users_message (__('Rebuilding List of possible fields.  This could take a while - I have to query evey meta record, of which there can be multiple for each main record.  Please be patient...', 'amr-users'));
	/* check if we have some options already in Database. - use their names, if not, use default, else overwrite .*/
	flush(); /* try does not always work */
	$oldnn = ausers_get_option('amr-users-nicenames');
	$nn = ameta_defaultnicenames();  /* get the default list names required */

	/*	Add any new fields in */
	unset($list);
	$list = amr_get_alluserkeys();  /* maybe only do this if a refresh is required ? No only happens on admin anyway ? */
	//echo '<h3>'.__('Try to make some nicer names.', 'amr-users').'</h3>';	
	/**** wp has changed - need to alllow for prefix now on fields.  Actually due to wpmu - keep the prefix, let the user remove it!  */
	foreach ($list as $i => $v) {
		if (empty( $nn[$v])) 	{ /* set a reasonable default nice name */
			if (!empty($oldnn[$v])) {
				$nn[$v] = $oldnn[$v];
				//echo '.';
				//echo '<br />'. sprintf(__('Use existing name %s for %s', 'amr-users'),$nn[$v],$v);
			}
			else {  // take the last part of the field only - no not nice too unpredictable
				//$lastdash = strripos($v,'-');
				//$nn[$v] = substr($v, $lastdash);
				$nn[$v] = $v;
				$nn[$v] = apply_filters('amr-users-nicenames-first',$nn[$v]);
				$nn[$v] = str_replace('s2member_custom_fields','s2m',$nn[$v]); // if it is a s2member field - reduce length of name
				$nn[$v] = (str_replace('s2member', 's2m',$nn[$v]));	
				$nn[$v] = (str_replace('capabilities', 'Cap',$nn[$v]));	
				$nn[$v] = (str_replace('-', ' ',$nn[$v]));
		//		if (isset ($wpdb->prefix)) {$nn[$v] = str_replace ($wpdb->prefix, '', $nn[$v]);} 
				/* Note prefix has underscore*/
				$nn[$v] = trim($nn[$v],'_');
				$nn[$v] = (str_replace('_', ' ',$nn[$v]));		
				$nn[$v] = ucwords ($nn[$v]);	
				//echo '<br />'. sprintf(__('Created name %s for %s', 'amr-users'),$nn[$v],$v);
				$nn[$v] = apply_filters('amr-users-nicenames-last',$nn[$v]);
				// allow so can reset nice names now and then from addon
			}
		}
	}
	unset($list);
	
	amr_check_for_table_prefixes($nn) ;
	ausers_update_option('amr-users-nicenames',$nn);
	$amr_nicenames = $nn;
	return($nn);
}

function amr_check_for_table_prefixes ($nn) {
// use a field that is always there and has the table prefixes
	$prefixes_in_use = array();
	$checkfield = 'user-settings-time';
	foreach ($nn as $i=> $n) {
		if (stristr($i, $checkfield)) {
			$prefixes_in_use[] = str_replace($checkfield, '', $i);
		}
	}
	ausers_update_option('amr-users-prefixes-in-use', $prefixes_in_use);
}

function amr_meta_nice_names_page() {
	/* may be able to work generically */
	global $amr_nicenames;
	global $ausersadminurl;
	
	//amr_meta_main_admin_header('Find fields, make nice names' );
	amr_meta_admin_headings ($plugin_page=''); // does the nonce check etc
	
	if (isset($_POST['action']) and !($_POST['action'] === "save")) return;
	
	echo PHP_EOL.'<div class="clear" style="clear:both;">&nbsp;</div>'.PHP_EOL;
	// NB do not check the values of submit fields as they may be translated.
	
	if (isset($_POST['update']) ) { // and ($_POST['update'] === "Update")) {/* Validate the input and save */
			if (amrmeta_validate_nicenames()) { // updates inside the function now
			}
			else echo '<h2>'.__('Validation failed', 'amr-users').'</h2>'; 	
		}
	if (isset($_POST['resetnice'])) { 
		if (ausers_delete_option ('amr-users-nicenames')) 
			_e('Deleting all nice name settings in database','amr-users');
		echo ' ';
		if (ausers_delete_option ('amr-users-nicenames-excluded')) 
			_e('Deleting all nice name exclusion settings in database','amr-users');
		echo ' ';	
		if (ausers_delete_option ('amr-users-original-keys')) 
			_e('Deleting original keys mapping in database','amr-users');
		echo ' ';
		if (ausers_delete_option ('amr-users-field-types')) 
			_e('Deleting field type specifications in database','amr-users');
		echo '<br />';			
	}
	if (isset($_POST['rebuild']) or isset($_POST['resetnice'])) {
				$amr_nicenames = ameta_rebuildnicenames ();
				_e('Rebuild Complete.', 'amr-users'); 
				return;
		}
	else {
		amrmeta_check_find_fields();
	}
	
	$amr_nicenames = ausers_get_option('amr-users-nicenames');
	ameta_list_nicenames_for_input($amr_nicenames); 

	echo ausers_form_end();
	}	//end amrmeta nice names option_page
	
