<commit_before><?php

/**
 * Copyright (c) 2011, Erasmus MC
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * Neither the name of Erasmus MC nor the
 *      names of its contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * @package    Gems
 * @subpackage Default
 * @author     <NAME> <<EMAIL>>
 * @copyright  Copyright (c) 2011 Erasmus MC
 * @license    New BSD License
 * @version    $Id$
 */

/**
 *
 * @package    Gems
 * @subpackage Default
 * @copyright  Copyright (c) 2011 Erasmus MC
 * @license    New BSD License
 * @since      Class available since version 1.1
 */
class Gems_Default_TokenPlanAction extends Gems_Controller_BrowseEditAction
{
    public $defaultPeriodEnd   = 2;
    public $defaultPeriodStart = -4;
    public $defaultPeriodType  = 'W';

    public $maxPeriod = 15;
    public $minPeriod = -15;

    public $sortKey = array(
        'gto_valid_from'          => SORT_ASC,
        'gto_mail_sent_date'      => SORT_ASC,
        'respondent_name'         => SORT_ASC,
        'gr2o_patient_nr'         => SORT_ASC,
        'calc_track_name'         => SORT_ASC,
        'calc_track_info'         => SORT_ASC,
        'calc_round_description'  => SORT_ASC,
        'gto_round_order'         => SORT_ASC,
        );

    protected function addBrowseTableColumns(MUtil_Model_TableBridge $bridge, MUtil_Model_ModelAbstract $model)
    {
        $HTML  = MUtil_Html::create();

        // Row with dates and patient data
        $bridge->gtr_track_type; // Data needed for buttons

        $bridge->setDefaultRowClass(MUtil_Html_TableElement::createAlternateRowClass('even', 'even', 'odd', 'odd'));
        $bridge->addColumn($this->getTokenLinks($bridge), ' ')->rowspan = 2; // Space needed because TableElement does not look at rowspans
        $bridge->addSortable('gto_valid_from');
        $bridge->addSortable('gto_valid_until');

        $bridge->addMultiSort('gr2o_patient_nr', $HTML->raw('; '), 'respondent_name');
        $bridge->addMultiSort('ggp_name', array($this->getActionLinks($bridge)));

        $bridge->tr();
        $bridge->addSortable('gto_mail_sent_date');
        $bridge->addSortable('gto_completion_time');

        if ($this->escort instanceof Gems_Project_Tracks_SingleTrackInterface) {
            $bridge->addMultiSort('calc_round_description', $HTML->raw('; '), 'gsu_survey_name');
        } else {
            $model->set('calc_track_info', 'tableDisplay', 'smallData');
            $model->set('calc_round_description', 'tableDisplay', 'smallData');
            $bridge->addMultiSort(
                'calc_track_name', 'calc_track_info',
                $bridge->calc_track_name->if($HTML->raw(' &raquo; ')),
                'gsu_survey_name', 'calc_round_description');
        }

        $bridge->addSortable('assigned_by');
    }

    /**
     * Creates a model for getModel(). Called only for each new $action.
     *
     * The parameters allow you to easily adapt the model to the current action. The $detailed
     * parameter was added, because the most common use of action is a split between detailed
     * and summarized actions.
     *
     * @param boolean $detailed True when the current action is not in $summarizedActions.
     * @param string $action The current action.
     * @return MUtil_Model_ModelAbstract
     */
    public function createModel($detailed, $action)
    {
        // MUtil_Model::$verbose = true;
        $model = $this->loader->getTracker()->getTokenModel();;
        $model->setCreate(false);

        $model->set('gr2o_patient_nr',       'label', $this->_('Respondent'));
        $model->set('gto_round_description', 'label', $this->_('Round / Details'));
        $model->set('gto_valid_from',        'label', $this->_('Valid from'));
        $model->set('gto_valid_until',       'label', $this->_('Valid until'));
        $model->set('gto_mail_sent_date',    'label', $this->_('Contact date'));
        $model->set('respondent_name',       'label', $this->_('Name'));

        return $model;
    }

