<?php

# PLUGIN PREVIEW BY TEXTPATTERN.INFO


# glz_custom_fields v1.5.0
# Unlimited, super special custom fields.
#
# Gerhard Lazu
# http://gerhardlazu.com
#
# Contributors: Randy Levine, Sam Weiss, Luca Botti, Manfre, Vladimir Siljkovic, Julian Reisenberger, Steve Dickinson, Stef Dawson, Jean-Pol Dupont
# Minimum requirements: Textpattern 4.6.2

// Including helper files. If we can't have classes, we will use includes


// -------------------------------------------------------------
// messages that will be available throughout this plugin
function glz_custom_fields_gTxt($get$atts = array()) {
  
$lang = array(
    
'no_name'                => 'Ooops! <strong>custom set</strong> must have a name',
    
'deleted'                => '<strong>{custom_set_name}</strong> was deleted',
    
'reset'                  => '<strong>{custom_set_name}</strong> was reset',
    
'created'                => '<strong>{custom_set_name}</strong> was created',
    
'updated'                => '<strong>{custom_set_name}</strong> was updated',
    
'exists'                 => 'Ooops! <strong>{custom_set_name}</strong> already exists',
    
'doesnt_exist'           => 'Ooops! <strong>{custom_set_name}</strong> is not set',
    
'field_problems'         => 'Ooops! <strong>{custom_set_name}</strong> has some problems. <a href="?event=glz_custom_fields">Go fix it</a>.',
    
'custom_set'             => 'Text Input'# custom sets in TXP 4.2.0 are by type custom_set by default...
    
'text_input'             => 'Text Input',
    
'select'                 => 'Select',
    
'multi-select'           => 'Multi-Select',
    
'textarea'               => 'Textarea',
    
'checkbox'               => 'Checkbox',
    
'radio'                  => 'Radio',
    
'date-picker'            => 'Date Picker',
    
'time-picker'            => 'Time Picker',
    
'custom-script'          => 'Custom Script',
    
'type_not_supported'     => 'Type not supported',
    
'no_do'                  => 'Ooops! No action specified for method, abort.',
    
'not_specified'          => 'Ooops! {what} is not specified',
    
'searchby_not_set'       => '<strong>searcby</strong> cannot be left blank',
    
'jquery_missing'         => 'Upgrade TXP to at least 4.0.5 or put <strong>jquery.js</strong> in your /textpattern folder. <a href="http://jquery.com" title="jQuery website">jQuery website</a>',
    
'check_path'             => 'Make sure all your paths are correct. Check <strong>config.php</strong> and the Admin tab (mainly Advanced).',
    
'no_articles_found'      => 'No articles with custom fields have been found.',
    
'migration_success'      => 'Migrating custom fields was successful',
    
'migration_skip'         => '<strong>custom_fields</strong> table already has data in it, migration skipped.',
    
'search_section_created' => '<strong>search</strong> section has been created',
    
'custom_sets_all_input'  => 'All custom sets have been set back to input',
    
'preferences_updated'    => 'Plugin preferences have been updated',
    
'not_found'              => 'Ooops! <strong>{file}</strong> cannot be found, check path',
    
'not_callable'           => 'Ooops! <strong>{function}()</strong> cannot be called. Ensure <strong>{file}</strong> can be executed.'
  
);

  
$out = ( strstr($lang[$get], "Ooops!") ) ? // Ooops! would appear 0 in the string...
      
"<span class=\"red\">{$lang[$get]}</span>" :
      
$lang[$get];

  return 
strtr($out$atts);
}





// -------------------------------------------------------------
// I would do this through a factory class, but some folks are still running PHP4...
function glz_custom_fields_MySQL($do$name=''$table=''$extra='') {
  if ( !empty(
$do) ) {
    switch ( 
$do ) {
      case 
'all':
        return 
glz_all_custom_sets();
        break;

      case 
'values':
        return 
glz_values_custom_field($name$extra);
        break;

      case 
'all_values' :
        return 
glz_all_existing_custom_values($name$extra);
        break;

      case 
'article_customs':
        return 
glz_article_custom_fields($name$extra);
        break;

      case 
'next_custom':
        return 
glz_next_empty_custom();
        break;

      case 
'new':
        
glz_new_custom_field($name$table$extra);
        
glz_custom_fields_update_count();
        break;

      case 
'update':
        return 
glz_update_custom_field($name$table$extra);
        break;

      case 
'reset':
        return 
glz_reset_custom_field($name$table$extra);
        break;

      case 
'delete':
        
glz_delete_custom_field($name$table);
        
glz_custom_fields_update_count();
        break;

      case 
'check_migration':
        return 
glz_check_migration();
        break;

      case 
'mark_migration':
        return 
glz_mark_migration();
        break;

      case 
'custom_set_exists':
        return 
glz_check_custom_set_exists($name);
        break;

      case 
'plugin_preferences':
        return 
glz_plugin_preferences($name);
        break;

      case 
'update_plugin_preferences':
        return 
glz_update_plugin_preferences($name);
        break;
    }
  }
  else
    
trigger_error(glz_custom_fields_gTxt('no_do'));
}


function 
glz_all_custom_sets() {
  
$all_custom_sets getRows("
    SELECT
      `name` AS custom_set,
      `val` AS name,
      `position`,
      `html` AS type
    FROM
      `"
.PFX."txp_prefs`
    WHERE
      `event`='custom'
    ORDER BY
      `position`
  "
);

  foreach ( 
$all_custom_sets as $custom_set ) {
    
$out[$custom_set['custom_set']] = array(
      
'name'      => $custom_set['name'],
      
'position'  => $custom_set['position'],
      
'type'      => $custom_set['type']
    );
  }

  return 
$out;
}


function 
glz_values_custom_field($name$extra) {
  global 
$prefs;

  if ( 
is_array($extra) ) {
    
extract($extra);

    if ( !empty(
$name) ) {
      switch ( 
$prefs['values_ordering'] ) {
        case 
"ascending":
          
$orderby "value ASC";
          break;
        case 
"descending":
          
$orderby "value DESC";
          break;
        default:
          
$orderby "id ASC";
      }


      
$arr_values getThings("
        SELECT
          `value`
        FROM
          `"
.PFX."custom_fields`
        WHERE
          `name` = '
{$name}'
        ORDER BY
          
{$orderby}
      "
);

      if ( 
count($arr_values) > ) {
        
// decode all special characters e.g. ", & etc. and use them for keys
        
foreach ( $arr_values as $key => $value )
          
$arr_values_formatted[glz_return_clean_default(htmlspecialchars($value))] = stripslashes($value);

        
// if this is a range, format ranges accordingly
        
return glz_format_ranges($arr_values_formatted$custom_set_name);
      }
    }
  }
  else
    
trigger_error(glz_custom_fields_gTxt('not_specified', array('{what}' => "extra attributes")));
}


function 
glz_all_existing_custom_values($name$extra) {
  if ( 
is_array($extra) ) {
    
extract(lAtts(array(
      
'custom_set_name'   => "",
      
'status'            => 4
    
),$extra));

    
// we might want to check the custom field values for all articles - think initial migration
    
$status_condition = ($status == 0) ? "<> ''" "= '$status'";

    if ( !empty(
$name) ) {
      
$arr_values getThings("
        SELECT DISTINCT
          `
$name`
        FROM
          `"
.PFX."textpattern`
        WHERE
          `Status` 
$status_condition
        AND
          `
$name` <> ''
        ORDER BY
          `
$name`
        "
);

      
// trim all values
      
foreach ( $arr_values as $key => $value )
        
$arr_values[$key] = trim($value);

      
// DEBUG
      // dmp($arr_values);

      // prepare our array for checking. We need a single string to check for | instances - seems quickest.
      
$values_check join('::'$arr_values);

      
// DEBUG
      // dmp($values_check);

      // check if some of the values are multiple ones
      
if ( strstr($values_check'|') ) {
        
// initialize $out
        
$out = array();
        
// put all values in an array
        
foreach ( $arr_values as $value ) {
          
$arr_values explode('|'$value);
          
$out array_merge($out$arr_values);
        }
        
// keep only the unique ones
        
$out array_unique($out);
        
// keys and values need to be the same
        
$out php4_array_combine($out$out);
      }

      
// check if this is a range
      
else if ( strstr($values_check'-') && strstr($custom_set_name'range') )
        
// keys won't have the unit ($, £, m<sup>3</sup>, etc.) values will
        
$out glz_format_ranges($arr_values$custom_set_name);
      else
        
// keys and values need to be the same
        
$out php4_array_combine($arr_values$arr_values);

      
// calling stripslashes on all array values
      
array_map('glz_array_stripslashes'$out);

      return 
$out;
    }
  }
  else
    
trigger_error(glz_custom_fields_gTxt('not_specified', array('{what}' => "extra attributes")));
}


