<?php
/*
Plugin Name: Group Tag Entry
Plugin URI: 
Description: Allows you to set up groups of tags, and then assign them to posts by selecting check boxes, drop-down lists, and the like. 
Version: 1.0
Author: Jennifer Hodgdon, Poplar ProductivityWare
Author URI: http://poplarware.com

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.
*/

$grouptagsFileName = plugin_basename(__FILE__);
$grouptagsTextDomain = 'grouptags';
$grouptagsDBVersion = 1;
$grouptagsElemTable = $wpdb->prefix . 'grouptags_ui_elems';
$grouptagsSubelemTable = $wpdb->prefix . 'grouptags_ui_subelems';
$grouptagsBlankItemCount = 3;

add_action('activate_' . $grouptagsFileName, 'grouptags_install_tables');
add_action('dbx_post_advanced', 'grouptags_post_entry_section' );
add_action('save_post', 'grouptags_post_save' );
add_action('admin_menu', 'grouptags_admin_screen');
add_action('admin_print_scripts', 'grouptags_js_header');

// Activation function -- creates or updates database tables for plugin
function grouptags_install_tables()
{ 
  global $grouptagsDBVersion, $grouptagsElemTable, $grouptagsSubelemTable;

   // newer versions of WP have this file in a different place...

   if( file_exists( ABSPATH . 'wp-admin/includes/upgrade.php' ))
     require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
   else
     require_once(ABSPATH . 'wp-admin/upgrade-functions.php');
   
   $elemStructure = "CREATE TABLE " . $grouptagsElemTable . " (" .
                "elem_id BIGINT(20) NOT NULL AUTO_INCREMENT, \n" .
                "elem_type VARCHAR(15) NOT NULL, \n" .
                "elem_display_name VARCHAR(50) NOT NULL, \n" .
                "elem_order DOUBLE NOT NULL, \n" .
                "PRIMARY KEY  (elem_id), \n" .
                "KEY elem_order (elem_order));";

   $subelemStructure = "CREATE TABLE " . $grouptagsSubelemTable . " (" .
                "subelem_id BIGINT(20) NOT NULL AUTO_INCREMENT, \n" .
                "elem_id BIGINT(20) NOT NULL, \n" .
                "subelem_display_name VARCHAR(50), \n" .
                "subelem_order DOUBLE, \n" .
                "subelem_tags TEXT, \n" .
                "PRIMARY KEY  (subelem_id), \n" .
                "KEY subelem_order (subelem_order), \n" .
                "KEY (elem_id));" ;

    dbDelta( $elemStructure, true );
    dbDelta( $subelemStructure, true );
 
    add_option( "grouptags_db_version", $grouptagsDBVersion );
    update_option( "grouptags_db_version", $grouptagsDBVersion );
} // end of grouptags_install_tables function

// Sets up admin screen for plugin
function grouptags_admin_screen()
{
  global $grouptagsTextDomain, $grouptagsFileName;

  add_options_page( __('Group Tags Setup', $grouptagsTextDomain), 
                    __('Group Tags', $grouptagsTextDomain), 6, 
                    $grouptagsFileName, 
                    'grouptags_setup_page' );
} // end of grouptags_admin_screen function