    public function emailAction()
    {
        $model   = $this->getModel();

        // Set the request cache to use the search params from the index action
        $this->getCachedRequestData(true, 'index', true);

        // Load the filters
        $this->_applySearchParameters($model);

        $sort = array(
            'grs_email'          => SORT_ASC,
            'grs_first_name'     => SORT_ASC,
            'grs_surname_prefix' => SORT_ASC,
            'grs_last_name'      => SORT_ASC,
            'gto_valid_from'     => SORT_ASC,
            'gto_round_order'    => SORT_ASC,
            'gsu_survey_name'    => SORT_ASC,
        );

        if ($tokensData = $model->load(true, $sort)) {

            $form = new Gems_Email_MultiMailForm(array(
                'escort' => $this->escort,
                'templateOnly' => ! $this->escort->hasPrivilege('pr.token.mail.freetext'),
            ));
            $form->setTokensData($tokensData);

            $wasSent = $form->processRequest($this->getRequest());

            if ($form->hasMessages()) {
                $this->addMessage($form->getMessages());
            }

            if ($wasSent) {
                if ($this->afterSaveRoute(array())) {
                    return null;
                }

            } else {
                $table = new MUtil_Html_TableElement(array('class' => 'formTable'));
                $table->setAsFormLayout($form, true, true);
                $table['tbody'][0][0]->class = 'label';  // Is only one row with formLayout, so all in output fields get class.
                if ($links = $this->createMenuLinks(10)) {
                    $table->tf(); // Add empty cell, no label
                    $linksCell = $table->tf($links);
                }

                $this->html->h3(sprintf($this->_('Email %s'), $this->getTopic()));
                $this->html[] = $form;
            }


        } else {
            $this->addMessage($this->_('No tokens found.'));
        }
    }

    public function getActionLinks(MUtil_Model_TableBridge $bridge)
    {
        // Get the other token buttons
        if ($menuItems = $this->menu->findAll(array('controller' => array('track', 'survey'), 'action' => array('email', 'answer'), 'allowed' => true))) {
            $buttons = $menuItems->toActionLink($this->getRequest(), $bridge);
            $buttons->appendAttrib('class', 'rightFloat');
        } else {
            $buttons = null;
        }
        // Add the ask button
        if ($menuItem = $this->menu->find(array('controller' => 'ask', 'action' => 'take', 'allowed' => true))) {
            $askLink = $menuItem->toActionLink($this->getRequest(), $bridge);
            $askLink->appendAttrib('class', 'rightFloat');

            if ($buttons) {
                // Show previous link if show, otherwise show ask link
                $buttons = array($buttons, $askLink);
            } else {
                $buttons = $askLink;
            }
        }

        return $buttons;
    }

