<?php

# PLUGIN PREVIEW BY TEXTPATTERN.INFO

/**
 * smd_thumbnail
 *
 * A Textpattern CMS plugin for managing multiple image thumbnails:
 *  -> Create unlimited thumbnail profiles of differing sizes for various site uses
 *  -> Thumbnail files are created in your image directory -- no realtime scaling
 *  -> Batch create / alter thumbnails
 *  -> Choose to sync the thumbnails with Textpattern's own thumbs
 *
 * @author Stef Dawson
 * @link   http://stefdawson.com/
 * TODO: Make Selections (lines 912-916) optional via prefs or something
 * TODO: Simplify AJAX response packets to speed things up
 * TODO: Interface elements for Profile creation don't get rendered if there are no images in pool
 */
if (!defined('SMD_THUMB')) {
    
define("SMD_THUMB"'smd_thumbnail');
}
if (!
defined('SMD_THUMB_ACTIVE')) {
    
define("SMD_THUMB_ACTIVE"1);
}
if (!
defined('SMD_THUMB_CROP')) {
    
define("SMD_THUMB_CROP"2);
}
if (!
defined('SMD_THUMB_SHARP')) {
    
define("SMD_THUMB_SHARP"4);
}

if (
txpinterface === 'admin') {
    global 
$smd_thumb_event$smd_thumb_prevs;

    
$smd_thumb_event 'smd_thumbnail';
    
$smd_thumb_privs '1,2,3'// Plugin privs
    
$smd_thumb_prevs = array('1'); // Privs for prefs

    
add_privs($smd_thumb_event$smd_thumb_privs);
    
add_privs('smd_thumb_profiles'$smd_thumb_privs);
    
register_callback('smd_thumb_welcome''plugin_lifecycle.'.$smd_thumb_event);
    
register_callback('smd_thumb_profiles''image_ui''extend_controls');
    
register_callback('smd_thumbs''image_ui''thumbnail');
    
register_callback('smd_thumb_edit''image_ui''thumbnail_edit');
    
register_callback('smd_thumb_empty''image_ui''thumbnail_image');
    
register_callback('smd_thumb_empty''image_ui''thumbnail_create');
    
register_callback('smd_thumb_generate''image_uploaded''image');
    
register_callback('smd_thumb_generate''image_uploaded''moderate');
    
register_callback('smd_thumb_delete''image_deleted''image');
    
register_callback('smd_thumb_create_one''image''smd_thumb_create_one');
    
register_callback('smd_thumb_switch_active''image''smd_thumb_switch_active');
    
register_callback('smd_thumb_switch_pref''image''smd_thumb_switch_pref');
    
register_callback('smd_thumb_insert''image''smd_thumbnail_insert'1);
    
register_callback('smd_thumb_inject_css''admin_side''head_end');
} elseif (
txpinterface === 'public') {
    
smd_thumb_set_impath();
    if (
class_exists('\Textpattern\Tag\Registry')) {
        
Txp::get('\Textpattern\Tag\Registry')
            ->
register('smd_thumbnail')
            ->
register('smd_if_thumbnail')
            ->
register('smd_thumbnail_info');
    }
}

/**
 * CSS definitions: hopefully kind to themers.
 */