// Creates and processes the admin setup page
function grouptags_setup_page()
{
  global $grouptagsTextDomain;
  global $grouptagsBlankItemCount;

  // read current UI info from db

  $info = _grouptags_get_ui_info();

  // See if we have posted info

  if( $_POST['grouptags_hidden'] == 'Y' ) {

    // clear old info from DB
    _grouptags_clear_elems();

    $skipping = 1;
    $last_id = -1;
    $new_id = -1;
    $last_type = '';
    $last_disp = '';

    // go through old IDs and see if we have info for them

    for( $i = 0; $i < count( $info ); $i++ ) {
      $id = $info[$i]['elem_id'];

      if( $id != $last_id ) {
        // we have arrived at a new item in the array...

        if( !$skipping ) {
          // process new sub-items
          for( $j = 0; $j < $grouptagsBlankItemCount; $j++ ) {
            $subid = "New" . $j;
            _grouptags_process_subelem( $last_id, $subid, $new_id );
          }
        }

        // see if we are skipping this item or not
        // and save the item info

        $last_id = $id;
        $ord = $_POST['grouptags_order_' . $id ];

        if( $ord < 0 ) {
          $skipping = 1;
        } else {
          $skipping = 0;
          $last_ord = $ord;
          $last_type = $_POST['grouptags_type_' . $id ];
          $last_disp = $_POST['grouptags_dispname_' . $id ];
          $new_id = _grouptags_insert_elem( $last_type, $last_disp, $last_ord );
        }
      }
    
      // process sub-item info

      if( !$skipping ) {
        if( $last_type == "checkbox" ) {

          // should only be one sub-item, get and save info
          $subid = $info[$i]['subelem_id'];
          $tags = $_POST['grouptags_tags_' . $last_id . '_' . $subid ];

          _grouptags_insert_subelem( $new_id, '', 1, $tags );

          // skip any other sub-items left over from before
          $skipping = 1;

        } else if( $last_type != "label" ) {
          // process all subitems, with full info

          $subid = $info[$i]['subelem_id'];
          _grouptags_process_subelem( $last_id, $subid, $new_id );
        }
      }

    }

    // process any new sub-items in last item
    if( !$skipping ) {
      for( $j = 0; $j < $grouptagsBlankItemCount; $j++ ) {
        $subid = "New" . $j;
        _grouptags_process_subelem( $last_id, $subid, $new_id );
      }
    }

    // see if user has added any new items - could be up to 3 of them

    for( $i = 0; $i < $grouptagsBlankItemCount; $i++ ) {
      $id = "New" . $i;
      $ord = $_POST['grouptags_order_' . $id ];

      if( $ord > 0 ) {

        $type = $_POST['grouptags_type_' . $id ];
        $disp = $_POST['grouptags_dispname_' . $id ];
        $new_id = _grouptags_insert_elem( $type, $disp, $ord );

        // process sub-items

        $todo = $grouptagsBlankItemCount;
        if( $type == "checkbox" ) { 
          $todo = 1;
        } else if( $type == "label" ) {
          $todo = 0;
        }

        for( $j = 0; $j < $todo; $j++ ) {
          $subid = "New" . $j;
          _grouptags_process_subelem( $id, $subid, $new_id );
        }
      }
    }

    // now re-read info from DB
    $info = _grouptags_get_ui_info();

  }

  // page header

  ?>
      <div class="wrap">
         <h2><?php _e('Tag Groups Setup', $grouptagsTextDomain ); ?></h2>
         <h3><?php _e('Tag Group Entry Section:', $grouptagsTextDomain ); ?></h3>
         <p><?php _e('(Hints and Output Preview at bottom of page...)', $grouptagsTextDomain ); ?></p>
         
<form name="form1" method="post">
         <input type="hidden" name="grouptags_hidden" value="Y">
  <?

  // display current items in text entry fields

  $last_elem_id = -1;
  $last_elem_type = '';
  $count = 0;
  $elem_start = "<hr /><p>";
  $subelems_start = "</p><ul>";
  $elem_end = "</ul>\n";

  foreach( $info as $item ) {
    if( $item['elem_id'] != $last_elem_id ) {

      // close out the previous element, if it was open

      if( $count ) {
        if( $last_elem_type != "label" && 
            $last_elem_type != "checkbox" ) {
          echo _grouptags_blank_subelems( $item['elem_id'] );
        }

        echo $elem_end;
      }

      // start a new element

      echo $elem_start;

      echo _grouptags_order_box( $item['elem_order'], 1, $item['elem_id'] ) . " " .
        _grouptags_type_dropdown( $item['elem_type'], $item['elem_id'] ) . " " . 
        _grouptags_disp_name_box( $item['elem_display_name'], 1, $item['elem_id'] );

      echo $subelems_start;

      $last_elem_id = $item['elem_id'];
      $last_elem_type = $item['elem_type'];
    }

    $count++;

    // put in sub-elem info

    if( $item['elem_type'] == "checkbox" ) {
      echo "<li>" .
        _grouptags_tag_box( $item['subelem_tags'], $item['elem_id'], $item['subelem_id'] ) . 
        "</li>";
    } else if( $item['elem_type'] != "label" ) {

      echo "<li>" .
        _grouptags_order_box( $item['subelem_order'], 0, $item['elem_id'], $item['subelem_id'] ) . " " .
        _grouptags_disp_name_box( $item['subelem_display_name'], 0, $item['elem_id'], $item['subelem_id'] ) . " " .
        "<br />" .
        _grouptags_tag_box( $item['subelem_tags'], $item['elem_id'], $item['subelem_id'] ) . 
        "</li>";
    }
  }

  if( $count ) {
    if( $last_elem_type != "label" && 
        $last_elem_type != "checkbox" ) {
      echo _grouptags_blank_subelems( $item['elem_id'] );
    }

    echo $elem_end;
  }

  // add some blank lines for new elements

  for( $i = 0; $i < $grouptagsBlankItemCount; $i++ ) {

    $id = "New" . $i;

    echo $elem_start;
    echo _grouptags_order_box( -1, 1, $id ) . " " .
      _grouptags_type_dropdown( '', $id ) . " " . 
      _grouptags_disp_name_box( '', 1, $id );

    echo $subelems_start;
    echo _grouptags_blank_subelems( $id );
    echo $elem_end;

  }

  // submit button and form close

  ?>
          <p class="submit">
          <input type="submit" name="Submit" value="<?php _e('Update Tag Groups', $grouptagsTextDomain) ?>" />
          </p>
         </form>

         <hr />
         <h3><?php _e('Data Entry Hints:', $grouptagsTextDomain ); ?></h3>
         <ul>
         <li><?php _e( "Terminlology: Labels, Check Boxes, etc. are Elements. WIthin some Elements, you have Items (such as the items in a drop-down list).", $grouptagsTextDomain ); ?></li>
         <li><?php _e( "The overall Order number determines the order of Elements on the page. The item Order number determines the order of items in a list.", $grouptagsTextDomain ); ?></li>
         <li><?php _e( "You can use decimal points in your Order numbers, for instance 2.5 to go between order 2 and order 3.", $grouptagsTextDomain ); ?></li>
         <li><?php _e( "Set the Order to -1 to delete/omit an item or element. When entering an item/element for the first time, you must change the Order to something other than -1, or it will be ignored.", $grouptagsTextDomain ); ?></li>
         <li><?php _e( "Separate tags by commas in Tags fields.", $grouptagsTextDomain ); ?></li>
         <li><?php _e( "When defining a Check Box, only fill in the Tags field on the first item in the group. Leave the other items blank.", $grouptagsTextDomain ); ?></li>
         <li><?php _e( "When defining a Label, leave all items blank.", $grouptagsTextDomain ); ?></li>
         <li><?php _e( "If you need more blank lines to define new elements, or to add more items within elements, save what you have and more blank lines will appear.", $grouptagsTextDomain ); ?></li>
         </ul>
         <hr />

         <h3><?php _e('Preview of Tag Entry Section:', $grouptagsTextDomain ); ?></h3>
      <form>
       <?php _grouptags_tag_entry_form( ); ?>
      </form>
        </div>

  <?php

} // end of grouptags_setup_page function