    /**
     * Returns tokenplan specific autosearch fields. Can be overruled.
     *
     * The form / html elements to search on. Elements can be grouped by inserting null's between them.
     * That creates a distinct group of elements
     *
     * @param MUtil_Model_ModelAbstract $model
     * @param array $data The $form field values (can be usefull, but no need to set them)
     * @return array Of Zend_Form_Element's or static tekst to add to the html or null for group breaks.
     */
    protected function getAutoSearchElements(MUtil_Model_ModelAbstract $model, array $data)
    {
        $elements = parent::getAutoSearchElements($model, $data);

        if ($elements) {
            $elements[] = null; // break into separate spans
        }

        // Create date range elements
        $min  = -91;
        $max  = 91;
        $size = max(strlen($min), strlen($max));

        $options = array(
            'gto_valid_from'      => $this->_('Valid from'),
            'gto_valid_until'     => $this->_('Valid until'),
            'gto_mail_sent_date'  => $this->_('E-Mailed on'),
            'gto_completion_time' => $this->_('Completion date'),
            );
        $element = $this->_createSelectElement('date_used', $options);
        $element->class = 'minimal';
        $element->setLabel($this->_('For date'));
        $elements[] = $element;

        $element = new Zend_Form_Element_Text('period_start', array('label' => $this->_('from'), 'size' => $size - 1, 'maxlength' => $size, 'class' => 'rightAlign'));
        $element->addValidator(new Zend_Validate_Int());
        $element->addValidator(new Zend_Validate_Between($min, $max));
        $elements[] = $element;

        $element = new Zend_Form_Element_Text('period_end', array('label' => $this->_('until'), 'size' => $size - 1, 'maxlength' => $size, 'class' => 'rightAlign'));
        $element->addValidator(new Zend_Validate_Int());
        $element->addValidator(new Zend_Validate_Between($min, $max));
        $elements[] = $element;

        $options = array(
            'D' => $this->_('days'),
            'W' => $this->_('weeks'),
            'M' => $this->_('months'),
            'Y' => $this->_('years'),
            );
        $element = $this->_createSelectElement('date_type', $options);
        $element->class = 'minimal';
        $elements[] = $element;

        $joptions['change'] = new Zend_Json_Expr('function(e, ui) {
jQuery("#period_start").attr("value", ui.values[0]);
jQuery("#period_end"  ).attr("value", ui.values[1]).trigger("keyup");

}');
        $joptions['min']    = $this->minPeriod;
        $joptions['max']    = $this->maxPeriod;
        $joptions['range']  = true;
        $joptions['values'] = new Zend_Json_Expr('[jQuery("#period_start").attr("value"), jQuery("#period_end").attr("value")]');

        $element = new ZendX_JQuery_Form_Element_Slider('period', array('class' => 'periodSlider', 'jQueryParams' => $joptions));
        $elements[] = $element;

        $elements[] = null; // break into separate spans


        return array_merge($elements, $this->getAutoSearchSelectElements());
    }