function 
glz_article_custom_fields($name$extra) {
  if ( 
is_array($extra) ) {
    
// see what custom fields we need to query for
    
foreach ( $extra as $custom => $custom_set )
      
$select[] = glz_custom_number($custom);

    
// prepare the select elements
    
$select implode(','$select);

    
$arr_article_customs getRow("
      SELECT
        
$select
      FROM
        `"
.PFX."textpattern`
      WHERE
        `ID`='
$name'
    "
);

    return 
$arr_article_customs;
  }
  else
    
trigger_error(glz_custom_fields_gTxt('not_specified', array('{what}' => "extra attributes")));
}


function 
glz_new_custom_field($name$table$extra) {
  if ( 
is_array($extra) ) {
    
extract($extra);
    
// DRYing up, we'll be using this variable quiet often
    
$custom_set = ( isset($custom_field_number) ) ?
      
"custom_{$custom_field_number}_set" :
      
$custom_set;

    if ( (
$table == PFX."txp_prefs") ) {
      
// if this is a new field without a position, use the $custom_field_number
      
if (empty($custom_set_position)) $custom_set_position $custom_field_number;
      
$query "
        INSERT INTO
          `"
.PFX."txp_prefs` (`prefs_id`, `name`, `val`, `type`, `event`, `html`, `position`)
        VALUES
          ('1', '
{$custom_set}', '{$name}', '1', 'custom', '{$custom_set_type}', {$custom_set_position})
      "
;
    }
    else if ( 
$table == PFX."txp_lang" ) {
      
$query "
        INSERT INTO
          `"
.PFX."txp_lang` (`lang`,`name`,`event`,`data`,`lastmod`)
        VALUES
          ('
{$lang}','{$custom_set}','prefs','{$name}',now())
      "
;
    }
    else if ( 
$table == PFX."textpattern" ) {
      
$column_type = ( $custom_set_type == "textarea" ) ? "TEXT" "VARCHAR(255)";
      
$dflt = ( $custom_set_type == "textarea" ) ? '' "DEFAULT ''";
      
$query "
        ALTER TABLE
          `"
.PFX."textpattern`
        ADD
          `custom_
{$custom_field_number}{$column_type} NOT NULL {$dflt}
      "
;
    }
    else if ( 
$table == PFX."custom_fields" ) {
      
$arr_values array_unique(array_filter(explode("\r\n"$value), 'glz_arr_empty_values'));

      if ( 
is_array($arr_values) && !empty($arr_values) ) {
        
$size_arr_values count($arr_values);
        
$insert '';
        foreach ( 
$arr_values as $key => $value ) {
          
// don't insert empty values
          
if ( !empty($value) )
            
// make sure special characters are escaped before inserting them in the database
            
$value addslashes(addslashes(trim($value)));
            
// if this is the last value, query will have to be different
            
$insert .= ($key+!= $size_arr_values ) ?
              
"('{$custom_set}','{$value}'), " :
              
"('{$custom_set}','{$value}')";
        }
        
$query "
          INSERT INTO
            `"
.PFX."custom_fields` (`name`,`value`)
          VALUES
            
{$insert}
        "
;
      }
    }
    if ( isset(
$query) && !empty($query) )
      
safe_query($query);
  }
  else
    
trigger_error(glz_custom_fields_gTxt('not_specified', array('{what}' => "extra attributes")));
}


function 
glz_update_custom_field($name$table$extra) {
  if ( 
is_array($extra) )
    
extract($extra);

  if ( (
$table == PFX."txp_prefs") ) {
    
safe_query("
      UPDATE
        `"
.PFX."txp_prefs`
      SET
        `val` = '
{$custom_set_name}',
        `html` = '
{$custom_set_type}',
        `position` = '
{$custom_set_position}'
      WHERE
        `name`='
{$name}'
    "
);
  }
  else if ( (
$table == PFX."textpattern") ) {
    
$column_type = ( $custom_set_type == "textarea" ) ? "TEXT" "VARCHAR(255)";
    
$dflt = ( $custom_set_type == "textarea" ) ? '' "DEFAULT ''";
    
safe_query("
      ALTER TABLE
        `"
.PFX."textpattern`
      MODIFY
        `
{$custom_field}{$column_type} NOT NULL {$dflt}
    "
);
  }
}


function 
glz_reset_custom_field($name$table$extra) {
  if ( 
is_array($extra) )
    
extract($extra);

  if ( 
$table == PFX."txp_prefs" ) {
    
safe_query("
      UPDATE
        `"
.PFX."txp_prefs`
      SET
        `val` = '',
        `html` = 'text_input'
      WHERE
        `name`='
{$name}'
    "
);
  }
  else if ( 
$table == PFX."textpattern" ) {
    
safe_query("UPDATE `".PFX."textpattern` SET `{$name}` = ''");
    
safe_query("ALTER TABLE `".PFX."textpattern` MODIFY `{$custom_field}` VARCHAR(255) NOT NULL DEFAULT ''");
  }
}


function 
glz_delete_custom_field($name$table) {
  
// remember, custom fields under 10 MUST NOT be deleted
  
if ( glz_custom_digit($name) > 10 ) {
    if ( 
in_array($table, array(PFX."txp_prefs"PFX."txp_lang"PFX."custom_fields")) ) {
      
$query "
        DELETE FROM
          `
{$table}`
        WHERE
          `name`='
{$name}'
      "
;
    }
    else if ( 
$table == PFX."textpattern" ) {
      
$query "
        ALTER TABLE
          `"
.PFX."textpattern`
        DROP
          `
{$name}`
      "
;
    }
    
safe_query($query);
  }
  else {
    if ( 
$table == PFX."txp_prefs" )
      
glz_custom_fields_MySQL("reset"$name$table);
    else if ( (
$table == PFX."custom_fields") ) {
      
safe_query("
        DELETE FROM
          `
{$table}`
        WHERE
          `name`='
{$name}'
      "
);
    }
  }
}


// -------------------------------------------------------------
// checks if custom_fields table has any values in it
function glz_check_migration() {
  return 
getThing("
    SELECT
      COUNT(*)
    FROM
      `"
.PFX."custom_fields`
  "
);
}


// -------------------------------------------------------------
// make a note of glz_custom_fields migration in txp_prefs
function glz_mark_migration() {
  
set_pref("migrated""1""glz_custom_f");
}


// -------------------------------------------------------------
// check if one of the special custom fields exists
function glz_check_custom_set_exists($name) {
  if ( !empty(
$name) ) {
    return 
getThing("
      SELECT
        `name`, `val`
      FROM
        `"
.PFX."txp_prefs`
      WHERE
        `html` = '
{$name}'
      AND
        `name` LIKE 'custom_%'
      ORDER BY
        `name`
    "
);
  }
}


// -------------------------------------------------------------
// updates max_custom_fields
function glz_custom_fields_update_count() {
  
set_pref('max_custom_fields'safe_count("txp_prefs""event='custom'"));
}

// -------------------------------------------------------------
// returns all plugin preferences
function glz_plugin_preferences($arr_preferences) {
    
$r safe_rows_start('name, val''txp_prefs'"event = 'glz_custom_f'");
    if (
$r) {
        while (
$a nextRow($r)) {
            
$out[$a['name']] = stripslashes($a['val']);
        }
    }
  return 
$out;
}

// -------------------------------------------------------------
// updates all plugin preferences
function glz_update_plugin_preferences($arr_preferences) {
  
// die(dmp($arr_preferences));
  
foreach ($arr_preferences as $preference => $value) {
    
set_pref($preferenceaddslashes(addslashes(trim($value))), "glz_custom_f"10); // 10 so that it won't appear under TXP's prefs tab
  
}
}






// -------------------------------------------------------------
// goes through all custom sets, returns the first one which is not being used
function glz_next_empty_custom() {
  global 
$all_custom_sets;

  foreach ( 
$all_custom_sets as $custom => $custom_set ) {
    if ( empty(
$custom_set['name']) )
      return 
$custom;
  }
}


// -------------------------------------------------------------
// edit/delete buttons in custom_fields table require a form each
function glz_form_buttons($action$value$custom_set$custom_set_name$custom_set_type$custom_set_position$onsubmit='') {
  
$onsubmit = ($onsubmit) ?
    
'onsubmit="'.$onsubmit.'"' :
    
'';

  return
    
'<form method="post" action="index.php" '.$onsubmit.'>
      <input name="custom_set" value="'
.$custom_set.'" type="hidden" />
      <input name="custom_set_name" value="'
.$custom_set_name.'" type="hidden" />
      <input name="custom_set_type" value="'
.$custom_set_type.'" type="hidden" />
      <input name="custom_set_position" value="'
.$custom_set_position.'" type="hidden" />
      <input name="event" value="glz_custom_fields" type="hidden" />
      <input name="'
.$action.'" value="'.$value.'" type="submit" />
    </form>'
;
}


// -------------------------------------------------------------
// the types our custom fields can take
function glz_custom_set_types() {
  return array(
    
'normal' => array(
      
'text_input',
      
'checkbox',
      
'radio',
      
'select',
      
'multi-select',
      
'textarea'),
    
'special' => array(
      
'date-picker',
      
'time-picker',
      
'custom-script')
  );
}


// -------------------------------------------------------------
// outputs only custom fields that have been set, i.e. have a name assigned to them
function glz_check_custom_set($all_custom_sets$step) {
  
$out = array();

  foreach (
$all_custom_sets as $key => $custom_field) {
    if (!empty(
$custom_field['name'])) {
      if ( (
$step == "body") && ($custom_field['type'] == "textarea") )
        
$out[$key] = $custom_field;
      else if ( (
$step == "custom_fields") && ($custom_field['type'] != "textarea") ) {
        
$out[$key] = $custom_field;
      }
    }
  }

  return 
$out;
}


// -------------------------------------------------------------
// removes { } from values which are marked as default
function glz_return_clean_default($value) {
  
$pattern "/^.*\{(.*)\}.*/";

  return 
preg_replace($pattern"$1"$value);
}


// -------------------------------------------------------------
// return our default value from all custom_field values
function glz_default_value($all_values) {
  if ( 
is_array($all_values) ) {
    
preg_match("/(\{.*\})/"join(" "$all_values), $default);
    return ( (!empty(
$default) && $default[0]) ? $default[0] : '');
  }
}


// -------------------------------------------------------------
// calling the above function in an array context
function glz_clean_default_array_values(&$value) {
  
$value glz_return_clean_default($value);
}


// -------------------------------------------------------------
// custom_set without "_set" e.g. custom_1_set => custom_1
// or custom set formatted for IDs e.g. custom-1
function glz_custom_number($custom_set$delimiter="_") {
  
$custom_field substr($custom_set0, -4);

  if (
$delimiter != "_")
    
$custom_field str_replace("_"$delimiter$custom_field);

  return 
$custom_field;
}


// -------------------------------------------------------------
// custom_set digit e.g. custom_1_set => 1
function glz_custom_digit($custom_set) {
  
$out explode("_"$custom_set);
  
// $out[0] will always be custom
  
return $out[1];
}


// -------------------------------------------------------------
// removes empty values from arrays - used for new custom fields
function glz_arr_empty_values($value) {
  if ( !empty(
$value) )
    return 
$value;
}


// -------------------------------------------------------------
// returns the custom set from a custom set name e.g. "Rating" gives us custom_1_set
function glz_get_custom_set($value) {
  global 
$all_custom_sets;

  
// go through all custom fields and see if the one we're looking for exists
  
foreach ( $all_custom_sets as $custom => $custom_set ) {
    if ( 
$custom_set['name'] == $value )
      return 
$custom;
  }
  
// if it doesn't, return error message
  
trigger_error(glz_custom_fields_gTxt('doesnt_exist', array('{custom_set_name}' => $value)));
}


// -------------------------------------------------------------
// get the article ID, EVEN IF it's newly saved
function glz_get_article_id() {
  return ( !empty(
$GLOBALS['ID']) ?
    
$GLOBALS['ID'] :
    
gps('ID') );
}


// -------------------------------------------------------------
// helps with range formatting - just DRY
function glz_format_ranges($arr_values$custom_set_name) {
  
//initialize $out
  
$out '';
  foreach ( 
$arr_values as $key => $value ) {
    
$out[$key] = ( strstr($custom_set_name'range') ) ?
      
glz_custom_fields_range($value$custom_set_name) :
      
$value;
  }
  return 
$out;
}


// -------------------------------------------------------------
// acts as a callback for the above function
function glz_custom_fields_range($custom_value$custom_set_name) {
  
// last part of the string will be the range unit (e.g. $, &pound;, m<sup>3</sup> etc.)
  
$nomenclature array_pop(explode(' '$custom_set_name));

  
// see whether range unit should go after
  
if ( strstr($nomenclature'(after)') ) {
    
// trim '(after)' from the measuring unit
    
$nomenclature substr($nomenclature0, -7);
    
$after 1;
  }

  
// check whether it's a range or single value
  
$arr_value explode('-'$custom_value);
  if ( 
is_array($arr_value) ) {
    
// initialize $out
    
$out '';
    foreach ( 
$arr_value as $value ) {
      
// check whether nomenclature goes before or after
      
$out[] = ( !isset($after) ) ?
        
$nomenclature.number_format($value) :
        
number_format($value).$nomenclature;
    }
    return 
implode('-'$out);
  }
  
// our range is a single value
  
else {
    
// check whether nomenclature goes before or after
    
return ( !isset($after) ) ?
      
$nomenclature.number_format($value) :
      
number_format($value).$nomenclature;
  }
}


// -------------------------------------------------------------
// returns the next available number for custom set
function glz_custom_next($arr_custom_sets) {
  
$arr_extra_custom_sets = array();
  foreach ( 
array_keys($arr_custom_sets) as $extra_custom_set) {
    
$arr_extra_custom_sets[] = glz_custom_digit($extra_custom_set);
  }
  
// order the array
  
sort($arr_extra_custom_sets);

  for ( 
$i=0$i count($arr_extra_custom_sets); $i++ ) {
    if (
$arr_extra_custom_sets[$i] > $i+1)
      return 
$i+1;
  }

  return 
count($arr_extra_custom_sets)+1;
}


// -------------------------------------------------------------
// checks if the custom field name isn't already taken
function glz_check_custom_set_name($arr_custom_fields$custom_set_name$custom_set='') {
  foreach ( 
$arr_custom_fields as $custom => $arr_custom_set ) {
    if ( (
$custom_set_name == $arr_custom_set['name']) && (!empty($custom_set) && $custom_set != $custom) )
      return 
TRUE;
  }

  return 
FALSE;
}


// -------------------------------------------------------------
// formats the custom set output based on its type
function glz_format_custom_set_by_type($custom$custom_id$custom_set_type$arr_custom_field_values$custom_value ""$default_value "") {
  if ( 
is_array($arr_custom_field_values) )
    
$arr_custom_field_values array_map('glz_array_stripslashes'$arr_custom_field_values);

  switch ( 
$custom_set_type ) {
    
// these are the normal custom fields
    
case "text_input":
      return array(
        
fInput("text"$custom$custom_value"edit""""""22"""$custom_id),
        
'glz_custom_field'
      
);

    case 
"select":
      return array(
        
glz_selectInput($custom$custom_id$arr_custom_field_values$custom_value$default_value),
        
'glz_custom_select_field'
      
);

    case 
"multi-select":
      return array(
        
glz_selectInput($custom$custom_id$arr_custom_field_values$custom_value$default_value1),
        
'glz_custom_multi-select_field'
      
);

    case 
"checkbox":
      return array(
        
glz_checkbox($custom$arr_custom_field_values$custom_value$default_value),
        
'glz_custom_checkbox_field'
      
);

    case 
"radio":
      return array(
        
glz_radio($custom$custom_id$arr_custom_field_values$custom_value$default_value),
        
'glz_custom_radio_field'
      
);

    case 
"textarea":
      return array(
        
text_area($custom100500$custom_value$custom_id),
        
'glz_text_area_field'
      
);

    
// here start the special custom fields, might need to refactor the return, starting to repeat itself
    
case "date-picker":
      return array(
        
fInput("text"$custom$custom_value"edit date-picker""""""22"""$custom_id),
        
'glz_custom_date-picker_field clearfix'
      
);

    case 
"time-picker":
      return array(
        
fInput("text"$custom$custom_value"edit time-picker""""""22"""$custom_id),
        
'glz_custom_time-picker_field'
      
);

    case 
"custom-script":
      global 
$custom_scripts_path;
      return array(
        
glz_custom_script($custom_scripts_path."/".reset($arr_custom_field_values), $custom$custom_id$custom_value),
        
'glz_custom_field_script'
      
);

    
// a type has been passed that is not supported yet
    
default:
      return array(
        
glz_custom_fields_gTxt('type_not_supported'),
        
'glz_custom_field'
      
);
  }
}


// -------------------------------------------------------------
// had to duplicate the default selectInput() because trimming \t and \n didn't work + some other mods & multi-select
function glz_selectInput($name ''$id ''$arr_values ''$custom_value ''$default_value ''$multi '') {
  if ( 
is_array($arr_values) ) {
    global 
$prefs;
    
$out = array();

    
// if there is no custom_value coming from the article, let's use our default one
    
if ( empty($custom_value) )
      
$custom_value $default_value;

    foreach (
$arr_values as $key => $value) {
      
$selected glz_selected_checked('selected'$key$custom_value$default_value);
      
$out[] = "<option value=\"$key\"{$selected}>$value</option>";
    }

    
// we'll need the extra attributes as well as a name that will produce an array
    
if ($multi) {
      
$multi ' multiple="multiple" size="'.$prefs['multiselect_size'].'"';
      
$name .= "[]";
    }

    return 
"<select id=\"".glz_idify($id)."\" name=\"$name\" class=\"list\"$multi>".
      (
$default_value '' "<option value=\"\"$selected>&nbsp;</option>").
      ( 
$out join(''$out) : '').
      
"</select>";
  }
  else
    return 
glz_custom_fields_gTxt('field_problems', array('{custom_set_name}' => $name));
}


// -------------------------------------------------------------
// had to duplicate the default checkbox() to keep the looping in here and check against existing value/s
function glz_checkbox($name ''$arr_values ''$custom_value ''$default_value '') {
  if ( 
is_array($arr_values) ) {
    
$out = array();

    
// if there is no custom_value coming from the article, let's use our default one
    
if ( empty($custom_value) )
      
$custom_value $default_value;

    foreach ( 
$arr_values as $key => $value ) {
      
$checked glz_selected_checked('checked'$key$custom_value);

      
// Putting an additional span around the input and label combination so the two can be floated together as a pair for left-right, left-right,... arrangement of checkboxes and radio buttons. Thanks Julian!
      
$out[] = "<span><input type=\"checkbox\" name=\"{$name}[]\" value=\"$key\" class=\"checkbox\" id=\"".glz_idify($key)."\"{$checked} /><label for=\"".glz_idify($key)."\">$value</label></span><br />";
    }

    return 
join(''$out);
  }
  else
    return 
glz_custom_fields_gTxt('field_problems', array('{custom_set_name}' => $name));
}


// -------------------------------------------------------------
// had to duplicate the default radio() to keep the looping in here and check against existing value/s
function glz_radio($name ''$id ''$arr_values ''$custom_value ''$default_value '') {
  if ( 
is_array($arr_values) ) {
    
$out = array();

    
// if there is no custom_value coming from the article, let's use our default one
    
if ( empty($custom_value) )
      
$custom_value $default_value;

    foreach ( 
$arr_values as $key => $value ) {
      
$checked glz_selected_checked('checked'$key$custom_value);

      
// Putting an additional span around the input and label combination so the two can be floated together as a pair for left-right, left-right,... arrangement of checkboxes and radio buttons. Thanks Julian!
      
$out[] = "<span><input type=\"radio\" name=\"$name\" value=\"$key\" class=\"radio\" id=\"{$id}_".glz_idify($key)."\"{$checked} /><label for=\"{$id}_".glz_idify($key)."\">$value</label></span><br />";
    }

    return 
join(''$out);
  }
  else
    return 
glz_custom_fields_gTxt('field_problems', array('{custom_set_name}' => $name));
}


// -------------------------------------------------------------
// checking if this custom field has selected or checked values
function glz_selected_checked($nomenclature$value$custom_value '') {
  
// we're comparing against a key which is a "clean" value
  
$custom_value htmlspecialchars($custom_value);

  
// make an array if $custom_value contains multiple values
  
if ( strpos($custom_value'|') )
    
$arr_custom_value explode('|'$custom_value);

  if ( isset(
$arr_custom_value) )
    
$out = ( in_array($value$arr_custom_value) ) ? $nomenclature=\"$nomenclature\"" "";
  else
    
$out = ($value == $custom_value) ? $nomenclature=\"$nomenclature\"" "";

  return 
$out;
}


//-------------------------------------------------------------
// button gets more consistent styling across browsers rather than input type="submit"
// included in this plugin until in makes it into TXP - if that ever happens...
function glz_fButton($type$name$contents='Submit'$value$class=''$id=''$title=''$onClick=''$disabled false) {
  
$o  '<button type="'.$type.'" name="'.$name.'"';
  
$o .= ' value="'.htmlspecialchars($value).'"';
  
$o .= ($class)    ? ' class="'.$class.'"' '';
  
$o .= ($id)       ? ' id="'.$id.'"' '';
  
$o .= ($title)    ? ' title="'.$title.'"' '';
  
$o .= ($onClick)  ? ' onclick="'.$onClick.'"' '';
  
$o .= ($disabled) ? ' disabled="disabled"' '';
  
$o .= '>';
  
$o .= $contents;
  
$o .= '</button>';
  return 
$o;
}


//-------------------------------------------------------------
// evals a PHP script and displays output right under the custom field label
function glz_custom_script($script$custom$custom_id$custom_value) {
  if ( 
is_file($script) ) {
    include_once(
$script);
    
$custom_function basename($script".php");
    if ( 
is_callable($custom_function) ) {
      return 
call_user_func_array($custom_function, array($custom$custom_id$custom_value));
    }
    else
      return 
glz_custom_fields_gTxt('not_callable', array('{function}' => $custom_function'{file}' => $script));
  }
  else
    return 
glz_custom_fields_gTxt('not_found', array('{file}' => $script));

}


// -------------------------------------------------------------
// PHP4 doesn't come with array_combine... Thank you redbot!
function php4_array_combine($keys$values) {
  
$result = array(); // initializing the array

  
foreach ( array_map(null$keys$values) as $pair ) {
    
$result[$pair[0]] = $pair[1];
  }

  return 
$result;
}


// -------------------------------------------------------------
// converts all values into id safe ones
function glz_idify($value) {
  
$patterns[0] = "/\s/";
  
$replacements[0] = "-";
  
$patterns[1] = "/[^a-zA-Z0-9\-]/";
  
$replacements[1] = "";

  return 
preg_replace($patterns$replacementsstrtolower($value));
}


// -------------------------------------------------------------
// strips slashes in arrays, used in conjuction with e.g. array_map
function glz_array_stripslashes(&$value) {
  return 
stripslashes($value);
}


// -------------------------------------------------------------
// returns all sections/categories that are searchable
function glz_all_searchable_sections_categories($type) {
  
$type = (in_array($type, array('category''section')) ? $type 'section');
  
$condition "";

  if ( 
$type == "section" )
    
$condition .= "searchable='1'";
  else
    
$condition .= "name <> 'root' AND type='article'";

  
$result safe_rows('*'"txp_{$type}"$condition);

  
$out = array();
  foreach (
$result as $value) {
    
$out[$value['name']] = $value['title'];
  }

  return 
$out;
}

// -------------------------------------------------------------
// will leave only [A-Za-z0-9 ] in the string
function glz_clean_string($string) {
  if (
$string)
    return 
preg_replace('/[^A-Za-z0-9\s\_\-]/'''$string);
}





// -------------------------------------------------------------
// replaces the default custom fields under write tab
function glz_custom_fields_replace($event$step$data$rs) {
  global 
$all_custom_sets$date_picker;
  
// get all custom fields & keep only the ones which are set, filter by step
  
$arr_custom_fields glz_check_custom_set($all_custom_sets$step);

  
// DEBUG
  // dmp($arr_custom_fields);

  
$out ' ';

  if ( 
is_array($arr_custom_fields) && !empty($arr_custom_fields) ) {
    
// get all custom fields values for this article
    
$arr_article_customs glz_custom_fields_MySQL("article_customs"glz_get_article_id(), ''$arr_custom_fields);

    
// DEBUG
    // dmp($arr_article_customs);

    
if ( is_array($arr_article_customs) )
      
extract($arr_article_customs);

    
// let's see which custom fields are set
    
foreach ( $arr_custom_fields as $custom => $custom_set ) {
      
// get all possible/default value(s) for this custom set from custom_fields table
      
$arr_custom_field_values glz_custom_fields_MySQL("values"$custom'', array('custom_set_name' => $custom_set['name']));

      
// DEBUG
      // dmp($arr_custom_field_values);

      //custom_set formatted for id e.g. custom_1_set => custom-1 - don't ask...
      
$custom_id glz_custom_number($custom"-");
      
//custom_set without "_set" e.g. custom_1_set => custom_1
      
$custom glz_custom_number($custom);

      
// if current article holds no value for this custom field and we have no default value, make it empty
      
$custom_value = (!empty($$custom) ? $$custom '');
      
// DEBUG
      // dmp("custom_value: {$custom_value}");

      // check if there is a default value
      // if there is, strip the { }
      
$default_value glz_return_clean_default(glz_default_value($arr_custom_field_values));
      
// DEBUG
      // dmp("default_value: {$default_value}");

      // now that we've found our default, we need to clean our custom_field values
      
if (is_array($arr_custom_field_values))
        
array_walk($arr_custom_field_values"glz_clean_default_array_values");

      
// DEBUG
      // dmp($arr_custom_field_values);

      // the way our custom field value is going to look like
      
list($custom_set_value$custom_class) = glz_format_custom_set_by_type($custom$custom_id$custom_set['type'], $arr_custom_field_values$custom_value$default_value);

      
// DEBUG
      // dmp($custom_set_value);

      
$out .= graf(
        
"<label for=\"$custom_id\">{$custom_set['name']}</label><br />$custom_set_value"" class=\"$custom_class\""
      
);
    }
  }

  
// DEBUG
  // dmp($out);

  // if we're writing textarea custom fields, we need to include the excerpt as well
  
if ($step == "body") {
    
$out $data.$out;
  }

  return 
$out;
}


// -------------------------------------------------------------
// prep our custom fields for the db (watch out for multi-selects, checkboxes & radios, they might have multiple values)
function glz_custom_fields_before_save() {
  
// keep only the custom fields
  
foreach ($_POST as $key => $value) {
    
//check for custom fields with multiple values e.g. arrays
    
if ( strstr($key'custom_') && is_array($value) ) {
      
$value implode($value'|');
      
// feed our custom fields back into the $_POST
      
$_POST[$key] = $value;
    }
  }
  
// DEBUG
  // dmp($_POST);
}


// -------------------------------------------------------------
// adds the css & js we need
function glz_custom_fields_css_js() {
  global 
$glz_notice$date_picker$time_picker$prefs;

  
// here come our custom stylesheetz
  
$css '<link rel="stylesheet" type="text/css" media="all" href="http://'.$prefs['siteurl'].'/plugins/glz_custom_fields/glz_custom_fields.css">'.n;
  
// and here come our javascriptz
  
$js '';
  if ( 
$date_picker ) {
    
$css .= '<link rel="stylesheet" type="text/css" media="all" href="'.$prefs['datepicker_url'].'/datePicker.css" />'.n;
    foreach (array(
'date.js''datePicker.js') as $file) {
      
$js .= '<script type="text/javascript" src="'.$prefs['datepicker_url']."/".$file.'"></script>'.n;
    }
    
$js .= <<<EOF
<script type="text/javascript">
$(function() {
  if ($(".date-picker").length > 0) {
    try {
      Date.firstDayOfWeek = 
{$prefs['datepicker_first_day']};
      Date.format = '
{$prefs['datepicker_format']}';
      Date.fullYearStart = '19';
      $(".date-picker").datePicker({startDate:'
{$prefs['datepicker_start_date']}'});
    } catch(err) {
      $('#messagepane').html('<a href="http://
{$prefs['siteurl']}/textpattern/?event=plugin_prefs.glz_custom_fields">Fix the DatePicker jQuery plugin</a>');
    }
  }
});
</script>
EOF;
  }
  if ( 
$time_picker ) {
    
$css .= '<link rel="stylesheet" type="text/css" media="all" href="'.$prefs['timepicker_url'].'/timePicker.css" />'.n;
    
$js .= '<script type="text/javascript" src="'.$prefs['timepicker_url'].'/timePicker.js"></script>'.n;
    
$js .= <<<EOF
<script type="text/javascript">
$(function() {
  if ($(".time-picker").length > 0) {
    try {
      $(".time-picker").timePicker({
        startTime:'
{$prefs['timepicker_start_time']}',
        endTime: '
{$prefs['timepicker_end_time']}',
        step: 
{$prefs['timepicker_step']},
        show24Hours: 
{$prefs['timepicker_show_24']}
      });
    } catch(err) {
      $('#messagepane').html('<a href="http://
{$prefs['siteurl']}/textpattern/?event=plugin_prefs.glz_custom_fields">Fix the TimePicker jQuery plugin</a>');
    }
  }
});
</script>
EOF;
  }
  
$js .= '<script type="text/javascript" src="http://'.$prefs['siteurl'].'/plugins/glz_custom_fields/glz_custom_fields.js"></script>';

  
// displays the notices we have gathered throughout the entire plugin
  
if ( count($glz_notice) > ) {
    
// let's turn our notices into a string
    
$glz_notice join("<br />"array_unique($glz_notice));

    
$js .= '<script type="text/javascript">
    <!--//--><![CDATA[//><!--

    $(document).ready(function() {
      // add our notices
      $("#messagepane").html(\''
.$glz_notice.'\');
    });
    //--><!]]>
    </script>'
;
  }

  echo 
$js.n.t.$css.n.t;
}


// -------------------------------------------------------------
// we are setting up the pre-requisite values for glz_custom_fields
function before_glz_custom_fields() {
  
// we will be reusing these globals across the whole plugin
  
global $all_custom_sets$glz_notice$prefs$date_picker$time_picker;

  
// glz_notice collects all plugin notices
  
$glz_notice = array();

  
// let's get all custom field sets from prefs
  
$all_custom_sets glz_custom_fields_MySQL("all");

  
// let's see if we have a date-picker custom field (first of the special ones)
  
$date_picker glz_custom_fields_MySQL("custom_set_exists""date-picker");

  
// let's see if we have a time-picker custom field
  
$time_picker glz_custom_fields_MySQL("custom_set_exists""time-picker");
}


// -------------------------------------------------------------
// bootstrapping routines, run through plugin_lifecycle
function glz_custom_fields_install() {
  global 
$all_custom_sets$glz_notice$prefs;

  
// default custom fields are set to custom_set
  // need to change this because it confuses our set_types()
  
safe_query("
    UPDATE
      `"
.PFX."txp_prefs`
    SET
      `html` = 'text_input'
    WHERE
      `event` = 'custom'
    AND
      `html` = 'custom_set'
  "
);

  
// set plugin preferences
  
$arr_plugin_preferences = array(
    
'values_ordering'       => "custom",
    
'multiselect_size'      => "5",
    
'datepicker_url'        => hu."plugins/glz_custom_fields/jquery.datePicker",
    
'datepicker_format'     => "dd/mm/yyyy",
    
'datepicker_first_day'  => 1,
    
'datepicker_start_date' => "01/01/1990",
    
'timepicker_url'        => hu."plugins/glz_custom_fields/jquery.timePicker",
    
'timepicker_start_time' => "00:00",
    
'timepicker_end_time'   => "23:30",
    
'timepicker_step'       => 30,
    
'timepicker_show_24'    => true,
    
'custom_scripts_path'   => $prefs['path_to_site']."/plugins/glz_custom_fields"
  
);
  
glz_custom_fields_MySQL("update_plugin_preferences"$arr_plugin_preferences);

  
// let's update plugin preferences, make sure they won't appear under Admin > Preferences
  
safe_query("
    UPDATE
      `"
.PFX."txp_prefs`
    SET
      `type` = '10'
    WHERE
      `event` = 'glz_custom_f'
  "
);

  
// if we don't have a search section, let's create it because we'll need it when searching by custom fields
  
if( !getRow("SELECT name FROM `".PFX."txp_section` WHERE name='search'") ) {
    
safe_query("
      INSERT INTO
        `"
.PFX."txp_section` (`name`, `page`, `css`, `in_rss`, `on_frontpage`, `searchable`, `title`)
      VALUES
        ('search', 'default', 'default', '0', '0', '0', 'Search')
    "
);
    
// add a notice that search section has bee created
    
$glz_notice[] = glz_custom_fields_gTxt("search_section_created");
  }

  
// if we don't have the custom_fields table, let's create it
  
if ( !getRows("SHOW TABLES LIKE '".PFX."custom_fields'") ) {
    
safe_query("
      CREATE TABLE `"
.PFX."custom_fields` (
        `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
        `name` varchar(255) NOT NULL default '',
        `value` varchar(255) NOT NULL default '',
        PRIMARY KEY (id),
        KEY (`name`)
      ) ENGINE=MyISAM
    "
);
  }
  else {
    
// if there isn't and id column, add it
    
if ( !getRows("SHOW COLUMNS FROM ".PFX."custom_fields LIKE 'id'") ) {
      
safe_query("
        ALTER TABLE `"
.PFX."custom_fields`
          ADD `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT KEY
      "
);
    }

   
// if we have definitely migrated using this function, skip everything
   
if ( isset($prefs['migrated']) )
     return;
   
// abort the migration if there are values in custom_fields table, we don't want to overwrite anything
   
else if ( glz_custom_fields_MySQL('check_migration') > ) {
     
// DEBUG
     // dmp(glz_custom_fields_MySQL('check_migration'));
     
$glz_notice[] = glz_custom_fields_gTxt("migration_skip");
     
// make a note of this migration in txp_prefs
     
glz_custom_fields_MySQL('mark_migration');
     return;
   }

   
// go through all values in custom field columns in textpattern table one by one
   
foreach ($all_custom_sets as $custom => $custom_set) {
     
// check only for custom fields that have been set
     
if ( $custom_set['name'] ) {
       
// get all existing custom values for ALL articles
       
$all_values glz_custom_fields_MySQL('all_values'glz_custom_number($custom), '', array('custom_set_name' => $custom_set['name'], 'status' => 0));
       
// if we have results, let's create SQL queries that will add them to custom_fields table
       
if ( count($all_values) > ) {
         
// initialize insert
         
$insert '';
         foreach ( 
$all_values as $escaped_value => $value ) {
           
// don't insert empty values or values that are over 255 characters
           // values over 255 characters hint to a textarea custom field
           
if ( !empty($escaped_value) && strlen($escaped_value) < 255 )
             
// if this is the last value, query will have to be different
             
$insert .= ( end($all_values) != $value ) ?
               
"('{$custom}','{$escaped_value}')," :
               
"('{$custom}','{$escaped_value}')";
         }
         
$query "
           INSERT INTO
             `"
.PFX."custom_fields` (`name`,`value`)
           VALUES
             
{$insert}
         "
;
         if ( isset(
$query) && !empty($query) ) {
           
// create all custom field values in custom_fields table
           
safe_query($query);
           
// update the type of this custom field to select (might want to make this user-adjustable at some point)
           
glz_custom_fields_MySQL("update"$customPFX."txp_prefs", array(
             
'custom_set_name'   => $custom_set['name'],
             
'custom_set_type'   => "select",
             
'custom_set_position' => $custom_set['position']
           ));
           
$glz_notice[] = glz_custom_fields_gTxt("migration_success");
         }
       }
     }
   }

   
// make a note of this migration in txp_prefs
   
glz_custom_fields_MySQL('mark_migration');
  }
}





global 
$event;

// globals, expensive operations mostly
before_glz_custom_fields();

if (@
txpinterface == "admin") {

  
// INSTALL ROUTINES
  // checks if all tables exist and everything is setup properly
  
add_privs('glz_custom_fields_install'"1");
  
register_callback("glz_custom_fields_install""plugin_lifecycle.glz_custom_fields""installed");

  
// we'll be doing this only on the pages that we care about, not everywhere
  
if ( in_array($event, array("article""prefs""glz_custom_fields""plugin_prefs.glz_custom_fields")) ) {
    
// we need some stylesheets & JS
    
add_privs('glz_custom_fields_css_js'"1,2,3,4,5,6");
    
register_callback('glz_custom_fields_css_js'"admin_side"'head_end');

    
// we need to make sure that all custom field values will be converted to strings first - think checkboxes & multi-selects etc.
    
if ( (gps("step") == "edit") || (gps("step") == "create") ) {
      
add_privs('glz_custom_fields_before_save'"1,2,3,4,5,6");
      
register_callback('glz_custom_fields_before_save'"article"''1);
    }
  }

  
// Custom Fields tab under Extensions
  
add_privs('glz_custom_fields'"1,2");
  
register_tab("extensions"'glz_custom_fields'"Custom Fields");
  
register_callback('glz_custom_fields'"glz_custom_fields");

  
// plugin preferences
  
add_privs('plugin_prefs.glz_custom_fields'"1,2");
  
register_callback('glz_custom_fields_preferences''plugin_prefs.glz_custom_fields');


  
// YES, finally the default custom fields are replaced by the new, pimped ones : )
  
add_privs('glz_custom_fields_replace'"1,2,3,4,5,6");
  
register_callback('glz_custom_fields_replace''article_ui''custom_fields');
  
// YES, now we have textarea custom fields as well ; )
  
register_callback('glz_custom_fields_replace''article_ui''body');
}

// -------------------------------------------------------------
// everything is happening in this function... generates the content for Extensions > Custom Fields
function glz_custom_fields() {
  global 
$event$all_custom_sets$glz_notice$prefs;

  
// we have $_POST, let's see if there is any CRUD
  
if ( $_POST ) {
    
$incoming stripPost();
    
// DEBUG
    // die(dmp($incoming));
    
extract($incoming);

    
// create an empty $value if it's not set in the $_POST
    
if ( !isset($value) )
      
$value '';

    
// we are deleting a new custom field
    
if ( gps('delete') ) {
      
glz_custom_fields_MySQL("delete"$custom_setPFX."txp_prefs");
      
glz_custom_fields_MySQL("delete"$custom_setPFX."txp_lang");
      
glz_custom_fields_MySQL("delete"$custom_setPFX."custom_fields");

      
glz_custom_fields_MySQL("delete"glz_custom_number($custom_set), PFX."textpattern");

      
$glz_notice[] = glz_custom_fields_gTxt("deleted", array('{custom_set_name}' => $custom_set_name));
    }

    
// we are resetting one of the mighty 10
    
if ( gps('reset') ) {
      
glz_custom_fields_MySQL("reset"$custom_setPFX."txp_prefs");
      
glz_custom_fields_MySQL("delete"$custom_setPFX."custom_fields");

      
glz_custom_fields_MySQL("reset"glz_custom_number($custom_set), PFX."textpattern", array(
        
'custom_set_type' => $custom_set_type,
        
'custom_field' => glz_custom_number($custom_set)
      ));

      
$glz_notice[] = glz_custom_fields_gTxt("reset", array('{custom_set_name}' => $custom_set_name));
    }

    
// we are adding a new custom field
    
if ( gps("custom_field_number") ) {
      
$custom_set_name gps("custom_set_name");

      
// if no name was specified, abort
      
if ( !$custom_set_name )
        
$glz_notice[] = glz_custom_fields_gTxt("no_name");
      else {
        
$custom_set_name glz_clean_string($custom_set_name);

        
$name_exists glz_check_custom_set_name($all_custom_sets$custom_set_name);

        
// if name doesn't exist
        
if ( $name_exists == FALSE ) {
          
glz_custom_fields_MySQL("new"$custom_set_namePFX."txp_prefs", array(
            
'custom_field_number' => $custom_field_number,
            
'custom_set_type'     => $custom_set_type,
            
'custom_set_position' => $custom_set_position
          
));
          
glz_custom_fields_MySQL("new"$custom_set_namePFX."txp_lang", array(
            
'custom_field_number' => $custom_field_number,
            
'lang'                => $GLOBALS['prefs']['language']
          ));
          
glz_custom_fields_MySQL("new"$custom_set_namePFX."textpattern", array(
            
'custom_field_number' => $custom_field_number,
            
'custom_set_type' => $custom_set_type
          
));
          
// there are custom fields for which we do not need to touch custom_fields table
          
if ( !in_array($custom_set_type, array("textarea""text_input")) ) {
            
glz_custom_fields_MySQL("new"$custom_set_namePFX."custom_fields", array(
              
'custom_field_number' => $custom_field_number,
              
'value'               => $value
            
));
          }

          
$glz_notice[] = glz_custom_fields_gTxt("created", array('{custom_set_name}' => $custom_set_name));
        }
        
// name exists, abort
        
else
          
$glz_notice[] = glz_custom_fields_gTxt("exists", array('{custom_set_name}' => $custom_set_name));
      }
    }

    
// we are editing an existing custom field
    
if ( gps('save') ) {
      if ( !empty(
$custom_set_name) ) {
        
$custom_set_name glz_clean_string($custom_set_name);
        
$name_exists glz_check_custom_set_name($all_custom_sets$custom_set_name$custom_set);
        
// if name doesn't exist we'll need to create a new custom_set
        
if ( $name_exists == FALSE ) {
          
glz_custom_fields_MySQL("update"$custom_setPFX."txp_prefs", array(
            
'custom_set_name'     => $custom_set_name,
            
'custom_set_type'     => $custom_set_type,
            
'custom_set_position' => $custom_set_position
          
));

          
// custom sets need to be changed based on their type
          
glz_custom_fields_MySQL("update"$custom_setPFX."textpattern", array(
            
'custom_set_type' => $custom_set_type,
            
'custom_field' => glz_custom_number($custom_set)
          ));

          
// for textareas we do not need to touch custom_fields table
          
if ( $custom_set_type != "textarea" ) {
            
glz_custom_fields_MySQL("delete"$custom_setPFX."custom_fields");
            
glz_custom_fields_MySQL("new"$custom_set_namePFX."custom_fields", array(
              
'custom_set'  => $custom_set,
              
'value'       => $value
            
));
          }

          
$glz_notice[] = glz_custom_fields_gTxt("updated", array('{custom_set_name}' => $custom_set_name));
        }
        
// name exists, abort
        
else
          
$glz_notice[] = glz_custom_fields_gTxt("exists", array('{custom_set_name}' => $custom_set_name));
      }
      else
        
$glz_notice[] = glz_custom_fields_gTxt('no_name');
    }

    
// need to re-fetch data since things modified
    
$all_custom_sets glz_custom_fields_MySQL("all");

  }

  
pagetop("Custom Fields");

  
// the table with all custom fields follows
  
echo
    
n.'<div class="listtables">'.n.
    
'  <table class="txp-list glz_custom_fields">'.n.
    
'    <thead>'.n.
    
'      <tr>'.n.
    
'        <th>Position</th>'.n.
    
'        <th>Name</th>'.n.
    
'        <th>Type</th>'.n.
    
'        <th>&nbsp;</th>'.n.
    
'      </tr>'.n.
    
'    </thead>'.n.
    
'    <tbody>'.n;

  
// looping through all our custom fields to build the table
  
$i 0;
  foreach ( 
$all_custom_sets as $custom => $custom_set ) {
    
// first 10 fields cannot be deleted, just reset
    
if ( $i 10 ) {
      
// can't reset a custom field that is not set
      
$reset_delete = ( $custom_set['name'] ) ?
        
glz_form_buttons("reset""Reset"$customhtmlspecialchars($custom_set['name']), $custom_set['type'], '''return confirm(\'By proceeding you will RESET ALL data in `textpattern` and `custom_fields` tables for `'.$custom.'`. Are you sure?\');') :
        
NULL;
    }
    else {
      
$reset_delete glz_form_buttons("delete""Delete"$customhtmlspecialchars($custom_set['name']), $custom_set['type'], '''return confirm(\'By proceeding you will DELETE ALL data in `textpattern` and `custom_fields` tables for `'.$custom.'`. Are you sure?\');');
    }

    
$edit glz_form_buttons("edit""Edit"$customhtmlspecialchars($custom_set['name']), $custom_set['type'], $custom_set['position']);

    echo
    
'      <tr>'.n.
    
'        <td class="custom_set_position">'.$custom_set['position'].'</td>'.n.
    
'        <td class="custom_set_name">'.$custom_set['name'].'</td>'.n.
    
'        <td class="type">'.(($custom_set['name']) ? glz_custom_fields_gTxt($custom_set['type']) : '').'</td>'.n.
    
'        <td class="events">'.$reset_delete.sp.$edit.'</td>'.n.
    
'      </tr>'.n;

    
$i++;
  }

  echo
    
'    </tbody>'.n.
    
'  </table>'.n;
    
'</div>'.n;

  
// the form where custom fields are being added/edited
  
$legend gps('edit') ?
    
'Edit '.gps('custom_set') :
    
'Add new custom field';

  
$custom_field gps('edit') ?
    
'<input name="custom_set" value="'.gps('custom_set').'" type="hidden" />' :
    
'<input name="custom_field_number" value="'.glz_custom_next($all_custom_sets).'" type="hidden" />';

  
$custom_set gps('edit') ?
    
gps('custom_set') :
    
NULL;

  
$custom_name gps('edit') ?
    
gps('custom_set_name') :
    
NULL;

  
$custom_set_position gps('edit') ?
    
gps('custom_set_position') :
    
NULL;

  
$arr_custom_set_types glz_custom_set_types();

  
$custom_set_types NULL;
  foreach ( 
$arr_custom_set_types as $custom_type_group => $custom_types ) {
    
$custom_set_types .= '<optgroup label="'.ucfirst($custom_type_group).'">'.n;
    foreach (
$custom_types as $custom_type) {
      
$selected = ( gps('edit') && gps('custom_set_type') == $custom_type ) ?
        
' selected="selected"' :
        
NULL;
      
$custom_set_types .= '<option value="'.$custom_type.'"'.$selected.'>'.glz_custom_fields_gTxt($custom_type).'</option>'.n;
    }
    
$custom_set_types .= '</optgroup>'.n;
  }
  
// fetching the values for this custom field
  
if ( gps('edit') ) {
    if ( 
$custom_set_type == "text_input" )
      
$arr_values glz_custom_fields_MySQL('all_values'glz_custom_number($custom_set), '', array('custom_set_name' => $custom_set_name'status' => 4));
    else
      
$arr_values glz_custom_fields_MySQL("values"$custom_set'', array('custom_set_name' => $custom_set_name));

    
$values = ( $arr_values ) ?
      
implode("\r\n"$arr_values) :
      
'';
  }
  else
    
$values '';

  
$action gps('edit') ?
    
'<input name="save" value="Save" type="submit" class="submit" />' :
    
'<input name="add_new" value="Add new" type="submit" class="submit" />';
  
// this needs to be different for a script
  
$value = ( isset($custom_set_type) && $custom_set_type == "custom-script" ) ?
    
'<input type="text" name="value" id="value" value="'.$values.'" class="left"/><span class="right"><em>Relative path from your website\'s public folder</em></span>' :
    
'<textarea name="value" id="value" class="left">'.$values.'</textarea><span class="right"><em>Each value on a separate line</em> <br /><em>One {default} value allowed</em></span>';

  
// ok, all is set, let's build the form
  
echo
    
'<form method="post" action="index.php" id="add_edit_custom_field">'.n.
    
'<input name="event" value="glz_custom_fields" type="hidden" />'.n.
    
$custom_field.n.
    
'<fieldset>'.n.
    
' <legend>'.$legend.'</legend>'.n.
    
' <p class="clearfix">
        <label for="custom_set_name" class="left">Name:</label>
        <input type="text" name="custom_set_name" value="'
.htmlspecialchars($custom_name).'" id="custom_set_name" class="left" />
        <span class="right"><em>Only word characters allowed</em></span>
      </p>'
.n.
    
' <p class="clearfix">
        <label for="custom_set_type" class="left">Type:</label>
        <select name="custom_set_type" id="custom_set_type" class="left">
    '
.      $custom_set_types.'
        </select>
      </p>'
.n.
    
' <p class="clearfix">
        <label for="custom_set_position" class="left">Position:</label>
        <input type="text" name="custom_set_position" value="'
.htmlspecialchars($custom_set_position).'" id="custom_set_position" class="left" />
        <span class="right"><em>Automatically assigned if blank</em></span>
      </p>'
.n.
    
' <p class="clearfix">
        <label for="value" class="left">Value:</label>
    '
.  $value.'
      </p>'
.n.
    
' '.$action.n.
    
'</fieldset>'.n.
    
'</form>'.n;
}


// -------------------------------------------------------------
// glz_custom_fields preferences
function glz_custom_fields_preferences() {
  global 
$event$glz_notice;

  if ( 
$_POST && gps('save') ) {
    
glz_custom_fields_MySQL("update_plugin_preferences"$_POST['glz_custom_fields_prefs']);
    
$glz_notice[] = glz_custom_fields_gTxt("preferences_updated");
    
// need to re-fetch from db because this has changed since $prefs has been populated
  
}
  
$current_preferences glz_custom_fields_MySQL('plugin_preferences');

  
pagetop("glz_custom_fields Preferences");

  
// custom_fields
  
$arr_values_ordering = array(
    
'ascending'   => "Ascending",
    
'descending'  => "Descending",
    
'custom'      => "As entered"
  
);
  
$values_ordering '<select name="glz_custom_fields_prefs[values_ordering]" id="glz_custom_fields_prefs_values_ordering">';
  foreach ( 
$arr_values_ordering as $value => $title ) {
    
$selected = ($current_preferences['values_ordering'] == $value) ? ' selected="selected"' '';
    
$values_ordering .= "<option value=\"$value\"$selected>$title</option>";
  }
  
$values_ordering .= "</select>";
  
$multiselect_size '<input type="text" name="glz_custom_fields_prefs[multiselect_size]" id="glz_custom_fields_prefs_multiselect_size" value="'.$current_preferences['multiselect_size'].'" />';
  
$custom_scripts_path_error = ( @fopen($current_preferences['custom_scripts_path'], "r") ) ?
    
'' :
    
'<br /><em class="red">Folder does not exist, please create it.</em>';

  
// jquery.datePicker
  
$datepicker_url_error = ( @fopen($current_preferences['datepicker_url']."/datePicker.js""r") ) ?
    
'' :
    
'<br /><em class="red">Folder does not exist, please create it.</em>';
  
$arr_date_format = array("dd/mm/yyyy""mm/dd/yyyy""yyyy-mm-dd""dd mm yy");
  
$date_format '<select name="glz_custom_fields_prefs[datepicker_format]" id="glz_custom_fields_prefs_datepicker_format">';
  foreach ( 
$arr_date_format as $format ) {
    
$selected = ($current_preferences['datepicker_format'] == $format) ? ' selected="selected"' '';
    
$date_format .= "<option value=\"$format\"$selected>$format</option>";
  }
  
$date_format .= "</select>";

  
$arr_days = array('Sunday''Monday''Tuesday''Wednesday''Thursday''Friday''Saturday');
  
$first_day '<select name="glz_custom_fields_prefs[datepicker_first_day]" id="glz_custom_fields_prefs_datepicker_first_day">';
  foreach ( 
$arr_days as $key => $day ) {
    
$selected = ($current_preferences['datepicker_first_day'] == $key) ? ' selected="selected"' '';
    
$first_day .= "<option value=\"$key\"$selected>$day</option>";
  }
  
$first_day .= "</select>";

  
$start_date '<input type="text" name="glz_custom_fields_prefs[datepicker_start_date]" id="glz_custom_fields_prefs_datepicker_start_date" value="'.$current_preferences['datepicker_start_date'].'" />';

  
// jquery.timePicker
  
$timepicker_url_error = ( @fopen($current_preferences['timepicker_url']."/timePicker.js""r") ) ?
    
'' :
    
'<br /><em class="red">Folder does not exist, please create it.</em>';
  
$arr_time_format = array('true' => "24 hours"'false' => "12 hours");
  
$show_24 '<select name="glz_custom_fields_prefs[timepicker_show_24]" id="glz_custom_fields_prefs_timepicker_show_24">';
  foreach ( 
$arr_time_format as $value => $title ) {
    
$selected = ($current_preferences['timepicker_show_24'] == $value) ? ' selected="selected"' '';
    
$show_24 .= "<option value=\"$value\"$selected>$title</option>";
  }
  
$show_24 .= "</select>";

  
$out = <<<EOF
<form action="index.php" method="post">
<table id="list" class="glz_custom_fields_prefs" cellpadding="0" cellspacing="0" align="center">
  <tbody>
    <tr class="heading">
      <td colspan="2"><h2 class="pref-heading">Custom Fields</h2></td>
    </tr>
    <tr>
      <th scope="row"><label for="glz_custom_fields_prefs_values_ordering">Order for custom field values</th>
      <td>
{$values_ordering}</td>
    </tr>
    <tr>
      <th scope="row"><label for="glz_custom_fields_prefs_multiselect_size">Multi-select field size</th>
      <td>
{$multiselect_size}</td>
    </tr>
    <tr>
      <th scope="row"><label for="glz_custom_fields_prefs_custom_scripts_path">Custom scripts path</th>
      <td><input type="text" name="glz_custom_fields_prefs[custom_scripts_path]" id="glz_custom_fields_prefs_custom_scripts_path" value="
{$current_preferences['custom_scripts_path']}" />{$custom_scripts_path_error}</td>
    </tr>

    <tr class="heading">
      <td colspan="2"><h2 class="pref-heading left">Date Picker</h2> <a href="http://www.kelvinluck.com/assets/jquery/datePicker/v2/demo/index.html" title="A flexible unobtrusive calendar component for jQuery" class="right">jQuery datePicker</a></td>
    </tr>
    <tr>
      <th scope="row"><label for="glz_custom_fields_prefs_datepicker_url">Date Picker plugin URL</th>
      <td><input type="text" name="glz_custom_fields_prefs[datepicker_url]" id="glz_custom_fields_prefs_datepicker_url" value="
{$current_preferences['datepicker_url']}" />{$datepicker_url_error}</td>
    </tr>
    <tr>
      <th scope="row"><label for="glz_custom_fields_prefs_datepicker_format">Date format</th>
      <td>
{$date_format}</td>
    </tr>
    <tr>
      <th scope="row"><label for="glz_custom_fields_prefs_datepicker_first_day">First day of week</th>
      <td>
{$first_day}</td>
    </tr>
    <tr>
      <th scope="row"><label for="glz_custom_fields_prefs_datepicker_start_date">Start date</th>
      <td>
{$start_date}<br /><em class="grey">MUST be the same as "Date format"</em></td>
    </tr>

    <tr class="heading">
      <td colspan="2"><h2 class="pref-heading left">Time Picker</h2> <a href="http://labs.perifer.se/timedatepicker/" title="jQuery time picker" class="right">jQuery timePicker</a></td>
    </tr>
    <tr>
      <th scope="row"><label for="glz_custom_fields_prefs_timepicker_url">Time Picker plugin URL</th>
      <td><input type="text" name="glz_custom_fields_prefs[timepicker_url]" id="glz_custom_fields_prefs_timepicker_url" value="
{$current_preferences['timepicker_url']}" />{$timepicker_url_error}</td>
    </tr>
    <tr>
      <th scope="row"><label for="glz_custom_fields_prefs_timepicker_start_time">Start time</th>
      <td><input type="text" name="glz_custom_fields_prefs[timepicker_start_time]" id="glz_custom_fields_prefs_timepicker_start_time" value="
{$current_preferences['timepicker_start_time']}" /></td>
    </tr>
    <tr>
      <th scope="row"><label for="glz_custom_fields_prefs_timepicker_end_time">End time</th>
      <td><input type="text" name="glz_custom_fields_prefs[timepicker_end_time]" id="glz_custom_fields_prefs_timepicker_end_time" value="
{$current_preferences['timepicker_end_time']}" /></td>
    </tr>
    <tr>
      <th scope="row"><label for="glz_custom_fields_prefs_timepicker_step">Step</th>
      <td><input type="text" name="glz_custom_fields_prefs[timepicker_step]" id="glz_custom_fields_prefs_timepicker_step" value="
{$current_preferences['timepicker_step']}" /></td>
    </tr>
    <tr>
      <th scope="row"><label for="glz_custom_fields_prefs_timepicker_step">Time format</th>
      <td>
{$show_24}</td>
    </tr>

    <tr>
      <td colspan="2" class="noline">
        <input class="publish" type="submit" name="save" value="Save" />
        <input type="hidden" name="event" value="plugin_prefs.glz_custom_fields" />
      </td>
    </tr>
  </tbody>
</table>
EOF;

  echo 
$out;
}