// internal function: processes a POSTed sub-elem
function _grouptags_process_subelem( $elem_id, $subid, $new_elem_id ) {
  $subord = $_POST['grouptags_sub_order_' . $elem_id . '_' . $subid ];
  $disp = $_POST['grouptags_sub_dispname_' . $elem_id . '_' . $subid ];
  $tags = $_POST['grouptags_tags_' . $elem_id . '_' . $subid ];

  if( $subord > 0 ) {
    _grouptags_insert_subelem( $new_elem_id, $disp, $subord, $tags );
  }
}

// internal function: returns a string containing blank sub-elem lines
function _grouptags_blank_subelems( $id ) {

  global $grouptagsBlankItemCount;

  $str = '';

  for( $i = 0; $i < $grouptagsBlankItemCount; $i++ ) {

    $str .= "<li>";
    $sub_id = "New" . $i;
    $str .= _grouptags_order_box( -1, 0, $id, $sub_id ) . " " .
      _grouptags_disp_name_box( '', 0, $id, $sub_id ) . " " .
      "<br />" .
      _grouptags_tag_box( '', $id, $sub_id ) . 
      "</li>\n";
  }

  return $str;
}

// internal function: returns a string containing an order text box
// inputs: current value of order, true/false is it an item (or subitem),
// item ID, sub-item ID (can omit)
function _grouptags_order_box( $ord, $is_item, $id, $sub_id = 0 ) {
  global $grouptagsTextDomain;

  $str = '';

  $str .= __("Order:", $grouptagsTextDomain );
  $str .= " ";
  $str .= '<input type="text" size="5" value="' . $ord . '" ';
  if( $is_item ) {
    $str .= 'name="grouptags_order_' . $id;
  } else {
    $str .= 'name="grouptags_sub_order_' . $id . '_' . $sub_id;
  }

  $str .= '"' . ">\n";

  return $str;
}