    protected function getAutoSearchSelectElements()
    {
        // intval() protects against any escaping tricks
        $orgId = intval($this->_getParam('gto_id_organization', $this->escort->getCurrentOrganization()));

        $elements[] = $this->_('Select:');
        $elements[] = MUtil_Html::create('br');

        // Add track selection
        if ($this->escort instanceof Gems_Project_Tracks_MultiTracksInterface) {
            $sql = "SELECT gtr_id_track, gtr_track_name FROM gems__tracks WHERE gtr_active=1 AND gtr_track_type='T' AND INSTR(gtr_organizations, '|$orgId|') > 0";
            $elements[] = $this->_createSelectElement('gto_id_track', $sql, $this->_('(all tracks)'));
        }

        $sql = "SELECT gro_round_description, gro_round_description
                    FROM gems__rounds INNER JOIN gems__tracks ON gro_id_track = gtr_id_track
                    WHERE gro_active=1 AND
                        LENGTH(gro_round_description) > 0 AND
                        gtr_active=1 AND
                        gtr_track_type='T' AND
                        INSTR(gtr_organizations, '|$orgId|') > 0";
        $elements[] = $this->_createSelectElement('gto_round_description', $sql, $this->_('(all rounds)'));

        $sql = "SELECT gsu_id_survey, gsu_survey_name
                    FROM gems__surveys INNER JOIN gems__rounds ON gsu_id_survey = gro_id_survey
                        INNER JOIN gems__tracks ON gro_id_track = gtr_id_track
                    WHERE gsu_active=1 AND
                        gro_active=1 AND
                        gtr_active=1 AND
                        gtr_track_type='T' AND
                        INSTR(gtr_organizations, '|$orgId|') > 0";
        /* TODO: use this when we can update this list using ajax
        if (isset($data['gsu_id_primary_group'])) {
            $sql .= $this->db->quoteInto(" AND gsu_id_primary_group = ?", $data['gsu_id_primary_group']);
        } // */
        $elements[] = $this->_createSelectElement('gto_id_survey', $sql, $this->_('(all surveys)'));

        $options = array(
            'all'       => $this->_('(all actions)'),
            'notmailed' => $this->_('Not emailed'),
            'tomail'    => $this->_('To email'),
            'toremind'  => $this->_('Needs reminder'),<commit_msg>Removed filter for surveys of other track types.<commit_after><?php

/**
 * Copyright (c) 2011, Erasmus MC
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * Neither the name of Erasmus MC nor the
 *      names of its contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * @package    Gems
 * @subpackage Default
 * @author     <NAME> <<EMAIL>>
 * @copyright  Copyright (c) 2011 Erasmus MC
 * @license    New BSD License
 * @version    $Id$
 */

/**
 *
 * @package    Gems
 * @subpackage Default
 * @copyright  Copyright (c) 2011 Erasmus MC
 * @license    New BSD License
 * @since      Class available since version 1.1
 */
class Gems_Default_TokenPlanAction extends Gems_Controller_BrowseEditAction
{
    public $defaultPeriodEnd   = 2;
    public $defaultPeriodStart = -4;
    public $defaultPeriodType  = 'W';

    public $maxPeriod = 15;
    public $minPeriod = -15;

    public $sortKey = array(
        'gto_valid_from'          => SORT_ASC,
        'gto_mail_sent_date'      => SORT_ASC,
        'respondent_name'         => SORT_ASC,
        'gr2o_patient_nr'         => SORT_ASC,
        'calc_track_name'         => SORT_ASC,
        'calc_track_info'         => SORT_ASC,
        'calc_round_description'  => SORT_ASC,
        'gto_round_order'         => SORT_ASC,
        );

    protected function addBrowseTableColumns(MUtil_Model_TableBridge $bridge, MUtil_Model_ModelAbstract $model)
    {
        $HTML  = MUtil_Html::create();

        // Row with dates and patient data
        $bridge->gtr_track_type; // Data needed for buttons

        $bridge->setDefaultRowClass(MUtil_Html_TableElement::createAlternateRowClass('even', 'even', 'odd', 'odd'));
        $bridge->addColumn($this->getTokenLinks($bridge), ' ')->rowspan = 2; // Space needed because TableElement does not look at rowspans
        $bridge->addSortable('gto_valid_from');
        $bridge->addSortable('gto_valid_until');

        $bridge->addMultiSort('gr2o_patient_nr', $HTML->raw('; '), 'respondent_name');
        $bridge->addMultiSort('ggp_name', array($this->getActionLinks($bridge)));

        $bridge->tr();
        $bridge->addSortable('gto_mail_sent_date');
        $bridge->addSortable('gto_completion_time');

        if ($this->escort instanceof Gems_Project_Tracks_SingleTrackInterface) {
            $bridge->addMultiSort('calc_round_description', $HTML->raw('; '), 'gsu_survey_name');
        } else {
            $model->set('calc_track_info', 'tableDisplay', 'smallData');
            $model->set('calc_round_description', 'tableDisplay', 'smallData');
            $bridge->addMultiSort(
                'calc_track_name', 'calc_track_info',
                $bridge->calc_track_name->if($HTML->raw(' &raquo; ')),
                'gsu_survey_name', 'calc_round_description');
        }

        $bridge->addSortable('assigned_by');
    }

    /**
     * Creates a model for getModel(). Called only for each new $action.
     *
     * The parameters allow you to easily adapt the model to the current action. The $detailed
     * parameter was added, because the most common use of action is a split between detailed
     * and summarized actions.
     *
     * @param boolean $detailed True when the current action is not in $summarizedActions.
     * @param string $action The current action.
     * @return MUtil_Model_ModelAbstract
     */
    public function createModel($detailed, $action)
    {
        // MUtil_Model::$verbose = true;
        $model = $this->loader->getTracker()->getTokenModel();;
        $model->setCreate(false);

        $model->set('gr2o_patient_nr',       'label', $this->_('Respondent'));
        $model->set('gto_round_description', 'label', $this->_('Round / Details'));
        $model->set('gto_valid_from',        'label', $this->_('Valid from'));
        $model->set('gto_valid_until',       'label', $this->_('Valid until'));
        $model->set('gto_mail_sent_date',    'label', $this->_('Contact date'));
        $model->set('respondent_name',       'label', $this->_('Name'));

        return $model;
    }

    public function emailAction()
    {
        $model   = $this->getModel();

        // Set the request cache to use the search params from the index action
        $this->getCachedRequestData(true, 'index', true);

        // Load the filters
        $this->_applySearchParameters($model);

        $sort = array(
            'grs_email'          => SORT_ASC,
            'grs_first_name'     => SORT_ASC,
            'grs_surname_prefix' => SORT_ASC,
            'grs_last_name'      => SORT_ASC,
            'gto_valid_from'     => SORT_ASC,
            'gto_round_order'    => SORT_ASC,
            'gsu_survey_name'    => SORT_ASC,
        );

        if ($tokensData = $model->load(true, $sort)) {

            $form = new Gems_Email_MultiMailForm(array(
                'escort' => $this->escort,
                'templateOnly' => ! $this->escort->hasPrivilege('pr.token.mail.freetext'),
            ));
            $form->setTokensData($tokensData);

            $wasSent = $form->processRequest($this->getRequest());

            if ($form->hasMessages()) {
                $this->addMessage($form->getMessages());
            }

            if ($wasSent) {
                if ($this->afterSaveRoute(array())) {
                    return null;
                }

            } else {
                $table = new MUtil_Html_TableElement(array('class' => 'formTable'));
                $table->setAsFormLayout($form, true, true);
                $table['tbody'][0][0]->class = 'label';  // Is only one row with formLayout, so all in output fields get class.
                if ($links = $this->createMenuLinks(10)) {
                    $table->tf(); // Add empty cell, no label
                    $linksCell = $table->tf($links);
                }

                $this->html->h3(sprintf($this->_('Email %s'), $this->getTopic()));
                $this->html[] = $form;
            }


        } else {
            $this->addMessage($this->_('No tokens found.'));
        }
    }

    public function getActionLinks(MUtil_Model_TableBridge $bridge)
    {
        // Get the other token buttons
        if ($menuItems = $this->menu->findAll(array('controller' => array('track', 'survey'), 'action' => array('email', 'answer'), 'allowed' => true))) {
            $buttons = $menuItems->toActionLink($this->getRequest(), $bridge);
            $buttons->appendAttrib('class', 'rightFloat');
        } else {
            $buttons = null;
        }
        // Add the ask button
        if ($menuItem = $this->menu->find(array('controller' => 'ask', 'action' => 'take', 'allowed' => true))) {
            $askLink = $menuItem->toActionLink($this->getRequest(), $bridge);
            $askLink->appendAttrib('class', 'rightFloat');

            if ($buttons) {
                // Show previous link if show, otherwise show ask link
                $buttons = array($buttons, $askLink);
            } else {
                $buttons = $askLink;
            }
        }

        return $buttons;
    }

    /**
     * Returns tokenplan specific autosearch fields. Can be overruled.
     *
     * The form / html elements to search on. Elements can be grouped by inserting null's between them.
     * That creates a distinct group of elements
     *
     * @param MUtil_Model_ModelAbstract $model
     * @param array $data The $form field values (can be usefull, but no need to set them)
     * @return array Of Zend_Form_Element's or static tekst to add to the html or null for group breaks.
     */
    protected function getAutoSearchElements(MUtil_Model_ModelAbstract $model, array $data)
    {
        $elements = parent::getAutoSearchElements($model, $data);

        if ($elements) {
            $elements[] = null; // break into separate spans
        }

        // Create date range elements
        $min  = -91;
        $max  = 91;
        $size = max(strlen($min), strlen($max));

        $options = array(
            'gto_valid_from'      => $this->_('Valid from'),
            'gto_valid_until'     => $this->_('Valid until'),
            'gto_mail_sent_date'  => $this->_('E-Mailed on'),
            'gto_completion_time' => $this->_('Completion date'),
            );
        $element = $this->_createSelectElement('date_used', $options);
        $element->class = 'minimal';
        $element->setLabel($this->_('For date'));
        $elements[] = $element;

        $element = new Zend_Form_Element_Text('period_start', array('label' => $this->_('from'), 'size' => $size - 1, 'maxlength' => $size, 'class' => 'rightAlign'));
        $element->addValidator(new Zend_Validate_Int());
        $element->addValidator(new Zend_Validate_Between($min, $max));
        $elements[] = $element;

        $element = new Zend_Form_Element_Text('period_end', array('label' => $this->_('until'), 'size' => $size - 1, 'maxlength' => $size, 'class' => 'rightAlign'));
        $element->addValidator(new Zend_Validate_Int());
        $element->addValidator(new Zend_Validate_Between($min, $max));
        $elements[] = $element;

        $options = array(
            'D' => $this->_('days'),
            'W' => $this->_('weeks'),
            'M' => $this->_('months'),
            'Y' => $this->_('years'),
            );
        $element = $this->_createSelectElement('date_type', $options);
        $element->class = 'minimal';
        $elements[] = $element;

        $joptions['change'] = new Zend_Json_Expr('function(e, ui) {
jQuery("#period_start").attr("value", ui.values[0]);
jQuery("#period_end"  ).attr("value", ui.values[1]).trigger("keyup");

}');
        $joptions['min']    = $this->minPeriod;
        $joptions['max']    = $this->maxPeriod;
        $joptions['range']  = true;
        $joptions['values'] = new Zend_Json_Expr('[jQuery("#period_start").attr("value"), jQuery("#period_end").attr("value")]');

        $element = new ZendX_JQuery_Form_Element_Slider('period', array('class' => 'periodSlider', 'jQueryParams' => $joptions));
        $elements[] = $element;

        $elements[] = null; // break into separate spans


        return array_merge($elements, $this->getAutoSearchSelectElements());
    }

    protected function getAutoSearchSelectElements()
    {
        // intval() protects against any escaping tricks
        $orgId = intval($this->_getParam('gto_id_organization', $this->escort->getCurrentOrganization()));

        $elements[] = $this->_('Select:');
        $elements[] = MUtil_Html::create('br');

        // Add track selection
        if ($this->escort instanceof Gems_Project_Tracks_MultiTracksInterface) {
            $sql = "SELECT gtr_id_track, gtr_track_name FROM gems__tracks WHERE gtr_active=1 AND gtr_track_type='T' AND INSTR(gtr_organizations, '|$orgId|') > 0";
            $elements[] = $this->_createSelectElement('gto_id_track', $sql, $this->_('(all tracks)'));
        }

        $sql = "SELECT gro_round_description, gro_round_description
                    FROM gems__rounds INNER JOIN gems__tracks ON gro_id_track = gtr_id_track
                    WHERE gro_active=1 AND
                        LENGTH(gro_round_description) > 0 AND
                        gtr_active=1 AND
                        gtr_track_type='T' AND
                        INSTR(gtr_organizations, '|$orgId|') > 0";
        $elements[] = $this->_createSelectElement('gto_round_description', $sql, $this->_('(all rounds)'));

        $sql = "SELECT gsu_id_survey, gsu_survey_name
                    FROM gems__surveys INNER JOIN gems__rounds ON gsu_id_survey = gro_id_survey
                        INNER JOIN gems__tracks ON gro_id_track = gtr_id_track
                    WHERE gsu_active=1 AND
                        gro_active=1 AND
                        gtr_active=1 AND
                        INSTR(gtr_organizations, '|$orgId|') > 0";
        /* TODO: use this when we can update this list using ajax
        if (isset($data['gsu_id_primary_group'])) {
            $sql .= $this->db->quoteInto(" AND gsu_id_primary_group = ?", $data['gsu_id_primary_group']);
        } // */
        $elements[] = $this->_createSelectElement('gto_id_survey', $sql, $this->_('(all surveys)'));

        $options = array(
            'all'       => $this->_('(all actions)'),
            'notmailed' => $this->_('Not emailed'),
            'tomail'    => $this->_('To email'),
            'toremind'  => $this->_('Needs reminder'),
{'fraction_non_alphanumeric': 0.13726627047398174, 'fraction_numerical': 0.003406290766777794, 'mean_word_length': 2.498161997718342, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 341, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '513097', 'n_tokens_mistral': 8120, 'n_tokens_neox': 7735, 'n_words': 1966}