#!/usr/bin/perl -w
#
#  libzvbi test of teletext search
#
#  Copyright (C) 2007, 2020 Tom Zoerner
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

# Description:
#
#   Example for the use of class Video::ZVBI::search. The script captures
#   and caches teletext pages until the RETURN key is pressed, then
#   prompts for a search string. A search across teletext pages is
#   started, and the content of matching pages is printed on the terminal.

use strict;
use blib;
use Getopt::Long;
use Video::ZVBI qw(/^VBI_/);

my $opt_device = "/dev/dvb/adapter0/demux0";
my $opt_pid = 0;  # mandatory for DVB
my $opt_v4l2 = 0;
my $opt_verbose = 0;
my $opt_help = 0;

my $cr;

sub pg_handler {
   my($type, $ev, $lcr) = @_;

   printf STDERR "${lcr}Page %03x.%02x ",
           $ev->{pgno},
           $ev->{subno} & 0xFF;
}

sub progress {
   my ($pg,$search_cnt_ref) = @_;
   my ($page,$sub) = $pg->get_page_no();
   printf "${cr}Searching page %03X.%04x ", $page, $sub;
   $$search_cnt_ref++;
   return 1;
}

sub search {
   my ($vtdec) = @_;
   my $search_cnt = 0;
   my $match_cnt = 0;
   my $pat;

   print "\nEnter search pattern: ";
   chomp($pat = <STDIN>);
   if (defined($pat) && ($pat ne "")) {
      my $srch;
      my $pg;
      my $stat;
      my $any_sub = VBI_ANY_SUBNO;
      my $last_page;
      my $last_sub;

      #my $rand = [int(rand(1000))];
      #print "Search rand user data $rand->[0]\n";
      $srch = Video::ZVBI::search::new($vtdec, 0x100, $any_sub, $pat, 0, 0, \&progress, \$search_cnt);
      die "failed to initialize search: $!\n" unless $srch;

      while (($stat = $srch->next($pg, 1)) == VBI_SEARCH_SUCCESS) {
         # match found
         my ($page,$sub) = $pg->get_page_no();
         if (!defined($last_page) || !defined($last_sub) ||
             ($page != $last_page) || ($sub != $last_sub)) {

            printf "\nFound match: %03X.%04X\n", $page, $sub;
            my ($rows, $cols) = $pg->get_page_size();
            my $txt = $pg->get_page_text();
            for (my $row = 0; $row < $rows; $row++) {
               print substr($txt, $row*$cols, $cols) . "\n";
            }
            $last_page = $page;
            $last_sub = $sub;
            $match_cnt++;
         }
      }
      die "search \"$pat\": result code $stat\n" unless $stat == VBI_SEARCH_NOT_FOUND;
   }
   print "${cr}Found $match_cnt matches on $search_cnt searched pages for \"$pat\"\n";
}

sub main_func {
   my $opt_verbose = 0;
   my $err;
   my $cap;
   my $vtdec;
   my $exp;

   if ($opt_v4l2 || (($opt_pid == 0) && ($opt_device !~ /dvb/))) {
      my $opt_buf_count = 5;
      my $opt_services = VBI_SLICED_TELETEXT_B;
      my $opt_strict = 0;

      my $pxc = Video::ZVBI::proxy::create($opt_device, $0, 0, $err, $opt_verbose);
      if (defined $pxc) {
         # work-around for bug in proxy_new() prior to libzvbi 0.2.26 which closed STDIN
         open OLDSTDIN, "<&", \*STDIN;

         $cap = Video::ZVBI::capture::proxy_new($pxc, 5, 0, $opt_services, $opt_strict, $err);
         undef $pxc unless defined $cap;

         open STDIN, "<&OLDSTDIN"; # work-around cntd.
         close OLDSTDIN;
      }
      if (!defined $cap) {
         $cap = Video::ZVBI::capture::v4l2_new($opt_device, $opt_buf_count, $opt_services, $opt_strict, $err, $opt_verbose);
      }
      if (!defined $cap) {
         $cap = Video::ZVBI::capture::v4l_new($opt_device, 0, $opt_services, $opt_strict, $err, $opt_verbose);
      }
      if (!defined $cap) {
         $cap = Video::ZVBI::capture::bktr_new($opt_device, 0, $opt_services, $opt_strict, $err, $opt_verbose);
      }
   }
   else {
      warn "WARNING: DVB devices require --pid parameter\n" if $opt_pid <= 0;
      $cap = Video::ZVBI::capture::dvb_new2($opt_device, $opt_pid, $err, $opt_verbose);
   }
   die "Failed to open video device: $err\n" unless $cap;

   $cr = (-t STDERR) ? "\r" : "\n";

   $vtdec = Video::ZVBI::vt::decoder_new();
   die "failed to create teletext decoder: $!\n" unless defined $vtdec;

   $vtdec->event_handler_register(VBI_EVENT_TTX_PAGE, \&pg_handler, $cr); 

   print STDERR "Press RETURN to stop capture and enter a search pattern\n";

   while (1) {
      my $sliced;
      my $timestamp;
      my $n_lines;
      my $res;

      my $rin = '';
      vec($rin, fileno(STDIN), 1) = 1;
      if (select($rin, undef, undef, 0) > 0) {
         <STDIN>;
         search($vtdec);
      }

      $res = $cap->pull_sliced($sliced, $n_lines, $timestamp, 1000);
      warn "Capture error: $!\n" if $res < 0;

      if ($res > 0) {
         $vtdec->decode($sliced, $n_lines, $timestamp);
      }
   }

   exit(-1);
}

sub usage {
        print STDERR "\
libzvbi test of teletext search
Copyright (C) 2007, 2020 Tom Zoerner
This program is licensed under GPL 2 or later. NO WARRANTIES.\n\
Usage: $0 [OPTIONS]\n\
--device PATH     Specify the capture device\
--pid NNN         Specify the PES stream PID: Required for DVB\
--v4l2            Force device to be addressed via analog driver\
--verbose         Emit debug trace output\
--help            Print this message and exit\
";
  exit(1);
}

my %CmdOpts = (
        "device=s" =>  \$opt_device,
        "pid=i" =>     \$opt_pid,
        "v4l2" =>      \$opt_v4l2,
        "verbose" =>   \$opt_verbose,
        "help" =>      \$opt_help,
);
GetOptions(%CmdOpts) || usage();
usage() if $opt_help;
die "Options --v4l2 and --pid are mutually exclusive\n" if $opt_v4l2 && $opt_pid;

main_func();