// internal function: returns a string containing an item type drop-down
// inputs: current value of type, item ID
function _grouptags_type_dropdown( $type, $id ) {
  global $grouptagsTextDomain;

  $types = array( 'label', 'checkbox', 'drop-down', 'radio' );
  $labels = array( __('Label', $grouptagsTextDomain), 
                   __('Check box', $grouptagsTextDomain),
                   __('Drop-Down List', $grouptagsTextDomain),
                   __('Radio Button Group', $grouptagsTextDomain ));

  $str = '';

  $str .= '<select name="grouptags_type_' . $id . '">' . "\n";

  for( $i = 0; $i < count( $types ); $i++ ) {
    $str .= '<option value="' . $types[$i] . '"';
    if( $types[$i] == $type ) {
      $str .= " selected";
    }
    $str .= ">" . $labels[$i] . "</option>\n";
  }

  $str .= "</select>\n";

  return $str;

}

// internal function: returns a string containing a display name textbox
// inputs: current value of name, true/false is it an item (or subitem),
// item ID, sub-item ID (can omit)
function _grouptags_disp_name_box( $name, $is_item, $id, $sub_id = 0 ) {
  global $grouptagsTextDomain;

  $str = '';

  $str .= __("Displayed Name:", $grouptagsTextDomain );
  $str .= " ";
  $str .= '<input type="text" size="30" value="' . 
    _grouptags_escape_dq( $name ). '" ';
  if( $is_item ) {
    $str .= 'name="grouptags_dispname_' . $id;
  } else {
    $str .= 'name="grouptags_sub_dispname_' . $id . '_' . $sub_id;
  }

  $str .= '"' . ">\n";

  return $str;
}

// internal function: returns a string containing a tags textbox
// inputs: current value of tags, item ID, sub-item ID (can omit)
function _grouptags_tag_box( $tags, $id, $sub_id = 0 ) {
  global $grouptagsTextDomain;

  $str = '';

  $str .= __("Tags:", $grouptagsTextDomain );
  $str .= " ";
  $str .= '<input type="text" size="80" value="' . 
    _grouptags_escape_dq( $tags ). '" ';
  $str .= 'name="grouptags_tags_' . $id . '_' . $sub_id . '"';

  $str .= ">\n";

  return $str;
}

// Internal function: returns the string with double quotes
// escaped for HTML use
function _grouptags_escape_dq( $str ) {
  return preg_replace( '/"/', '&quot;', _grouptags_remove_backslash( $str ));
}

// Internal function: removes backslashes in a string and returns it
function _grouptags_remove_backslash( $str ) {
  return preg_replace( "/\\\\/", '', $str );
}

