protected function action_stats()
 {
     $g = new xml_gen();
     $s = new morg_stats($this->dbh);
     $this->head('Statistics', './');
     // general stats
     echo $g->h4('General Statistics');
     $t = new Table(2, "id='stats'", null, 'left;right;left');
     $t->data('Total number of tracks:');
     $t->data(number_format($s->number_of_tracks()));
     // filesize stats
     $t->row_attr("class='add_space'");
     $t->data('Total size of tracks:');
     $t->data($this->display_bytes_human_readable($s->size_of_tracks()));
     $t->data('Average track size:');
     $t->data($this->display_bytes_human_readable($s->average_size_of_tracks()));
     // playing time stats
     $t->row_attr("class='add_space'");
     $t->data('Total track length:');
     $t->data($this->display_seconds_as_days($s->length_of_tracks()));
     $t->data('Total track length:');
     $t->data($this->display_seconds_human_readable($s->length_of_tracks()));
     $t->data('Average track length:');
     $t->data($this->display_seconds_human_readable($s->average_length_of_tracks()));
     $t->done();
     // file formats stats
     echo $g->h4('File Formats');
     $t = new Table(5, "id='stats2'", null, 'left;right;right;right;right');
     foreach ($s->format_names_array() as $format_name_id => $format_name) {
         $t->data($format_name);
         $t->data(number_format($s->number_of_tracks($format_name_id)) . ' files');
         $t->data($this->display_bytes_human_readable($s->size_of_tracks($format_name_id)));
         $t->data($this->display_seconds_human_readable($s->length_of_tracks($format_name_id)));
         $t->data(number_format($s->average_bit_rate($format_name_id) / 1000) . ' kbps');
     }
     $t->done();
     // reports
     echo $g->h4('Reports');
     $t = new Table(3, "id='stats3'");
     $t->data('File Formats/Encoders');
     $t->data();
     $t->data('[' . $g->a('./?action=stats_formats', 'view', "title='View report'") . ']');
     $t->data('Fields');
     $t->data();
     $t->data('[' . $g->a('./?action=stats_fields', 'view', "title='View report'") . ']');
     $t->data('Duplicate Files (md5_data)');
     $t->data();
     $t->data('[' . $g->a('./?action=stats_duplicates1&field=artist', 'view', "title='View report'") . ']');
     $t->data('Duplicate Files (metadata)');
     $t->data();
     $t->data('[' . $g->a('./?action=stats_duplicates2&field=artist', 'view', "title='View report'") . ']');
     $t->done();
     // problems
     echo $g->h4('Problems');
     $t = new Table(3, "id='stats4'");
     $t->data('Files not tagged');
     $t->data(number_format($s->count_tagless()) . ' items');
     $t->data('[' . $g->a('./?action=stats_tagless', 'view', "title='View report'") . ']');
     // missing key fields
     foreach ($this->key_fields() as $field) {
         $t->data('Files missing ' . $field . ' field');
         $t->data(number_format($s->count_missing_key_field($field)) . ' items');
         $t->data('[' . $g->a('./?action=stats_key_field&field=' . $field, 'view', "title='View report'") . ']');
     }
     $t->data('Files missing replaygain info');
     $t->data(number_format($s->count_missing_replaygain()) . ' items');
     $t->data('[' . $g->a('./?action=stats_replaygain', 'view', "title='View report'") . ']');
     $t->data('Directories without artwork');
     $t->data(number_format($s->count_artless_directories()) . ' items');
     $t->data('[' . $g->a('./?action=stats_artless_dirs', 'view', "title='View report'") . ']');
     $t->done();
     $this->foot();
 }
function FormatEncoderOptionsReport()
{
    echo xml_gen::h3('Format/Encoder/Options Distribution');
    global $dbh;
    $t = new Table(11, 'class=table', null, 'left;left;left;;right;left;right;left;right;left;right;left');
    // NOTE: Left joining because encoder_options might not be set....
    $dbh->query("select N.name as format_name, E.name as encoder_version, O.name as encoder_options, count(X.id) as counter, sum(X.filesize)/1024/1024/1024 as sumsize, sum(X.playtime)/3600 as sumplay, sum(X.avg_bit_rate)/1000 as sumbitr from getid3_file X left join getid3_encoder_options O on O.id = X.encoder_options_id, getid3_format_name N, getid3_encoder_version E where N.id = X.format_name_id and E.id = X.encoder_version_id  group by N.id,E.id,O.id order by N.name, E.name");
    while ($dbh->next_record()) {
        $t->data($dbh->f('format_name') . xml_gen::space(3));
        $t->data($dbh->f('encoder_version') . xml_gen::space(3));
        $t->data($dbh->f('encoder_options') . xml_gen::space(3));
        $t->data(number_format($dbh->f('counter')));
        $t->data('files' . xml_gen::space(3));
        $t->data(number_format($dbh->f('sumsize')));
        $t->data('Gb' . xml_gen::space(3));
        $t->data(number_format($dbh->f('sumplay'), 1));
        $t->data('hours' . xml_gen::space(3));
        $t->data(number_format($dbh->f('sumbitr') / $dbh->f('counter')));
        $t->data('kbps (avg)');
    }
    $t->done();
}
 function dump(&$var)
 {
     if (!is_array($var)) {
         if (is_int($var)) {
             return number_format($var);
         }
         if (is_bool($var)) {
             return $var ? 'true' : 'false';
         }
         return $var;
     } else {
         $t = new Table(3, "class=dump");
         foreach ($var as $key => $value) {
             $t->data($key);
             // Show cover
             if ($key == 'data' && isset($var['image_mime']) && isset($var['dataoffset'])) {
                 $t->data('embedded image');
                 $t->data("<img src='demo.browse.php?filename=" . urlencode($_GET['filename']) . "&show_img=" . md5($value) . "'>");
                 break;
             }
             $type = gettype($value);
             $t->data($type);
             if ($type == 'string') {
                 echo '(' . strlen($value) . ')';
             } elseif ($type == 'array') {
                 echo '(' . sizeof($value) . ')';
             }
             $t->data(null, 'class=dump_' . $type);
             echo dump($value);
         }
         $t->done();
     }
 }