function smd_thumb_get_style_rules()
{
    
$smd_thumb_styles = array(
        
'smd_thumb' =>'
.smd_selected { border:1px solid #1b3eb7; background:#1b3eb7; }
#smd_thumbs img { padding:2px; margin:1px; border:1px solid black; }
.smd_hidden { display:none; }
.smd_thumb_new_profile { display:table-row; }
#smd_thumb_profiles { clear:both; margin:0 auto 1em; }
#smd_thumb_profiles .txp-summary { text-align:left; }
#smd_thumb_batch { float:right; }
.smd_inactive { opacity:.3; }
.smd_thumb_heading_active { cursor:pointer; }
#smd_thumb_profile_form table { width:100% }
.smd_thumb_switcher { float:right; }
.pref-label { text-align: right!important; }
#smd_thumb_profile_form th { display:none; }
#smd_thumb_profile_form td { display:block; }
#smd_thumb_profile_form td:first-child { padding-top:0.5em }
#smd_thumb_profile_form td:last-child { padding-bottom:0.5em }
#smd_thumb_profile_form td:before { content: attr(data-th) ": "; font-weight:bold; width:6.5em; display:inline-block; }
#smd_thumb_profile_form tr { border-top:1px solid #ccc; }
#smd_thumb_profile_form th, #smd_thumb_profile_form td { margin:0.3em 0.7em; }
@media (min-width:480px) {
  #smd_thumb_profile_form td:before { display:none; }
  #smd_thumb_profile_form th, #smd_thumb_profile_form td { display:table-cell; padding:.1em .1em; vertical-align:baseline }
  #smd_thumb_profile_form th:first-child, #smd_thumb_profile_form td:first-child { padding-left: 0; }
  #smd_thumb_profile_form th:last-child, #smd_thumb_profile_form td:last-child { padding-right: 0; }
}
'
);

    return 
$smd_thumb_styles;
}

/**
 * Inject the stylesheet rules into the matching panel.
 *
 * @param  string $evt Textpattern event (panel)
 * @param  string $stp Textpattern step (action)
 */
function smd_thumb_inject_css($evt$stp)
{
    global 
$event;

    if (
$event === 'image') {
        
$smd_thumb_styles smd_thumb_get_style_rules();
        echo 
'<style type="text/css">'$smd_thumb_styles['smd_thumb'], '</style>';
    }

    return;
}

/**
 * Kickstart the plugin after installation / activation / deletion.
 *
 * @param  string $evt Textpattern event (panel)
 * @param  string $stp Textpattern step (action)
 */
function smd_thumb_welcome($evt$stp)
{
    switch (
$stp) {
        case 
'installed':
            
smd_thumb_table_install();
            
// Remove per-user prefs on upgrade from v0.1x to v0.20.
            
safe_delete ('txp_prefs'"name IN ('smd_thumb_txp_create', 'smd_thumb_txp_delete', 'smd_thumb_auto_replace') AND user_name != ''");
            break;
        case 
'deleted':
            
smd_thumb_table_remove();
            break;
    }

    return;
}

/**
 * Display the designated default thumbnail on the list page.
 */
function smd_thumbs($evt$stp$dflt$currimg)
{
    
extract(gpsa(array('page''sort''dir''crit''search_method')));

    
$search_method = (is_array($search_method)) ? implode(','$search_method) : $search_method;

    if (
smd_thumb_table_exist()) {
        
$default get_pref('smd_thumb_default_profile'''1);

        if (
$default) {
            
$row safe_row('*'SMD_THUMB"name='".sanitizeForUrl($default)."'");

            if (
$row) {
                
$edit_url '?event=image'.a.'step=image_edit'.a.'id='.$currimg['id'].a.'sort='.$sort.
                        
a.'dir='.$dir.a.'page='.$page.a.'search_method[]='.$search_method.a.'crit='.$crit;
                
$out smd_thumb_img($row$currimg, array('class' => 'content-image '.$default));

                return (
$out) ? href($out$edit_url) : gTxt('no');
            } else {
                return 
gTxt('no');
            }
        } else {
            return 
gTxt('no');
        }
    }
}

/**
 * Don't want the 'create' controls or thumbnail image as they're both handled in the edit portion of the screen.
 */
function smd_thumb_empty($evt$stp$dflt$currimg)
{
    return 
' ';
}

/**
 * Create a bunch of thumbnails en masse.
 *
 * With a lot of images in the database, doing it all in one hit would time out.
 * Thus it's done via ajax; one request per image.
 *
 * @param  string $type Flavour of thumbnail creation: by (usr), by (cat), by (sel)ection, or (all)
 * @param  string $lst  List of images to operate upon
 * @return [type]       [description]
 */
function smd_thumb_create_group($type$lst '')
{
    switch (
$type) {
        case 
'all':
            
$where '1=1';
            break;
        case 
'sel':
            
$where = ($lst) ? 'id IN ('.doSlash($lst).')' '1=0';
            break;
        case 
'cat':
            
$where "category in ('".doSlash($lst)."')";
            break;
        case 
'usr':
            
$where "author in ('".doSlash($lst)."')";
            break;
    }

    
$images safe_column('id''txp_image'$where);
    
$count count($images);

    echo <<<EOJS
<script type="text/javascript">
var bctr = 0; var btot = 
{$count};
jQuery(function() {
    jQuery("#smd_thumb_btot").text("/'.
$count.'");
EOJS;

    foreach (
$images as $img) {
        echo <<<EOJS
    sendAsyncEvent(
    {
        event: textpattern.event,
        step: 'smd_thumb_create_one',
        smd_thumb_imgid: 
{$img}
    }, smd_create_group_feedback);
EOJS;
    }
    echo 
'});';
    echo <<<EOJS
function smd_create_group_feedback() {
    bctr++;
    jQuery('#smd_thumb_bcurr').text(bctr);
}
EOJS;
    echo 
'</script>';
}

/**
 * AJAX method to create one thumbnail for each active profile, from the passed id.
 */
function smd_thumb_create_one()
{
    
$currimg gps('smd_thumb_imgid');
    
assert_int($currimg);

    
$rs safe_rows('*'SMD_THUMB'1=1 AND flags & ' SMD_THUMB_ACTIVE);
    
$curr safe_row('*''txp_image'"id=" doSlash($currimg));

    if (
$rs) {
        
smd_thumb_make($rs$curr1);
        
send_xml_response();
    }
}

/**
 * AJAX method to set the active thumbnail profile.
 *
 * Requires GET/POST params:
 *  -> smd_thumb_profile TName of the profile to set as active
 */
function smd_thumb_switch_active()
{
    
$name doSlash(gps('smd_thumb_profile'));

    if (
$name) {
        
safe_update(SMD_THUMB'flags = flags ^ ' SMD_THUMB_ACTIVE"name='$name'");
        
send_xml_response(array('smd_thumb_profile' => $name));
    }
}

/**
 * AJAX method to toggle the given preference name to the given state.
 *
 * Requires GET/POST params:
 *  -> smd_thumb_txptype Preference name (without plugin prefix)
 *  -> smd_thumb_state   Preference value to store
 */
function smd_thumb_switch_pref()
{
    
$name doSlash(gps('smd_thumb_txptype'));
    
$state doSlash(gps('smd_thumb_state'));

    if (
$name) {
        
set_pref('smd_thumb_'.$name$state'smd_thumb'PREF_HIDDEN'text_input');
        
send_xml_response();
    }
}

/**
 * Wrapper to create thumbnail for active profiles from uploaded image.
 *
 * @param  string $evt Textpattern event (panel)
 * @param  string $stp Textpattern step (action)
 * @param  string $id  New image identifier. If omitted, will try GET/POST, then Txp's GLOBALS['ID']
 */
function smd_thumb_generate($evt$stp$id='')
{
    
$id = ($id) ? $id gps('id');
    
$id = ($id) ? $id $GLOBALS['ID'];
    
$rs safe_rows('*'SMD_THUMB'1=1 AND flags & ' SMD_THUMB_ACTIVE);

    
smd_thumb_make($rs$id);
}

/**
 * Wrapper to delete a bunch of selected thumbnails.
 *
 * Uses GET/POST parameters:
 *  -> selected Comma-separated list of selected image identifiers
 *
 * @param  string $evt Textpattern event (panel)
 * @param  string $stp Textpattern step (action)
 */
function smd_thumb_delete($evt$stp)
{
    
$ids gps('selected');
    
$rs safe_rows('*'SMD_THUMB'1=1');

    
$images safe_rows('*''txp_image''id IN (' join(',',quote_list($ids)) . ')');

    foreach (
$images as $img) {
        
smd_thumb_unmake($rs$img);
    }
}

/**
 * Create a thumbnail.
 *
 * @param  array  $rs       Record set containing image meta data
 * @param  int    $currimg  Identifier for the current image being operated upon
 * @param  bool   $force    Whether to always create the thumbnail, even if it exists
 * @return string           Feedback messageĀ§
 */
function smd_thumb_make($rs$currimg$force 0)
{
    
// Wrapper for wet_thumb to allow multiple thumbnails.
    
$msg '';
    
smd_thumb_set_impath();

    if (!
class_exists('smd_thumb')) {
        class 
smd_thumb extends wet_thumb
        
{
            var 
$m_ext;
            var 
$m_id;
            var 
$m_dir;
            var 
$m_dflt;
            var 
$width;
            var 
$height;
            var 
$force;

            
/**
             * Constructor.
             *
             * @param int     $id         Unique image identifier
             * @param string  $dir        Subdirectory in which to store the image
             * @param array   $img_row    Image meta data to store
             * @param boolean $is_default Whether the thumbnail is to become the default
             * @param string  $pro_w      Thumbnail width
             * @param string  $pro_h      Thumbnail height
             * @param boolean $force      Whether to overwrite any previous thumbnail
             */
            
public function __construct ($id$dir$img_row$is_default false$pro_w ''$pro_h ''$force 0)
            {
                
$id assert_int($id);

                if (
$img_row) {
                    
extract($img_row);
                    
$this->m_id $id;
                    
$this->m_ext $ext;
                    
$this->m_dir $dir;
                    
$this->force $force;
                    
$this->width $pro_w;
                    
$this->height $pro_h;
                    
$this->m_dflt $is_default;
                }

                
parent::__construct();
            }

            
/**
             * Store the thumbnail image on disk.
             *
             * @return bool
             */
            
public function write_image()
            {
                if (!isset(
$this->m_ext)) {
                    return 
false;
                }

                
$autor get_pref('smd_thumb_auto_replace''0');
                
$recfrom get_pref('smd_thumb_create_from''full');
                
$src_sz = ($recfrom === 'full') ? '' 't';
                
$infile IMPATH $this->m_id $src_sz $this->m_ext;
                
$outfile IMPATH $this->m_dir DS $this->m_id $this->m_ext;

                if (!
file_exists($outfile) || $autor || $this->force) {
                    
// If this is the default profile and the pref indicates, write a Txp thumb too.
                    
if (($this->m_dflt === true) && (get_pref('smd_thumb_txp_create''0'))) {
                        
$txp_thumb IMPATH $this->m_id 't' $this->m_ext;

                        if (
parent::write($infile$txp_thumb)) {
                            
safe_update('txp_image'"thumbnail = 1, thumb_w = $this->width, thumb_h = $this->height"'id = ' $this->m_id);
                            @
chmod($outfile0644);
                        }
                    }

                    if (
parent::write ($infile$outfile)) {
                        @
chmod($outfile0644);

                        return 
true;
                    }
                }

                return 
false;
            }
        }
    }

    
// If passed only an ID, look up the rest of the image data.
    
if (!is_array($currimg)) {
        
assert_int($currimg);
        
$currimg safe_row('*''txp_image''id=' $currimg);
    }

    
// Create each thumbnail.
    
$pro_dflt get_pref('smd_thumb_default_profile''');

    foreach (
$rs as $row) {
        
// Sanitize a little.
        
$width = (int) $row['width'];
        
$height = (int) $row['height'];

        if (
$width === 0) {
            
$width '';
        }

        if (
$height === 0) {
            
$height '';
        }

        if (
$width === '' && $height === '') {
            continue;
        }

        
$crop = ($row['flags'] & SMD_THUMB_CROP) ? 0;
        
$sharpen = ($row['flags'] & SMD_THUMB_SHARP) ? 0;
        
$id $currimg['id'];
        
$is_dflt = ($row['name'] === $pro_dflt) ? true false;

        
$t = new smd_thumb($idsanitizeForUrl($row['name']), $currimg$is_dflt$width$height$force);
        
$t->extrapolate true// Allow bigger thumbs than original image.
        
$t->crop = ($crop === 1);
        
$t->sharpen = ($sharpen === 1);
        
$t->hint '0';
        
$t->width $width;
        
$t->height $height;
        
$t->quality $row['quality'];

        if (
$t->write_image()) {
            
$msg gTxt('thumbnail_saved', array('{id}' => $id));
        } else {
            
$msg = array(gTxt('thumbnail_not_saved', array('{id}' => $id)), E_ERROR);
        }
    }

    return 
$msg;
}

/**
 * Delete the passed set of thumbnails.
 *
 * @param  array  $rs      Sert of image identifiers to delete
 * @param  int    $currimg Current image being operated upon
 */
function smd_thumb_unmake($rs$currimg)
{
    
$id $currimg['id'];
    
$ext $currimg['ext'];
    
$pro_dflt get_pref('smd_thumb_default_profile''');
    
$txp_del get_pref('smd_thumb_txp_delete''0');
    
smd_thumb_set_impath();

    foreach (
$rs as $row) {
        
$path IMPATH sanitizeForUrl($row['name']) . DS $id $ext;

        if (
file_exists($path)) {
            
unlink($path);
        }

        
// Also remove Txp's built-in thumb?
        
if (($row['name'] === $pro_dflt) && ($txp_del == '1')) {
            
$path IMPATH $id 't' $ext;

            if (
file_exists($path)) {
                
safe_update('txp_image'"thumbnail = 0, thumb_w = 0, thumb_h = 0"'id = ' $id);
                
unlink($path);
            }
        }
    }

    return 
'';
}

/**
 * Insert a thumbnail when a new file is uploaded
 */
function smd_thumb_insert()
{
    global 
$txpcfg$txp_user$page$sort$dir$crit$search_method;

    
smd_thumb_set_impath();
    
extract(gpsa(array('page''sort''dir''crit''search_method')));

    
$search_method = (is_array($search_method)) ? implode(','$search_method) : $search_method;

    include_once 
txpath.'/lib/txplib_misc.php';

    
extract($txpcfg);
    
$id assert_int(gps('id'));
    
$profile gps('smd_thumb_profile');
    
$thumb_ext gps('smd_thumb_ext');

    
$author fetch('author''txp_image''id'$id);

    if (!
has_privs('image.edit') && !($author == $txp_user && has_privs('image.edit.own'))) {
        return;
    }

    
$file $_FILES['thefile']['tmp_name'];
    
$name $_FILES['thefile']['name'];

    
$file get_uploaded_file($file);

    if (empty(
$file)) {
        return;
    }

    list(
$w$h$extension) = getimagesize($file);

    
$valid_exts = array(
        
IMAGETYPE_GIF  => '.gif',
        
IMAGETYPE_JPEG => '.jpg',
        
IMAGETYPE_PNG  => '.png',
        
IMAGETYPE_SWF  => '.swf',
    );

    
$ext = isset($valid_exts[$extension]) ? $valid_exts[$extension] : '';

    if ((
$file !== false) && $profile && $ext) {
        
$newpath IMPATH sanitizeForUrl($profile) . DS $id $ext;
        if (
shift_uploaded_file($file$newpath) === false) {
            
// Failed: do nothing.
        
} else {
            @
chmod($newpath0644);

            
// If the pref indicates, duplicate as a Txp thumb too.
            
if (get_pref('smd_thumb_txp_create''0') == 1) {
                
$txp_thumb IMPATH $id 't' $ext;

                if (
copy($newpath$txp_thumb)) {
                    
safe_update('txp_image'"thumbnail = 1, thumb_w = $w, thumb_h = $h"'id = ' $id);
                    @
chmod($txp_thumb0644);
                }
            }

            
$message gTxt('image_uploaded', array('{name}' => $name));
        }
    }

    
// Since the headers have been sent, resort to js to refresh the page.
    
$urlPieces = array(
        
'event'         => 'image',
        
'step'          => 'image_edit',
        
'id'            => $id,
        
'sort'          => $sort,
        
'dir'           => $dir,
        
'page'          => $page,
        
'search_method' => $search_method,
        
'crit'          => $crit,
    );

    
$url html_entity_decode(join_qs($urlPieces));

    echo <<<EOS
<script type="text/javascript">
window.location.href="
{$url}";
</script>
<noscript>
<meta http-equiv="refresh" content="0;url=
{$url}" />
</noscript>
EOS;
    exit;
}

/**
 * pluggable_ui callback to render the additions to the image edit panel.
 *
 * @param  string $evt     Textpattern event (panel)
 * @param  string $stp     Textpattern step (action)
 * @param  string $dflt    Default markup ready to render
 * @param  array  $currimg Current image information
 */
function smd_thumb_edit($evt$stp$dflt$currimg)
{
    global 
$step$file_max_upload_size$txp_user;

    
extract(gpsa(array(
        
'id',
        
'page',
        
'sort',
        
'dir',
        
'crit',
        
'search_method',
        
'smd_thumbnail_size',
        
'smd_thumbnail_chosen_size',
        
'smd_thumbnail_delete',
        
'smd_step'
    
)));

    
$id = ($id) ? $id $GLOBALS['ID'];
    
$search_method = (is_array($search_method)) ? implode(','$search_method) : $search_method;

    
// Toggle profile panel.
    
if ($step === 'save_pane_state') {
        
smd_thumbnail_save_pane_state();
        return;
    }

    
// Create/delete the selected thumbs depending on the button pressed.
    
if ($smd_step === 'smd_thumbnail_manage') {
        
// Validate user
        
$author fetch('author''txp_image''id'$id);

        if (!
has_privs('image.edit') && !($author == $txp_user && has_privs('image.edit.own'))) {
            
image_list(gTxt('restricted_area'));

            return;
        }

        
// Grab the thumbnails to work on
        
$where = ($smd_thumbnail_size === 'all') ? '1=1 AND flags & ' SMD_THUMB_ACTIVE "name='" doSlash($smd_thumbnail_chosen_size) . "'";
        
$rs safe_rows('*'SMD_THUMB$where);

        
// Do it.
        
if ($smd_thumbnail_delete) {
            
$msg smd_thumb_unmake($rs$currimg);
        } else {
            
$msg smd_thumb_make($rs$currimg1);
        }
    }

    
$ext $currimg['ext'];
    echo 
script_js(<<<EOC
function smd_thumb_selector(sel) {
    var idx = 0;
console.log(sel);
    jQuery("#smd_thumbs img").each(function() {
        if (jQuery(this).hasClass(sel)) {
            jQuery(this).toggleClass('smd_selected active');
            if (jQuery(this).hasClass('smd_selected')) {
                jQuery("#smd_upload_thumbnail").attr('disabled', false);
                jQuery("#smd_thumb_profile").val(sel);
                idx = jQuery("#smd_thumbnail_size option[value='"+sel+"']").index();
                jQuery("#smd_thumbnail_chosen_size").val(sel);
            } else {
                jQuery("#smd_upload_thumbnail").attr('disabled', true);
                jQuery("#smd_thumb_profile").val('');
                jQuery("#smd_thumbnail_chosen_size").val('');
            }
        } else {
            jQuery(this).removeClass('smd_selected active');
        }
    });
    jQuery("#smd_thumbnail_size").prop("selectedIndex", idx);
}
function smd_thumb_select_changed() {
    obj = jQuery("#smd_thumbnail_size");
    if (obj.attr("selectedIndex") == 0) {
        jQuery("#smd_upload_thumbnail").attr('disabled', true);
        jQuery("#smd_thumb_profile").val('');
        jQuery("#smd_thumbnail_chosen_size").val('');
    } else {
        jQuery("#smd_upload_thumbnail").attr('disabled', false);
        jQuery("#smd_thumb_profile").val(obj.val());
        jQuery("#smd_thumbnail_chosen_size").val(obj.val());
    }
    jQuery("#smd_thumbs img").each(function() {
        if (jQuery(this).hasClass(obj.val())) {
            jQuery(this).addClass('smd_selected active');
        } else {
            jQuery(this).removeClass('smd_selected active');
        }
    });
}
jQuery(function() {
    jQuery("#smd_thumbs img").each(function() {
        var prf = jQuery(this).data('profile');
        jQuery(this).click(function() {
            smd_thumb_selector(prf);
        });
    });
    jQuery("#smd_upload_thumbnail").attr('disabled', true);
    jQuery(".thumbnail-upload").prepend('<input type="hidden" name="smd_thumb_imgid" value="
{$id}" /><input type="hidden" id="smd_thumb_profile" name="smd_thumb_profile" value="" /><input type="hidden" id="smd_thumb_ext" name="smd_thumb_ext" value="{$ext}" />');
});
EOC
    );

    
// Add thumbnails and creation controls.
    
if (smd_thumb_table_exist()) {
        
$rs safe_rows('*'SMD_THUMB'1=1 ORDER BY name');

        if (
$rs) {
            
$profiles = array('all' => gTxt('smd_thumb_all_sizes'));
            
$thumbs[] = '<div id="smd_thumbs">';

            foreach (
$rs as $row) {
                if (
$row['flags'] & SMD_THUMB_ACTIVE) {
                    
$profiles[$row['name']] = $row['name'];
                }

                
$thumbs[] = smd_thumb_img($row$currimg, array(
                    
'class' => 'content-image ' $row['name'],
                    
'data-profile' => $row['name'],
                    ));
            }

            
$thumbs[] = '</div>';

            
$qs = array(
                
"event"         => 'image',
                
"step"          => 'image_edit',
                
"id"            => $id,
                
"page"          => $page,
                
"sort"          => $sort,
                
"dir"           => $dir,
                
"crit"          => $crit,
                
"search_method" => $search_method,
            );

            
$out[] = '<div id="smd_thumbnail_control"><span class="txp-summary lever'.(get_pref('pane_smd_thumbnails_visible') ? ' expanded' '').'"><a href="#smd_thumbnails">'.gTxt('smd_thumb_thumbnail_heading').'</a></span><div id="smd_thumbnails" class="toggle" style="display:'.(get_pref('pane_smd_thumbnails_visible') ? 'block' 'none').'">';
            
$out[] = upload_form(gTxt('smd_thumb_upload'), 'upload_thumbnail''smd_thumbnail_insert''image'$id$file_max_upload_size'smd_upload_thumbnail''thumbnail-upload');
            
$out[] = '<form name="smd_thumbnail_create" method="post" action="'.join_qs($qs).'">';
            
$out[] = fInput('hidden''smd_step''smd_thumbnail_manage');
            
$out[] = fInput('hidden''smd_thumbnail_chosen_size''''''''''''''smd_thumbnail_chosen_size');
            
$out[] = selectInput('smd_thumbnail_size'$profiles''''' onchange="return smd_thumb_select_changed()";''smd_thumbnail_size');
            
$out[] = fInput('submit'''gTxt('create'));
            
$out[] = fInput('submit''smd_thumbnail_delete'gTxt('delete'));
            
$out[] = join(''$thumbs);
            
$out[] = '</form>';
            
$out[] = '</div>';

            return 
join(n$out);
        }
    }

    return 
' ';
}

/**
 * Create an &ltimg&gt tag to a thumbnail.
 *
 * @param  array  $row     Thumbnail information
 * @param  array  $currimg Corresponding image information
 * @param  array  $meta    Thumbnail meta info
 * @param  string $dsp     Textpattern Form that contains rendering information
 * @return string
 */
function smd_thumb_img($row$currimg$meta = array(), $dsp '')
{
    global 
$img_dir$smd_thumb_data;

    
smd_thumb_set_impath();

    
$dir sanitizeForUrl($row['name']);
    
$id $currimg['id'];
    
$ext $currimg['ext'];

    
// alt is a mandatory attribute so make sure it exists (even if it's "").
    
if (!isset($meta['alt'])) {
        
$meta['alt'] = $currimg['alt'];
    }

    
$path IMPATH $dir DS $id $ext;

    if (
file_exists($path)) {
        
$extras '';

        if (isset(
$meta['forcew']) || isset($meta['forceh'])) {
            
$dims getimagesize($path);

            if (isset(
$meta['forcew']) && !$row['width']) {
                
$row['width'] = $dims[0];
            }

            if (isset(
$meta['forceh']) && !$row['height']) {
                
$row['height'] = $dims[1];
            }

            unset(
$meta['forcew']);
            unset(
$meta['forceh']);
        }

        if (isset(
$meta['width']) && $meta['width'] !== '') {
            
$row['width'] = $meta['width'];
        }

        if (isset(
$meta['height']) && $meta['height'] !== '') {
            
$row['height'] = $meta['height'];
        }

        unset(
$meta['width']);
        unset(
$meta['height']);

        
// 'empty' includes zero dimensions which omits the attribute and allows the browser to scale.
        
$w = (!empty($row['width'])) ? ' width="'.$row['width'].'"''';
        
$h = (!empty($row['height'])) ? ' height="'.$row['height'].'"''';

        
$uDate '';

        if (!isset(
$meta['stamp'])) {
            
$uDate '?' filemtime($path);
        }

        unset(
$meta['stamp']);

        if (!isset(
$meta['class'])) {
            
$meta['class'] = $dir;
        }

        foreach (
$meta as $key => $val) {
            
// We need all atts for container tags, but only valid HTML atts should appear in the default <img> tag.
            
if (in_array($key, array('alt''class''title')) || strpos($key'data-') === 0) {
                
$extras .= ' ' $key '="' $val '"';
            }
        }

        if (
$dsp) {
            
// Hand off to the form/container for formatting advice
            
$smd_thumb_data $meta;
            
$smd_thumb_data['id'] = $id;
            
$smd_thumb_data['ext'] = $ext;
            
$smd_thumb_data['alt'] = $alt;
            
$smd_thumb_data['w'] = $row['width'];
            
$smd_thumb_data['h'] = $row['height'];
            
$smd_thumb_data['html_w'] = $w;
            
$smd_thumb_data['html_h'] = $h;
            return 
parse($dsp);
        } else {
            return 
'<img src="' ihu $img_dir '/' $dir '/' $id $ext $uDate '"' $w $h $extras ' />';
        }
    }

    return 
'';
}

/**
 * Callback to render profiles control area on Images panel.
 *
 * @param  string $evt     Textpattern event (panel)
 * @param  string $stp     Texpattern step (action)
 * @param  string $dflt    Default content HTML
 * @param  array  $imglist Record set of all images in the list
 * @return string          HTML
 */
function smd_thumb_profiles($evt$stp$dflt$imglist)
{
    global 
$smd_thumb_event$step$smd_thumb_prevs$txp_user;

    if (!
has_privs(__FUNCTION__)) {
        return;
    }

    
extract(gpsa(array(
        
'page',
        
'sort',
        
'dir',
        
'crit',
        
'search_method',
        
'smd_thumb_add',
        
'smd_thumb_cancel',
        
'smd_thumb_save',
        
'smd_thumb_name',
        
'smd_thumb_newname',
        
'smd_thumb_add_newname',
        
'smd_thumb_width',
        
'smd_thumb_add_width',
        
'smd_thumb_height',
        
'smd_thumb_add_height',
        
'smd_thumb_quality',
        
'smd_thumb_add_quality',
        
'smd_thumb_active',
        
'smd_thumb_active_new',
        
'smd_thumb_add_active_new',
        
'smd_thumb_crop',
        
'smd_thumb_add_crop',
        
'smd_thumb_sharpen',
        
'smd_thumb_add_sharpen',
        
'smd_thumb_default',
        
'smd_thumb_add_default',
        
'smd_thumb_selected',
        
'smd_thumb_cat_selected',
        
'smd_thumb_usr_selected',
        
'smd_thumb_group_type',
    )));

    if (
$smd_thumb_add) {
        
$smd_thumb_newname $smd_thumb_add_newname;
        
$smd_thumb_width $smd_thumb_add_width;
        
$smd_thumb_height $smd_thumb_add_height;
        
$smd_thumb_quality $smd_thumb_add_quality;
        
$smd_thumb_active_new $smd_thumb_add_active_new;
        
$smd_thumb_crop $smd_thumb_add_crop;
        
$smd_thumb_sharpen $smd_thumb_add_sharpen;
        
$smd_thumb_default $smd_thumb_add_default;
    }

    
// Sanitize.
    
$search_method = (is_array($search_method)) ? implode(','$search_method) : $search_method;
    
$quality = (is_numeric($smd_thumb_quality)) ? (($smd_thumb_quality 0) ? 75 : (($smd_thumb_quality 100) ? 75 $smd_thumb_quality) ) : 75;
    
$width = (is_numeric($smd_thumb_width)) ? $smd_thumb_width 0;
    
$height = (is_numeric($smd_thumb_height)) ? $smd_thumb_height 0;
    
$newname sanitizeForUrl($smd_thumb_newname);
    
$msg '';

    
smd_thumb_set_impath();

    
// Table control.
    
if (gps('remove')) {
        
smd_thumb_table_remove();
    } else {
        if (!
smd_thumb_table_exist()) {
            
smd_thumb_table_install();
        }
    }

    
// Action to toggle profile panel.
    
if ($step === 'save_pane_state') {
        
smd_thumbnail_save_pane_state();
        return;
    }

    
// Action to create thumbnails.
    
if ($step === 'smd_thumb_create_group') {
        switch (
$smd_thumb_group_type) {
            case 
'all':
                
smd_thumb_create_group('all');
                break;
            case 
'sel':
                
smd_thumb_create_group('sel'rtrim($smd_thumb_selected','));
                break;
            case 
'cat':
                
smd_thumb_create_group('cat'$smd_thumb_cat_selected);
                break;
            case 
'usr':
                
smd_thumb_create_group('usr'$smd_thumb_usr_selected);
                break;
        }

        
set_pref('pane_smd_thumb_group_type'$smd_thumb_group_type'smd_thumb'PREF_HIDDEN'text_input'0PREF_PRIVATE);
        
$step 'smd_thumb_prefs';
    }

    
// Action to save profile.
    
if ($step === 'smd_thumb_profile_save') {
        if (
smd_thumb_table_exist()) {
            if (
$smd_thumb_cancel) {
                
// Do nothing.
            
} elseif ($smd_thumb_add) {
                
// Create new profile.
                
$exists safe_row('*'SMD_THUMB"name='" doSlash($newname) . "'");

                if (
$exists) {
                    
$msg gTxt('smd_thumb_profile_exists', array('{name}' => doSlash($newname)));
                } else {
                    if (
$newname) {
                        
$flags 0;
                        
$flags = ($smd_thumb_active_new) ? $flags SMD_THUMB_ACTIVE $flags;
                        
$flags = ($smd_thumb_crop) ? $flags SMD_THUMB_CROP $flags;
                        
$flags = ($smd_thumb_sharpen) ? $flags SMD_THUMB_SHARP $flags;

                        
safe_insert(
                            
SMD_THUMB,
                            
"name='" doSlash($newname) . "'"
                            
", width='" doSlash($width) . "'"
                            
", height='" doSlash($height) . "'"
                            
", quality='" doSlash($quality) . "'"
                            
", flags='" doSlash($flags) . "'"
                        
);

                        
// Alter the default thumbnail.
                        
if ($smd_thumb_default) {
                            
set_pref('smd_thumb_default_profile'$newname'smd_thumb'PREF_HIDDEN);
                        }

                        
// Create the thumbnail directory
                        
@mkdir(IMPATH.$newname);
                    }
                }
            } else {
                
// Update existing profile.
                
$name sanitizeForUrl($smd_thumb_name);
                
$exists safe_row('*'SMD_THUMB"name='" doSlash($newname) . "'");

                if (
$exists && strtolower($newname) !== strtolower($name)) {
                    
$msg gTxt('smd_thumb_profile_exists', array('{name}' => doSlash($newname)));
                } else {
                    if (
$newname) {
                        
$flags 0;
                        
$flags = ($smd_thumb_active) ? $flags SMD_THUMB_ACTIVE $flags;
                        
$flags = ($smd_thumb_crop) ? $flags SMD_THUMB_CROP $flags;
                        
$flags = ($smd_thumb_sharpen) ? $flags SMD_THUMB_SHARP $flags;

                        
safe_update(
                            
SMD_THUMB,
                            
"name='" doSlash($newname) . "'"
                            
", width='" doSlash($width) . "'"
                            
", height='" doSlash($height) . "'"
                            
", quality='" doSlash($quality) . "'"
                            
", flags='" doSlash($flags) . "'"
                            
"name='" doSlash($name) . "'"
                        
);

                        
// Alter the default thumbnail.
                        
if ($smd_thumb_default) {
                            
set_pref('smd_thumb_default_profile'$newname'smd_thumb'PREF_HIDDEN);
                        } else {
                            
// Remove the default flag if this used to be the default.
                            
if (get_pref('smd_thumb_default_profile') === doSlash($name)) {
                                
set_pref('smd_thumb_default_profile''''smd_thumb'PREF_HIDDEN);
                            }
                        }

                        
// Adjust the thumbnail directory if the name has changed
                        
if ($newname != $name) {
                            
rename(IMPATH.$nameIMPATH.$newname);
                        }
                    }
                }
            }
        } else {
            
$msg gTxt('smd_thumb_tables_not_installed');
        }

        
$step 'smd_thumb_profile';
    }

    
// Action to delete a profile.
    
if ($step === 'smd_thumb_profile_delete') {
        if (
smd_thumb_table_exist()) {
            
$txp_del get_pref('smd_thumb_txp_delete');
            
$the_dflt get_pref('smd_thumb_default_profile'''1);

            if (!empty(
$smd_thumb_name)) {
                
$name sanitizeForUrl($smd_thumb_name);
                
$ret safe_delete(SMD_THUMB"name='" doSlash($name) . "'");
                if (
$ret) {
                    
smd_thumb_rmdir(IMPATH.$name);

                    
// Delete all Txp thumbs too?
                    
if (($name == $the_dflt) && ($txp_del == '1')) {
                        
$rs safe_rows('id, ext''txp_image''thumbnail = 1');

                        foreach (
$rs as $row) {
                            
$path IMPATH $row['id'] . 't' $row['ext'];

                            if (
file_exists($path)) {
                                
unlink($path);
                            }
                        }

                        
safe_update('txp_image''thumbnail = 0, thumb_w = 0, thumb_h = 0''thumbnail = 1');
                    }

                    
// Remove the default flag if this used to be the default
                    
if (get_pref('smd_thumb_default_profile') === doSlash($name)) {
                        
set_pref('smd_thumb_default_profile''''smd_thumb'PREF_HIDDEN);
                    }

                    
$msg gTxt('smd_thumb_profile_deleted', array('{name}' => doSlash($name)));
                }
            }
        }

        
$step 'smd_thumb_profile';
    }

    
$qs = array(
        
"event"         => 'image',
        
"page"          => $page,
        
"sort"          => $sort,
        
"dir"           => $dir,
        
"crit"          => $crit,
        
"search_method" => $search_method,
    );

    
$privs safe_field('privs''txp_users'"name = '" doSlash($txp_user) . "'");
    
$rights in_array($privs$smd_thumb_prevs) ? true false;

    
// Action to show thumbnail prefs.
    
if ($step === 'smd_thumb_prefs') {
        if (
smd_thumb_table_exist()) {
            
$pro_dflt get_pref('smd_thumb_default_profile'''1);

            
// Subselect lists for type 'cat' and 'usr'.
            
$rs getTree('root''image');
            
$allCats $rs treeSelectInput('smd_thumb_cat_selected'$rs'') : '';
            
$allCats "<span>".str_replace(array("\n"'-'), array('''&#45;'), str_replace('</''<\/'addslashes($allCats)))."<\/span>";
            
$rs safe_column('name''txp_users'"privs not in(0,6) order by name asc");
            
$allUsrs $rs selectInput('smd_thumb_usr_selected'$rs''true) : '';
            
$allUsrs "<span>".str_replace(array("\n"'-'), array('''&#45;'), str_replace('</''<\/'addslashes($allUsrs)))."<\/span>";

            echo 
script_js(<<<EOC
function smd_thumb_switch_pref(obj, name) {
    if (name == 'create_from') {
        state = jQuery(obj).val();
    } else {
        state = (jQuery(obj).prop('checked')) ? 1 : 0;
    }
    sendAsyncEvent(
    {
        event: textpattern.event,
        step: 'smd_thumb_switch_pref',
        smd_thumb_txptype: name,
        smd_thumb_state: state
    });
}
function smd_thumb_copy_selected() {
    jQuery("#images_form tbody .multi-edit input:checked, #images_form tbody .txp-list-col-multi-edit input:checked").each(function() {
        jQuery("#smd_thumb_selected").val(jQuery("#smd_thumb_selected").val() + jQuery(this).val() + ',');
    });
}
function smd_thumb_subsel(obj) {
    obj = jQuery(obj);
    dest = jQuery('#smd_thumb_subsel');
    item = obj.val();
    switch (item) {
        case 'all':
        case 'sel':
            dest.empty();
            break;
        case 'cat':
            dest.empty().prepend('
{$allCats}');
            break;
        case 'usr':
            dest.empty().prepend('
{$allUsrs}');
            break;
    }
}
jQuery(function() {
    jQuery('#smd_thumb_group_type').change();
});
EOC
        );

            
$btnPnl '<a class="smd_thumb_switcher" href="?event=image'.a.'sort='.$sort.a.'dir='.$dir.a.'page='.$page.a.'search_method[]='.$search_method.a.'crit='.$crit.'">'.gTxt('smd_thumb_btn_pnl').'</a>';
            
$btnGrp '<button class="navlink" type="submit" onclick="smd_thumb_copy_selected(); return confirm(\''.gTxt('smd_thumb_create_group_confirm').'\');">'.gTxt('smd_thumb_all_thumbs').'</button>';
            
$grpTypes = array(
                
'sel' => gTxt('smd_thumb_bysel'),
                
'cat' => gTxt('category'),
                
'usr' => gTxt('author'),
                
'all' => gTxt('smd_thumb_byall'),
            );

            
$grpOpts selectInput('smd_thumb_group_type'$grpTypesget_pref('pane_smd_thumb_group_type''all'1), ''' onchange="smd_thumb_subsel(this);"''smd_thumb_group_type').'<span id="smd_thumb_subsel"></span>';

            
$out[] = '<div id="smd_thumb_profiles"><h3 class="txp-summary lever'.(get_pref('pane_smd_thumbnail_profiles_visible') ? ' expanded' '').'"><a href="#smd_thumbnail_profiles">'.(($rights) ? gTxt('smd_thumb_profile_preftool_heading') : gTxt('smd_thumb_profile_tool_heading')).'</a></h3><div id="smd_thumbnail_profiles" class="toggle" style="display:'.(get_pref('pane_smd_thumbnail_profiles_visible') ? 'block' 'none').'">';
            
$out[] = '<div class="txp-buttons">'.$btnPnl.'</div>';

            
$out[] = '<div id="smd_thumb_batch"><span id="smd_thumb_bcurr"></span><span id="smd_thumb_btot"></span></div>';
            
$out[] = '<form method="post" name="smd_thumb_multi_edit" id="smd_thumb_multi_edit" action="'.join_qs($qs).'">';
            
$out[] = startTable();
            
$out[] = tr(td(gTxt('smd_thumb_batch_preamble') . $grpOpts $btnGrp));
            
$out[] = endTable();
            
$out[] = fInput('hidden''smd_thumb_selected''''''''''''''smd_thumb_selected');
            
$out[] = eInput($smd_thumb_event);
            
$out[] = sInput('smd_thumb_create_group');
            
$out[] = '</form>';

            if (
$rights) {
                
$out[] = '<div><h4>'.gTxt('smd_thumb_prefs').'</h4>';
                
$out[] = '<form method="post" name="smd_thumb_prefs" id="smd_thumb_prefs_form" action="'.join_qs($qs).'">';

                
$txp_rf get_pref('smd_thumb_create_from''full');
                
$out[] = '<div class="txp-prefs-group">';
                
$out[] = '<div class="txp-form-field">';
                
$out[] = '<div class="txp-form-field-label"><label>' gTxt('smd_thumb_txp_create_from') . '</label></div>';
                
$out[] = '<div class="txp-form-field-value">
                        <label>
                            <input type="radio"
                                name="smd_thumb_create_from"
                                value="full"'
                                
. (($txp_rf=='full') ? ' checked="checked"' '')
                                . 
' class="radio"
                                onchange="smd_thumb_switch_pref(this, \'create_from\');" />'
                                
gTxt('smd_thumb_txp_create_from_full')
                        . 
'</label>'
                        
'<label>
                            <input type="radio"
                                name="smd_thumb_create_from"
                                value="thumb"'
                                
. (($txp_rf=='thumb') ? ' checked="checked"' '')
                                . 
' class="radio"
                                onchange="smd_thumb_switch_pref(this, \'create_from\');" />'
                                
gTxt('smd_thumb_txp_create_from_thumb')
                        .
'</label>';
                
$out[] = '</div></div>';

                if (
$pro_dflt) {
                    
$txp_c get_pref('smd_thumb_txp_create');
                    
$txp_d get_pref('smd_thumb_txp_delete');
                    
$out[] = '<div class="txp-form-field">';
                    
$out[] = '<div class="txp-form-field-label"><label>' gTxt('smd_thumb_txp_default_sync') . '</label></div>';
                    
$out[] = '<div class="txp-form-field-value">
                            <label>
                                <input type="checkbox"
                                    name="smd_thumb_txp_create"
                                    value="1"'
                                    
. (($txp_c) ? ' checked="checked"' '')
                                    . 
' class="checkbox"
                                    onchange="smd_thumb_switch_pref(this, \'txp_create\');" />'
                                    
gTxt('smd_thumb_create')
                            . 
'</label>'
                            
'<label>
                                <input type="checkbox"
                                    name="smd_thumb_txp_delete"
                                    value="1"'
                                    
. (($txp_d) ? ' checked="checked"' '')
                                    . 
' class="checkbox"
                                    onchange="smd_thumb_switch_pref(this, \'txp_delete\');" />'
                                    
gTxt('smd_thumb_delete')
                            . 
'</label>';
                    
$out[] = '</div></div>';
                }

                
$txp_ar get_pref('smd_thumb_auto_replace');
                
$out[] = '<div class="txp-form-field">';
                
$out[] = '<div class="txp-form-field-label"><label>' gTxt('smd_thumb_txp_auto_replace') . '</label></div>';
                
$out[] = '<div class="txp-form-field-value">
                        <label>
                            <input type="checkbox"
                                name="smd_thumb_auto_replace"
                                value="1"'
                                
. (($txp_ar) ? ' checked="checked"' '')
                                . 
' class="checkbox"
                                onchange="smd_thumb_switch_pref(this, \'auto_replace\');" />'
                                
gTxt('yes')
                        . 
'</label>';
                
$out[] = '</div></div>';
                
$out[] = '</div></form></div>';
            }
            
$out[] = '</div></div> ';
        }
    
// Action to show thumbnail profile list.
    
} else {
        
$editFocus = ($step === 'smd_thumb_profile_edit') ? 'jQuery("#smd_thumb_profile_edited input[name=\'smd_thumb_newname\']").focus();' '';

        echo 
script_js(<<<EOC
function smd_thumb_togglenew() {
    box = jQuery("#smd_thumb_profile_create");
    box.toggleClass("smd_hidden smd_thumb_new_profile");
    jQuery("input.smd_focus").focus();
    return false;
}
function smd_thumb_switch_active(name) {
    sendAsyncEvent(
    {
        event: textpattern.event,
        step: 'smd_thumb_switch_active',
        smd_thumb_profile: name
    }, smd_thumb_switch_active_done);
}
function smd_thumb_switch_active_done(data) {
    var smd_thumb_profile = jQuery('#smd_thumb_profile_'+jQuery(data).find('smd_thumb_profile').attr('value'));
    smd_thumb_profile.toggleClass('smd_inactive');
    if (smd_thumb_profile.hasClass('smd_inactive')) {
        smd_thumb_profile.find('input:checkbox').removeAttr('checked');
    } else {
        smd_thumb_profile.find('input:checkbox').attr('checked', 'checked');
    }
}

jQuery(function() {
    jQuery('.smd_thumb_heading_active').click(function() {
        jQuery('.smd_thumb_row input:checkbox').each(function() {
            smd_thumb_switch_active(jQuery(this).parent().attr('class'));
        });
    });
    
{$editFocus}
});
EOC
        );

        
$btnNew '<a href="#" onclick="return smd_thumb_togglenew();">'.gTxt('smd_thumb_new').'</a>';
        
$btnPref '<a class="smd_thumb_switcher" href="?event=image'.a.'step=smd_thumb_prefs'.a.'sort='.$sort.a.'dir='.$dir.a.'page='.$page.a.'search_method[]='.$search_method.a.'crit='.$crit.'">'.(($rights) ? gTxt('smd_thumb_btn_tools_prefs') : gTxt('smd_thumb_btn_tools')).'</a>';
        
$btnCancel fInput('submit''smd_thumb_cancel'gTxt('Cancel'));

        
$headings n.'<thead>'.tr(
            
n.column_head('name''name''image'false'asc').
            
column_head('thumb_width''width''image'false).
            
column_head('thumb_height''height''image'false).
            
column_head(gTxt('smd_thumb_quality'), 'quality''image'false).
            
column_head('keep_square_pixels''crop''image'false).
            
column_head(gTxt('smd_thumb_sharpen'), 'sharpen''image'false).
            
column_head('active''active''image'false'''''''smd_thumb_heading_active').
            
column_head('default''default''image'false).
            
column_head(gTxt('smd_thumb_actions'), 'actions''image'false)
        ).
'</thead>';

        
$out[] = '<div id="smd_thumb_profiles"><h3 class="txp-summary lever'.(get_pref('pane_smd_thumbnail_profiles_visible') ? ' expanded' '').'"><a href="#smd_thumbnail_profiles" class="smd_thumbnail_heading">'.gTxt('smd_thumb_profile_heading').'</a></h3><div id="smd_thumbnail_profiles" class="toggle" style="display:'.(get_pref('pane_smd_thumbnail_profiles_visible') ? 'block' 'none').'">';
        
$out[] = '<div class="txp-buttons">'.n.$btnPref.'</div>';

        
// Main list of profiles.
        
$out[] = '<form method="post" name="smd_thumb_profile_form" id="smd_thumb_profile_form" action="'.join_qs($qs).'">';
        
$out[] = startTable();
        
$out[] = $headings;

        if (
smd_thumb_table_exist()) {
            
$rs safe_rows('*'SMD_THUMB'1=1 ORDER BY name');
            
$pro_dflt get_pref('smd_thumb_default_profile'''1);

            
// Row for each currently-defined profile.
            
foreach ($rs as $row) {
                
$link_edt join_qs($qs).a.'step=smd_thumb_profile_edit'.a.'smd_thumb_name='.$row['name'];
                
$link_del join_qs($qs).a.'step=smd_thumb_profile_delete'.a.'smd_thumb_name='.$row['name'];
                
$btnEdt '<a href="'.$link_edt.'">[' gTxt('edit') . ']</a>';
                
$btnDel '<a href="'.$link_del.'" onclick="return confirm(\''.gTxt('smd_thumb_delete_confirm', array("{name}" => $row['name'])).'\');">[' gTxt('delete') . ']</a>';
                
$active = ($row['flags'] & SMD_THUMB_ACTIVE) ? 0;
                
$crop = ($row['flags'] & SMD_THUMB_CROP) ? 0;
                
$sharpen = ($row['flags'] & SMD_THUMB_SHARP) ? 0;

                if (
$step == 'smd_thumb_profile_edit' && $row['name'] == $smd_thumb_name) {
                    
$btnSave fInput('submit''smd_thumb_save'gTxt('Save'), 'publish');
                    
$out[] = tr(
                        
tda(hInput('smd_thumb_name'$row['name']).fInput('text''smd_thumb_newname'$row['name']), array('data-th' => gTxt('name')))
                        .
tda(fInput('text''smd_thumb_width'$row['width'], '''''''4'), array('data-th' => gTxt('thumb_width')))
                        .
tda(fInput('text''smd_thumb_height'$row['height'], '''''''4'), array('data-th' => gTxt('thumb_height')))
                        .
tda(fInput('text''smd_thumb_quality'$row['quality'], '''''''4'), array('data-th' => gTxt('smd_thumb_quality')))
                        .
tda(checkbox('smd_thumb_crop''1'$crop), array('data-th' => gTxt('keep_square_pixels')))
                        .
tda(checkbox('smd_thumb_sharpen''1'$sharpen), array('data-th' => gTxt('smd_thumb_sharpen')))
                        .
tda(checkbox('smd_thumb_active''1'$active), array('data-th' => gTxt('active'), 'class' => $row['name']))
                        .
tda(checkbox('smd_thumb_default''1', (($row['name'] == $pro_dflt) ? 0)), array('data-th' => gTxt('default')))
                        .
tda($btnSave.$btnCancel, array('data-th' => gTxt('smd_thumb_actions')))
                    , 
' id="smd_thumb_profile_edited"');
                } else {
                    
$out[] = tr(
                        
tda(href($row['name'], $link_edt), array('data-th' => gTxt('name'))).
                        
tda($row['width'], array('data-th' => gTxt('thumb_width'))).
                        
tda($row['height'], array('data-th' => gTxt('thumb_height'))).
                        
tda($row['quality'], array('data-th' => gTxt('smd_thumb_quality'))).
                        
tda(($crop) ? gTxt('yes') : gTxt('no'), array('data-th' => gTxt('keep_square_pixels'))).
                        
tda(($sharpen) ? gTxt('yes') : gTxt('no'), array('data-th' => gTxt('smd_thumb_sharpen'))).
                        
tda('<input type="checkbox" name="smd_thumb_active_'.$row['name'].'" value="1"'.(($active) ? ' checked="checked"' ''). ' class="checkbox" onchange="smd_thumb_switch_active(\''.$row['name'].'\');" />', array('data-th' => gTxt('active'), 'class' => $row['name'])).
                        
tda(($row['name'] == $pro_dflt) ? gTxt('yes') : gTxt('no'), array('data-th' => gTxt('default'))).
                        
tda($btnDel, array('data-th' => gTxt('smd_thumb_actions')))
                    , 
' id="smd_thumb_profile_'.$row['name'].'" class="smd_thumb_row' . (($active) ? '' ' smd_inactive').'"');
                }
            }

            
// New Profile row.
            
$out[]= '<tr id="smd_thumb_profile_create" class="smd_hidden">';
            
$out[] = tda(sInput('smd_thumb_profile_save').fInput('text''smd_thumb_add_newname', (($step === 'smd_thumb_profile_save') ? $smd_thumb_name ''), 'smd_focus'), array('data-th' => gTxt('name')))
                .
tda(fInput('text''smd_thumb_add_width', (($step === 'smd_thumb_profile_save') ? $width ''), ''''''INPUT_XSMALL), array('data-th' => gTxt('thumb_width')))
                .
tda(fInput('text''smd_thumb_add_height', (($step === 'smd_thumb_profile_save') ? $height ''), ''''''INPUT_XSMALL), array('data-th' => gTxt('thumb_height')))
                .
tda(fInput('text''smd_thumb_add_quality', (($step === 'smd_thumb_profile_save') ? $quality ''), ''''''INPUT_XSMALL), array('data-th' => gTxt('smd_thumb_quality')))
                .
tda(checkbox('smd_thumb_add_crop''1', (($step === 'smd_thumb_profile_save') ? $smd_thumb_crop 0)), array('data-th' => gTxt('keep_square_pixels')))
                .
tda(checkbox('smd_thumb_add_sharpen''1', (($step === 'smd_thumb_profile_save') ? $smd_thumb_sharpen 0)), array('data-th' => gTxt('smd_thumb_sharpen')))
                .
tda(checkbox('smd_thumb_add_active_new''1'1), array('data-th' => gTxt('active')))
                .
tda(checkbox('smd_thumb_add_default''1'0), array('data-th' => gTxt('default')))
                .
tda(fInput('submit''smd_thumb_add'gTxt('add'), 'publish').$btnCancel, array('data-th' => gTxt('smd_thumb_actions')));
            
$out[]= '</tr>';

        }

        
$out[] = endTable().n.$btnNew;
        
$out[] = '</form></div></div>';
    }

    return 
join(n$out);
}

/**
 * Useful function for other plugins to use to retrieve a list of current profiles.
 *
 * @param  integer $active Whether to only return active profiles (1) or all of them (0)
 * @param  string  $order  The order in which to return the list
 * @return array
 */
function smd_thumb_get_profiles($active 1$order 'name')
{
    
$allowedOrders = array('name''width''height','quality');
    
$order in_array($order$allowedOrders) ? $order 'name';
    
$where[] = '1=1';

    if (
$active) {
        
$where[] = 'flags & ' SMD_THUMB_ACTIVE;
    }

    
$rs safe_rows('*'SMD_THUMBjoin(' AND '$where) . ' ORDER BY '.$order);

    return 
$rs;
}

/**
 * Delete a thumbnail directory and its contents.
 *
 * @param  string $dir Directory to remove.
 */
function smd_thumb_rmdir($dir)
{
    if (
is_dir($dir)) {
        
$objects scandir($dir);

        foreach (
$objects as $object) {
            if (
$object != "." && $object != "..") {
                if (
filetype($dir.DS.$object) == "dir"smd_thumb_rmdir($dir.DS.$object); else unlink($dir.DS.$object);
            }
        }

        
reset($objects);
        
rmdir($dir);
    }
}

/**
 * Set the global image path if not already set.
 */
function smd_thumb_set_impath()
{
    global 
$path_to_site$img_dir;

    if (!
defined('IMPATH')) {
        
define('IMPATH'$path_to_site DS $img_dir DS);
    }
}

/**
 * Add thumbnail table if not already installed.
 *
 * Flags: Bit 0=Active / 1=Crop / 2=Sharpen
 */
function smd_thumb_table_install()
{
    global 
$DB;

    
$tableDef "
        name    VARCHAR(32) NOT NULL DEFAULT '',
        width   INT(4)      NOT NULL DEFAULT '0',
        height  INT(4)      NOT NULL DEFAULT '0',
        quality TINYINT(2)  NULL     DEFAULT '75',
        flags   TINYINT(2)  NOT NULL DEFAULT '0',
        PRIMARY KEY (name)
    "
;

    if (!
safe_create(SMD_THUMB$tableDef)) {
        echo 
mysqli_error($DB->link);
    }

    
// Backup the current thumb prefs.
    
$exists safe_row('*''txp_prefs'"name='smd_thumb_backup_w'");

    if (!
$exists) {
        
set_pref('smd_thumb_backup_w'get_pref('thumb_w'), 'smd_thumb'PREF_HIDDEN'text_input'0);
        
set_pref('smd_thumb_backup_h'get_pref('thumb_h'), 'smd_thumb'PREF_HIDDEN'text_input'1);
        
set_pref('smd_thumb_backup_c'get_pref('thumb_crop'), 'smd_thumb'PREF_HIDDEN'text_input'2);

        
// Erase the current thumb prefs
        
set_pref('thumb_w''''image'PREF_HIDDEN);
        
set_pref('thumb_h''''image'PREF_HIDDEN);
        
set_pref('thumb_crop''''image'PREF_HIDDEN);
    }
}

/**
 * Drop thumbnail table if in database.
 */
function smd_thumb_table_remove()
{
    global 
$DB;

    if (!
safe_drop(SMD_THUMB)) {
        echo 
mysqli_error($DB->link);
    }

    
// Restore the original thumb prefs.
    
$exists safe_row('*''txp_prefs'"name='smd_thumb_backup_w'");

    if (
$exists) {
        
set_pref('thumb_w'get_pref('smd_thumb_backup_w'), 'image'PREF_HIDDEN);
        
set_pref('thumb_h'get_pref('smd_thumb_backup_h'), 'image'PREF_HIDDEN);
        
set_pref('thumb_crop'get_pref('smd_thumb_backup_c'), 'image'PREF_HIDDEN);

    }

    
// Erase the backup thumb prefs.
    
safe_delete('txp_prefs',
        
"name IN('smd_thumb_backup_w', 'smd_thumb_backup_h', 'smd_thumb_backup_c', 'smd_thumb_default_profile', 'pane_smd_thumbnail_profiles_visible', 'pane_smd_thumbnails_visible')");
}

/**
 * Determine if the thumbnail table exists.
 *
 * @param  string $all [description]
 */
function smd_thumb_table_exist($all='')
{
    if (
$all) {
        
$tbls = array(SMD_THUMB => 5);
        
$out count($tbls);
        foreach (
$tbls as $tbl => $cols) {
            if (
gps('debug')) {
                echo 
"++ TABLE ".$tbl." HAS ".count(@safe_show('columns'$tbl))." COLUMNS; REQUIRES ".$cols." ++".br;
            }
            if (
count(@safe_show('columns'$tbl)) == $cols) {
                
$out--;
            }
        }
        return (
$out===0) ? 0;
    } else {
        if (
gps('debug')) {
            echo 
"++ TABLE ".SMD_THUMB." HAS ".count(@safe_show('columns'SMD_THUMB))." COLUMNS;";
        }
        return(@
safe_show('columns'SMD_THUMB));
    }
}

/**
 * AJAX function to store the state of the current UI elements (which pane is visible).
 */
function smd_thumbnail_save_pane_state()
{
    
$panes = array('smd_thumbnail_profiles''smd_thumbnails');
    
$pane gps('pane');

    if (
in_array($pane$panes)) {
        
set_pref("pane_{$pane}_visible", (gps('visible') == 'true' '1' '0'), 'smd_thumb'PREF_HIDDEN'yesnoradio'0PREF_PRIVATE);
        
send_xml_response();
    } else {
        
send_xml_response(array('http-status' => '400 Bad Request'));
    }
}

/**
 * Public tag: show a thumbnail.
 *
 * @param  array  $atts  Tag attributes
 * @param  string $thing Container
 * @return string        HTML
 */
function smd_thumbnail($atts$thing NULL)
{
    global 
$thisimage$img_dir;

    
extract(lAtts(array(
        
'type'       => get_pref('smd_thumb_default_profile'''),
        
'id'         => '',
        
'name'       => '',
        
'escape'     => 'html',
        
'wraptag'    => '',
        
'class'      => '',
        
'html_id'    => '',
        
'style'      => '',
        
'link'       => '',
        
'link_rel'   => '',
        
'poplink'    => 0,
        
'add_stamp'  => 0,
        
'width'      => '',
        
'height'     => '',
        
'force_size' => '',
        
'display'    => 'thumbnail'// thumbnail (full img tag) or url
        
'form'       => '',
    ), 
$atts));

    
$thing = (empty($form)) ? $thing fetch_form($form);

    if (
$name) {
        
$name doSlash($name);
        
$rs safe_row('*''txp_image'"name = '$name' limit 1");
    } elseif (
$id) {
        
$id = (int) $id;
        
$rs safe_row('*''txp_image'"id = $id limit 1");
    } elseif (
$thisimage) {
        
$id = (int) $thisimage['id'];
        
$rs $thisimage;
    } else {
        
trigger_error(gTxt('unknown_image'));
        return;
    }

    
smd_thumb_set_impath();

    if (
$rs) {
        
extract($rs);
        
$thumbinfo safe_row('*'SMD_THUMB"name='".doSlash($type)."'");

        if (
$thumbinfo) {
            
$dir sanitizeForUrl($thumbinfo['name']);
            
$path IMPATH $dir DS $id $ext;

            if (
file_exists($path)) {
                
// Drop out if all we need to display is the thumb's URL.
                
if ($display === 'url') {
                    return 
ihu $img_dir '/' $dir '/' $id $ext;
                }

                if (
$escape === 'html') {
                    
$alt htmlspecialchars($alt);
                    
$caption htmlspecialchars($caption);
                }

                
$meta['url'] = ihu $img_dir '/' $dir '/' $id $ext;
                
$meta['alt'] = $alt;
                
$meta['type'] = $type;
                
$meta['width'] = $width;
                
$meta['height'] = $height;
                
$force_size do_list($force_size);

                if (
in_array('width'$force_size)) {
                    
$meta['forcew'] = 1;
                }

                if (
in_array('height'$force_size)) {
                    
$meta['forceh'] = 1;
                }

                
// Negative logic since we want the stamp on by default for the admin side.
                
if ($add_stamp == 0) {
                    
$meta['stamp'] = 1;
                }

                if (
$name) {
                    
$meta['name'] = $name;
                }

                if (
$caption) {
                    
$meta['title'] = $caption;
                }
// $meta['title'] = gTxt('smd_thumb_image') . $rs['w'] . " &#215; " . $rs['h'] . sp .  gTxt('smd_thumb_profile') . $thumbinfo['width'] . " &#215; " . $thumbinfo['height'];

                
if ($category) {
                    
$meta['category'] = $category;
                    
$meta['category_title'] = fetch_category_title($category'image');
                }

                if (
$author) {
                    
$meta['author'] = $author;
                }

                if (
$date) {
                    
$meta['date'] = $date;
                }

                if (
$html_id && !$wraptag) {
                    
$meta['id'] = $html_id;
                }

                if (
$class && !$wraptag) {
                    
$meta['class'] = $class;
                } else {
                    
$class $type;
                }

                if (
$style) {
                    
$meta['style'] = $style;
                }

                
$out smd_thumb_img($thumbinfo$rs$meta$thing);

                if (
$link) {
                    
$out href($outimagesrcurl($id$ext), (!empty($link_rel) ? ' rel="' $link_rel '"' '') . ' title="' $caption '"');
                } elseif (
$poplink) {
                    
$out '<a href="' imagesrcurl($id$ext) . '"' .
                        
' onclick="window.open(this.href, \'popupwindow\', '.
                        
'\'width=' $w ', height=' $h ', scrollbars, resizable\'); return false;">' $out '</a>';
                }

                return (
$wraptag) ? doTag($out$wraptag$class''$html_id) : $out;
            }
        }
    }

    
trigger_error(gTxt('unknown_image'));
}

/**
 * Public tag: check thumbnail exists.
 *
 * @param  array  $atts  Tag attributes
 * @param  string $thing Container
 */
function smd_if_thumbnail($atts$thing)
{
    global 
$thisimage;

    
assert_image();

    
smd_thumb_set_impath();

    
extract(lAtts(array(
        
'type' => get_pref('smd_thumb_default_profile'),
    ), 
$atts));

    
$thumbinfo safe_row('*'SMD_THUMB"name='".doSlash($type)."'");
    
$ret false;

    if (
$thumbinfo) {
        
$path IMPATH sanitizeForUrl($thumbinfo['name']) . DS $thisimage['id'] . $thisimage['ext'];
        
$ret file_exists($path);
    }

    return 
parse(EvalElse($thing$ret));
}

/**
 * Public tag: display selected thumbnail meta data.
 *
 * @param  array  $atts  Tag attributes
 * @param  string $thing Container
 * @return string        HTML
 */
function smd_thumbnail_info($atts$thing NULL)
{
    global 
$smd_thumb_data;

    
extract(lAtts(array(
        
'item'    => '',
        
'wraptag' => '',
        
'break'   => '',
        
'class'   => '',
        
'debug'   => 0,
    ), 
$atts));

    
$tdata is_array($smd_thumb_data) ? $smd_thumb_data : array();

    if (
$debug) {
        echo 
'++ AVAILABLE INFO ++';
        
dmp($tdata);
    }

    
$items do_list($item);
    
$out = array();

    foreach (
$items as $it) {
        if (isset(
$tdata[$it])) {
            
$out[] = $tdata[$it];
        }
    }

    return 
doWrap($out$wraptag$break$class);
}