// Internal function: prints the tag entry form. Returns an array
// of tags that were not found in the UI elements
function _grouptags_tag_entry_form( $tags = array() ) {

  global $grouptagsTextDomain;

  $info = _grouptags_get_ui_info();
  $tags_found = array();

  $last_elem_id = -1;
  $elem_start = "<br /><br />\n";
  $subelem_pre = "";
  $subelem_mid = "";
  $subelem_post = "";
  $elem_end = "";
  $dosubs = 0;
  $radio_count = 0;

  foreach( $info as $item ) {

    $thistags = explode( ',', $item['subelem_tags'] );
    for( $i = 0; $i < count( $thistags ); $i++ ) {
      $thistags[$i] = trim( $thistags[$i] );
    }

    if( $item['elem_id'] != $last_elem_id ) {

      // close out the previous element
      // and start a new element

      if( $last_elem_id != -1 ) {
        echo $elem_end;
        echo $elem_start;
      }

      $last_elem_id = $item['elem_id'];
      $elem_end = '';
      $subelem_pre = '';
      $subelem_mid = '';
      $subelem_mid_selected = '';
      $subelem_post = '';
      $dosubs = 0;
      
      
      if( $item['elem_type'] == "label" ) {
        echo "<strong>" . $item['elem_display_name'] . "</strong>";

      } else if( $item['elem_type'] == "checkbox" ) {

        echo '<input type="checkbox" value="' . 
          _grouptags_escape_dq( $item['subelem_tags'] ) . 
          '" name="grouptags_tags[]"';

        if( count( array_intersect( $tags, $thistags ))) {
          echo " checked";
          $tags_found = array_merge( $tags_found, $thistags );
        }

        echo '> '.
          $item['elem_display_name'];

      } else if( $item['elem_type'] == "drop-down" ) {

        echo $item['elem_display_name'] . ": ";

        echo '<select name="grouptags_tags[]">' . "\n";
        echo "<option />\n";
        $elem_end = '</select>' . "\n";
        $dosubs = 1;

        $subelem_pre = '<option value="';
        $subelem_mid = '">';
        $subelem_post = "</option>\n";
        $subelem_mid_selected = '" selected>';

      } else { // radio
        $radio_count++;
        echo $item['elem_display_name'] . ":\n";

        $dosubs = 1;
        $subelem_pre = 
          '<br /><input type="radio" name="grouptags_radio_' . $radio_count . 
          '" value="';
        $subelem_mid = '"> ';
        $subelem_post = "\n";
        $subelem_mid_selected = '" checked>';
      }

    }

    // put in sub-elem info

    if( $dosubs ) {
      echo $subelem_pre . _grouptags_escape_dq( $item['subelem_tags'] );

      if( count( array_intersect( $tags, $thistags ))) {
        echo $subelem_mid_selected;
        $tags_found = array_merge( $tags_found, $thistags );
      } else {
        echo $subelem_mid;
      }

      echo $item['subelem_display_name'] .
        $subelem_post;
    }
  }

  echo $elem_end;

  return array_diff( $tags, $tags_found );
}

// JavaScript for post editing screen
function grouptags_js_header() 
{

  global $editing, $post, $post_ID;
  global $grouptagsTextDomain;

  if( !$editing ) {
    // not on a post/page edit screen
    return;
  }

  if( $post && $post->post_type == 'page' ) {
    // it's a page, not a post -- note that $post is NOT set for a new
    // page/post, see below
    return;
  }

  // check the URL to see if it's a new page screen
  $req_url = $_SERVER['REQUEST_URI'];
  if( preg_match( '/page-new.php$/', $req_url )) {
    // it's the "new page" editing screen, not new post
    return;
  }

  // if we get here, we are on a post editing page, so we need the 
  // JavaScript for this page

  // we need JQuery library loaded...
  wp_print_scripts( array( 'jquery' ));
  
  // Set up JavaScript array of existing tags for lookup

?>
<style type="text/css">
#grouptags_popup ul { list-style: none; color: black; background: #eeeeee; border: 1px solid black; margin: 0; padding: 0; width: 150px;}
#grouptags_popup ul li { margin-left: 0; padding: 2px; text-indent: 0;}
.gtselected { background: white; font-style: bold;}
</style>

<script type="text/javascript">
  //<![CDATA[

   var grouptags_all_tags = new Array();

<?php

  $all_tags = get_terms( 'post_tag', 'hide_empty=0' );
  
  $i = 0;
  foreach( $all_tags as $item ) {
    $item = sanitize_term( $item, 'post_tag', 'display' );

    if( strlen( $item->name )) {
      echo "grouptags_all_tags[$i] = " . '"' .
        _grouptags_escape_dq( $item->name ) . '";' . "\n";

      $i++;
    }
  }
?>

  grouptags_all_tags.sort();

  var grouptags_curr_choices;

  function grouptags_list_choices() {
    grouptags_hide_choices();

    // figure out what tags to suggest

    // first find what the user is typing
    var txt = jQuery( '#grouptags_free_entry' ).val();

    // go back to previous comma
    var start = txt.lastIndexOf(',');
    if( start ) {
      txt = txt.substr( start + 1 );
    }
    while( txt.charAt(0) == ' ' && txt.length ) {
      txt = txt.substr( 1 );
    }

    if( !txt.length ) {
      // nothing to suggest
      return;
    }

    // now see which tags match this

    jQuery( '#grouptags_popup' ).html( '<ul></ul>' );

    grouptags_curr_choices = new Array();
    var count = 0;
    var i;
    for( i = 0; i < grouptags_all_tags.length; i++ ) {
      if( grouptags_all_tags[i].indexOf( txt ) == 0 ) {
        grouptags_curr_choices[ count ] = grouptags_all_tags[i];
        count++;
        jQuery( '#grouptags_popup ul' ).append( '<li>' + grouptags_all_tags[i] + '</li>' );
      }
    }

    if( !count ) {
      return;
    }

    jQuery( '#grouptags_popup ul li' ).hover( 
      function( ) {
        jQuery( this ).addClass( "gtselected" );
      },
      function( ) {
        jQuery( this ).removeClass( "gtselected" );
      });

    jQuery( '#grouptags_popup ul li' ).click( function() {
        var prev = jQuery( '#grouptags_free_entry' ).val();
        if( prev.lastIndexOf( ',' ) > 1 ) {
          prev = prev.substring( 0, prev.lastIndexOf( ',' ) + 1) + ' ';
        } else {
          prev = '';
        }
        prev = prev + jQuery( this ).text() + ", ";

        jQuery( '#grouptags_free_entry' ).val( prev );
        jQuery( '#grouptags_free_entry' ).focus();
        grouptags_hide_choices();
      });

    jQuery( '#grouptags_popup' ).show();

  }

  function grouptags_hide_choices() {
    grouptags_curr_choices = new Array();
    jQuery( '#grouptags_popup' ).hide();
  }

  addLoadEvent( function() {
      jQuery( '#grouptags_free_entry' ).keyup( function( e ) {
          var kc = e.which;
          if( !e.which ) {
            kc = window.keyCode;
          }

          if( kc == 27  || kc == 44 || kc == 188 ) { 
            // escape/comma -- hide choices
            grouptags_hide_choices();
          } else if(( kc >= 65 && 
                      kc <= 90 ) ||
                    ( kc >= 97 && 
                      kc <= 122 ) ||
                    kc == 8 ) { 
            // alpha character, or backspace: put up choice list
            // note: timeout is to allow choice to get into drop-down
            setTimeout( grouptags_list_choices, 100 );
          }
          
        }); 

   });
                    
//]]>
</script>
<?php

}  // end of grouptags_js_header function


// Post edit screen section for group tag entry
function grouptags_post_entry_section() {
  global $post_ID;
  global $grouptagTextDomain;

  // header info

  echo '<div class="dbx-b-ox-wrapper">' . "\n";
  echo '<fieldset id="group_tag_entry" class="dbx-box">' . "\n";
  echo '<div class="dbx-h-andle-wrapper"><h3 class="dbx-handle">' . 
        __( "Group Tag Entry - Overrides tag field above!", $grouptagTextDomain ) . "</h3></div>";   
   
  echo '<div class="dbx-c-ontent-wrapper"><div class="dbx-content" ' .
    ' id="group_tag_entry_section">';

  echo '<p>';
  _e( 'Note: If you have already typed in tags using the Tags field above, you MUST re-enter them in this section!', $grouptagTextDomain );
  echo '</p>';

  $curr_tags = wp_get_object_terms( $post_ID, 'post_tag' );
  $tags = array();
  foreach( $curr_tags as $tag ) {
    $tags[] = $tag->name;
  }

  $leftovers = _grouptags_tag_entry_form( $tags );

  echo "<br /><br />Additional Tags (separate by commas):" . 
    '<input type="text" id="grouptags_free_entry" name="grouptags_tags[]" value="' .
    _grouptags_escape_dq( implode( ', ', $leftovers )) . '" style="width:90%">';

  echo '<br /><div id="grouptags_popup"></div>';

  echo "</div></fieldset></div>\n";
}  // end of grouptags_post_entry_section function

// Process tags on post save
function grouptags_post_save( $post_id ) {

  $newtags = '';
  $comma = '';
  foreach( $_POST['grouptags_tags'] as $entry ) {
    $entry = trim( $entry );
    if( strlen( $entry )) {
      $newtags .= $comma . $entry;
      $comma = ',';
    }
  }

  for( $i = 1; $i < 100; $i++ ) {
    if( $_POST['grouptags_radio_' . $i ] ) {
      $entry = trim( $_POST['grouptags_radio_' . $i ] );
      if( strlen( $entry )) {
        $newtags .= $comma . $entry;
        $comma = ',';
      }
    }
  }

  wp_set_post_tags( $post_id, $newtags );

} // end of grouptags_post_save function


// Internal function: reads the current UI info from the database
// and returns it as an array of objects
function _grouptags_get_ui_info() {

  global $grouptagsElemTable, $grouptagsSubelemTable;
  global $wpdb;

  $qryStr = "SELECT " .
    "$grouptagsElemTable.elem_id as elem_id, " .
    "$grouptagsElemTable.elem_type as elem_type, " .
    "$grouptagsElemTable.elem_display_name as elem_display_name, " .
    "$grouptagsElemTable.elem_order as elem_order, " .
    "$grouptagsSubelemTable.subelem_id as subelem_id, " .
    "$grouptagsSubelemTable.subelem_display_name as subelem_display_name, " .
    "$grouptagsSubelemTable.subelem_order as subelem_order, " .
    "$grouptagsSubelemTable.subelem_tags as subelem_tags " .
    "FROM $grouptagsElemTable LEFT JOIN $grouptagsSubelemTable ON " .
    "$grouptagsElemTable.elem_id = $grouptagsSubelemTable.elem_id " .
    "ORDER BY elem_order, subelem_order";

  $info = $wpdb->get_results( $qryStr, ARRAY_A );
  if( !$info ) {
    return array();
  }

  return $info;
}

// internal function: clears database of elements and sub-elements
function _grouptags_clear_elems() {
  global $grouptagsElemTable, $grouptagsSubelemTable;
  global $wpdb;

  $qryStr = "TRUNCATE $grouptagsElemTable";
  $wpdb->query( $qryStr );

  $qryStr = "TRUNCATE $grouptagsSubelemTable";
  $wpdb->query( $qryStr );
}

// internal function: adds a new element, returns ID
 function _grouptags_insert_elem( $type, $disp, $ord ) {

  global $grouptagsElemTable;
  global $wpdb;

  $qryStr = "INSERT INTO $grouptagsElemTable (elem_type, elem_display_name, elem_order) VALUES ('" . 
    $wpdb->escape( _grouptags_remove_backslash( $type )) . "', '" .
    $wpdb->escape( _grouptags_remove_backslash( $disp )) . "', '" .    
    $wpdb->escape( intval( _grouptags_remove_backslash( $ord ))) . "')";

  $wpdb->query( $qryStr );
  return $wpdb->insert_id;
}

// internal function: adds a new sub-element, returns ID
function _grouptags_insert_subelem( $elem_id, $disp, $ord, $tags ) {
  global $grouptagsSubelemTable;
  global $wpdb;

  $qryStr = "INSERT INTO $grouptagsSubelemTable (elem_id, subelem_display_name, subelem_order, subelem_tags) VALUES ('" . 
    $wpdb->escape( _grouptags_remove_backslash( intval( $elem_id ))) . "', '" .    
    $wpdb->escape( _grouptags_remove_backslash( $disp )) . "', '" .    
    $wpdb->escape( intval( _grouptags_remove_backslash( $ord ))) . "', '" .    
    $wpdb->escape( _grouptags_remove_backslash( $tags )) . "')";

  $wpdb->query( $qryStr );
  return $wpdb->insert_id;

}

?>
