package XXV::MODULES::AUTOTIMER;

use strict;

use Tools;
use Event::File;
use Locale::gettext;


# This module method must exist for XXV
# ------------------
sub module {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $args = {
        Name => 'AUTOTIMER',
        Description => gettext('This module search for epg entries with an user defined text and create new timer.'),
        Version => '0.45',
        Date => '12.09.2005',
        Author => 'xpix',
        Status => sub{ $obj->status(@_) },
        Preferences => {
            active => {
                description => gettext('Activate this service'),
                default     => 'y',
                type        => 'confirm',
                required    => gettext('This is required!'),
            },
            interval => {
                description => gettext('The interval in seconds to search for timers'),
                default     => 300,
                type        => 'integer',
                required    => gettext('This is required!'),
            },
            exclude => {
                description => gettext('Exclude channel list for autotimer.'),
                type        => 'list',
                options     => 'multi',
                default     => '',
                choices     => sub{
                    my $mod = main::getModule('CHANNELS');
                    return $mod->ChannelArray('Name');
                },
                check   => sub{
                    my $value = shift || return;
                    if(ref $value eq 'ARRAY') {
                        return join(',', @$value);
                    } else {
                        return $value;
                    }
                },
            },
        },
        Commands => {
            astatus => {
                description => gettext('Status from autotimers'),
                short       => 'as',
                callback    => sub{ $obj->status(@_) },
                DenyClass   => 'alist',
            },
            anew => {
                description => gettext("Create a new autotimer"),
                short       => 'an',
                callback    => sub{ $obj->autotimerCreate(@_) },
                Level       => 'user',
                DenyClass   => 'aedit',
            },
            adelete => {
                description => gettext("Delete a autotimer 'aid'"),
                short       => 'ad',
                callback    => sub{ $obj->autotimerDelete(@_) },
                Level       => 'user',
                DenyClass   => 'aedit',
            },
            aedit => {
                description => gettext("Edit a autotimer 'aid'"),
                short       => 'ae',
                callback    => sub{ $obj->autotimerEdit(@_) },
                Level       => 'user',
                DenyClass   => 'aedit',
            },
            alist => {
                description => gettext("List the autotimer 'aid'"),
                short       => 'al',
                callback    => sub{ $obj->list(@_) },
                DenyClass   => 'alist',
            },
            aupdate => {
                description => gettext("Start the autotimer process"),
                short       => 'au',
                callback    => sub{ $obj->autotimer(@_) },
                Level       => 'user',
                DenyClass   => 'aedit',
            },
            aimport => {
                description => gettext("Import autotimer from vdradmind.at"),
                short       => 'ai',
                callback    => sub{ $obj->autotimerimport(@_) },
                Level       => 'user',
                DenyClass   => 'aedit',
            },
            aexport => {
                description => gettext("Export autotimer to vdradmind.at"),
                short       => 'ax',
                callback    => sub{ $obj->autotimerexport(@_) },
                Level       => 'user',
                DenyClass   => 'aedit',
            },
            atoggle => {
                description => gettext("Toggle autotimer on or off 'aid'"),
                short       => 'at',
                callback    => sub{ $obj->autotimerToggle(@_) },
                Level       => 'user',
                DenyClass   => 'aedit',
            },
        },
    };
    return $args;
}

# ------------------
sub status {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $watcher = shift;
    my $console = shift;
    my $lastReportTime = shift || 0;

    my $sql = qq|
SELECT
    t.Id as __Id,
    t.File,
    t.Status as __Status,
    c.Name as Channel,
    c.Pos as __Pos,
    DATE_FORMAT(t.Day, '%e.%c.%Y') as Day,
    t.Start,
    t.Stop,
    t.Priority,
    UNIX_TIMESTAMP(t.NextStartTime) as __Day,
    t.Collision as __Collision,
    t.NextEpgId as __NextEpgId,
    t.AutotimerId as __AutotimerId
FROM
    TIMERS as t,
    CHANNELS as c
WHERE
    t.ChannelID = c.Id
    and UNIX_TIMESTAMP(t.addtime) > $lastReportTime
    and t.AutotimerId > 0
ORDER BY
    t.NextStartTime|;

    my $fields = fields($obj->{dbh}, $sql);
    my $erg = $obj->{dbh}->selectall_arrayref($sql);
    for(@$erg) {
        $_->[6] = substr(sprintf('%04d', $_->[6]),0,2).':'.substr(sprintf('%04d', $_->[6]),2,2);
        $_->[7] = substr(sprintf('%04d', $_->[7]),0,2).':'.substr(sprintf('%04d', $_->[7]),2,2);
    }

    unshift(@$erg, $fields);
    return {
        message => sprintf(gettext('Autotimer has %d new timer programmed, since last report at %s'),
            (scalar @$erg - 1), scalar localtime($lastReportTime)),
        table   => $erg,
    };
}


# ------------------
sub new {
# ------------------
	my($class, %attr) = @_;
	my $self = {};
	bless($self, $class);

    # paths
    $self->{paths} = delete $attr{'-paths'};

	# who am I
    $self->{MOD} = $self->module;

    # all configvalues to $self without parents (important for ConfigModule)
    map {
        $self->{$_} = $attr{'-config'}->{$self->{MOD}->{Name}}->{$_} || $self->{MOD}->{Preferences}->{$_}->{default}
    } keys %{$self->{MOD}->{Preferences}};

    # read the DB Handle
    $self->{dbh} = delete $attr{'-dbh'};

    # file
    $self->{file} = $self->{config}->{file};

    # The Initprocess
    my $erg = $self->init or return error('Problem to initialze Module');

    # Interval to read timers and put to DB
    Event->timer(
        interval => $self->{interval},
        prio => 6,  # -1 very hard ... 6 very low
        cb => sub{
            lg 'Start interval autotimer to find new events!';
            $self->autotimer();
        },
    ) if($self->{active} eq 'y');

	return $self;
}

# ------------------
sub init {
# ------------------
    my $obj = shift || return error ('No Object!' );

    # Old Version
    if(tableExists($obj->{dbh}, 'AUTOTIMER')) {
        # Nicht loeschen da das Userdata sind
		my $fields = fields($obj->{dbh}, 'select * from AUTOTIMER');

        warn "Upps, you have a incompatible Database. Please use the script contrib/upgrade-xxv.sh to convert the database!"
            unless(scalar @$fields == 16);
    }

    # Look for table or create this table
    my $version = main::getVersion;
    $obj->{dbh}->do(qq|
      CREATE TABLE IF NOT EXISTS AUTOTIMER (
          Id int(16) unsigned auto_increment NOT NULL,
          Activ enum('y', 'n') default 'y',
          Done  enum('y', 'n') default 'y',
          Search varchar(100) NOT NULL default '',
          InFields set('title', 'subtitle', 'description' ) NOT NULL,
          Channels text default '',
          Start char(4) default '0000',
          Stop  char(4) default '0000',
          MinLength int(11) default '0',
          Priority int(11),
          Lifetime int(11),
          Dir varchar(100),
          VPS enum('y', 'n') default 'n',
          prevminutes int(11),
          afterminutes int(11),
          Weekdays set('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'),
          PRIMARY KEY  (Id)
        ) COMMENT = '$version'
    |);
}

# ------------------
sub autotimer {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $watcher = shift;
    my $console = shift;
    my $autotimerid = shift;

    # Get Autotimer
    my $sql = sprintf('select * from AUTOTIMER where Activ = "y" %s order by Id', ($autotimerid ? "AND Id = $autotimerid" : ''));
    my $att = $obj->{dbh}->selectall_hashref($sql, 'Id');

    my $waiter;
    if(ref $console && !$autotimerid && $console->typ eq 'HTML') {
        my $zaehler = scalar keys %$att;
        $waiter = $console->wait(gettext("Look for autotimer ..."), 0, ++$zaehler, 'yes');
    }

    my $l = 0; # Lines for Waiter
    my $C = 0; # Total of created and modifed timers
    my $M = 0;
    my $log;

    # Get Timersmodule
    my $timermod = main::getModule('TIMERS');
    foreach my $id (sort keys %$att) {
        my $a = $att->{$id};

        $waiter->next(++$l, undef, sprintf(gettext("Look for autotimer with ID(%d) with search '%s'"), $id, $a->{Search}))
          if(ref $waiter);

        if(ref $console && $autotimerid) {
            $console->message(' ') if($console->{TYP} eq 'HTML');
            $console->message(sprintf(gettext("Look for autotimer with ID(%d) with search '%s'"), $id, $a->{Search}));
        }

    	my $search = buildsearch($a->{InFields}, $a->{Search});

        # Start and Stop
        if($a->{Start} and $a->{Stop}) {
            if($a->{Start} > $a->{Stop}) {
                $search .= "\n AND ((DATE_FORMAT(e.starttime, '%H%i') > $a->{Start} AND DATE_FORMAT(e.starttime, '%H%i') < 2359) OR (DATE_FORMAT(e.starttime, '%H%i') >= 0 and DATE_FORMAT(e.starttime, '%H%i') < $a->{Stop}))";
            } else {
                $search .= "\n AND (DATE_FORMAT(e.starttime, '%H%i') > $a->{Start} AND DATE_FORMAT(e.starttime, '%H%i') < $a->{Stop})";
        }
        }

        # Min Length
        if(exists $a->{MinLength} and $a->{MinLength}) {
            $search .= sprintf(" AND e.duration >= %d ", $a->{MinLength} * 60);
        }

        # Channels
        if($a->{Channels} and my @channelids = split(',', $a->{Channels})) {
            @channelids = map {$_ = "'$_'"} @channelids;
            $search = sprintf(' %s  AND channel_id in (%s)', $search, join(',', @channelids));
        }

        # Weekdays
        if($a->{Weekdays} and my @weekdays = split(',', $a->{Weekdays})) {
            @weekdays = map {$_ = "'$_'"} @weekdays;
            $search = sprintf(' %s  AND DATE_FORMAT(e.starttime, \'%a\') in (%s)', $search, join(',', @weekdays));
        }

        # Exclude Channels
        if($obj->{exclude} and my @channelids = split(',', $obj->{exclude})) {
            @channelids = map {$_ = "'$_'"} @channelids;
            $search = sprintf(' %s  AND c.POS not in (%s)', $search, join(',', @channelids));
        }

    	# Custom time range
    	my $after = 0;
    	my $prev = 0;
    	if($a->{VPS} ne 'y') {
    		if(defined $a->{prevminutes}) {
    			$prev = $a->{prevminutes} * 60;
    		} else {
    			$prev = $timermod->{prevminutes} * 60;
    		}
    		if(defined $a->{afterminutes}) {
    			$after = $a->{afterminutes} * 60;
    		} else {
    			$after = $timermod->{afterminutes} * 60;
    		}
    	}

        # Search for timer
        my $sql = qq|
SELECT
    e.eventid as eventid,
    e.channel_id as ChannelID,
    c.Name as Channel,
    c.POS as POS,
    e.title as Title,
    e.subtitle as Subtitle,
    e.description as Summary,
    DATE_FORMAT(FROM_UNIXTIME(UNIX_TIMESTAMP(e.starttime) - $prev ), '%d') as Day,
    DATE_FORMAT(FROM_UNIXTIME(UNIX_TIMESTAMP(e.starttime) - $prev ), '%H%i') as Start,
    DATE_FORMAT(FROM_UNIXTIME(UNIX_TIMESTAMP(e.starttime) + e.duration + $after ), '%H%i') as Stop
FROM
    EPG as e,
    CHANNELS as c
WHERE
    ( $search )
    AND ( e.channel_id = c.Id )|;

#dumper $sql;
        my $data = $obj->{dbh}->selectall_hashref($sql, 'eventid') || next;

        if(ref $console && $autotimerid) {
            $console->message(sprintf(gettext("Found %d entries for '%s' in EPG DB."), scalar keys %$data, $a->{Search}));
            map {
                $console->table($data->{$_});
            } sort keys %{$data}
        }

        # Every found and save this as timer
        my $c = 0;
        my $m = 0;
        foreach my $Id (sort keys %$data) {
            $data->{$Id}->{Activ} = 'y';
			$data->{$Id}->{VPS} = $a->{VPS};
            $data->{$Id}->{Priority} = $a->{Priority};
            $data->{$Id}->{Lifetime} = $a->{Lifetime};

            if ($a->{Dir}) {
            	my $title = $a->{Dir};
                if($title =~ /.*%.*%.*/sig) { # Extended EPG, ersetze TAGs aus Summary im Titel
			 	   my %at_details;
		                $at_details{'title'}            = $data->{$Id}->{Title};
		                $at_details{'subtitle'}         = $data->{$Id}->{Subtitle} ? $data->{$Id}->{Subtitle} : $data->{$Id}->{Start};
		                $at_details{'date'}             = $data->{$Id}->{Day};
		                $at_details{'regie'}            = $1 if $data->{$Id}->{Summary} =~ m/\|Director: (.*?)\|/;
		                $at_details{'category'}         = $1 if $data->{$Id}->{Summary} =~ m/\|Category: (.*?)\|/;
		                $at_details{'genre'}            = $1 if $data->{$Id}->{Summary} =~ m/\|Genre: (.*?)\|/;
		                $at_details{'year'}             = $1 if $data->{$Id}->{Summary} =~ m/\|Year: (.*?)\|/;
		                $at_details{'country'}          = $1 if $data->{$Id}->{Summary} =~ m/\|Country: (.*?)\|/;
		                $at_details{'originaltitle'}    = $1 if $data->{$Id}->{Summary} =~ m/\|Originaltitle: (.*?)\|/;
		                $at_details{'fsk'}              = $1 if $data->{$Id}->{Summary} =~ m/\|FSK: (.*?)\|/;
		                $at_details{'episode'}          = $1 if $data->{$Id}->{Summary} =~ m/\|Episode: (.*?)\|/;
		                $at_details{'rating'}           = $1 if $data->{$Id}->{Summary} =~ m/\|Rating: (.*?)\|/;
		                $title =~ s/%([\w_-]+)%/$at_details{lc($1)}/sieg;
						$data->{$Id}->{File} = $title;
                } else { # Classic mode DIR~TITLE~SUBTILE
    				$data->{$Id}->{File} = sprintf('%s~%s~%s', $a->{Dir}, $data->{$Id}->{Title},$data->{$Id}->{Subtitle});
                }
			} else {
				$data->{$Id}->{File} = sprintf('%s~%s', $data->{$Id}->{Title},$data->{$Id}->{Subtitle});
		    }

		    # sind irgendweche Tags verwendet worden, die leer waren und die doppelte Verzeichnisse erzeugten?
		    $data->{$Id}->{File} =~s#~+#~#g;
		    $data->{$Id}->{File} =~s#^~##g;
		    $data->{$Id}->{File} =~s#~$##g;

            my $sql;
            my $nexttime = $timermod->getNextTime( $data->{$Id}->{Day} , $data->{$Id}->{Start}, $data->{$Id}->{Stop} )
                  or warn(sprintf("Can not get the nexttime for this autotimer: %d", $Id)), next;

            # Add anchor for reidentify timer
            my $aidcomment = sprintf('#~AT[%d]', $id);
            $data->{$Id}->{Summary} .= $aidcomment
                if($aidcomment);

            my $file = $data->{$Id}->{File};
            $file =~ s/\'/\\\'/sg;
            $file =~ s/%/\\%/sg;

            my $summary = $data->{$Id}->{Summary};
            $summary =~ s/\'/\\\'/sg;
            $summary =~ s/%/\\%/sg;

            # Avoid Timer already defined (the timer with the same data again do not put on)
            $sql = "select count(*) as cc from TIMERS where
                        ChannelID = '$data->{$Id}->{ChannelID}'
                        and UNIX_TIMESTAMP(NextStartTime) = '$nexttime->{start}'
                        and UNIX_TIMESTAMP(NextStopTime)  = '$nexttime->{stop}'
                        and Priority = '$data->{$Id}->{Priority}'
                        and Lifetime = '$data->{$Id}->{Lifetime}'
                        and (( Status & 1 = '0' )
                        or  (File = '$file'
                        and Summary = '$summary'))";
            my $again = $obj->{dbh}->selectrow_hashref($sql);
            next
                if( ref $again and $again->{cc} );

            # Adjust timers set by the autotimer
            my $timerID = 0;
            $sql = "select ID from TIMERS where
                        ChannelID = '$data->{$Id}->{ChannelID}'
                        and UNIX_TIMESTAMP(NextStartTime) = '$nexttime->{start}'
                        and UNIX_TIMESTAMP(NextStopTime)  = '$nexttime->{stop}'
                        and Summary like '%$aidcomment'
                        order by length(Summary) desc;";
            #dumper($sql);
            my $tresult = $obj->{dbh}->selectrow_hashref($sql);
            $timerID = $tresult->{ID}
                if( ref $tresult and $tresult->{ID} );

            if(!$timerID && $a->{Done} eq 'y') {
                # Ignore timer if it already with same title recorded
                $sql = "SELECT count(*) as cc
                            FROM RECORDS as r, OLDEPG as e
                            WHERE e.eventid = r.EventId
                                AND CONCAT_WS('~',e.title,IF(e.subtitle<>'',e.subtitle,NULL)) = '$file'";
                my $recording = $obj->{dbh}->selectrow_hashref($sql);
                next
                    if(ref $recording and $recording->{cc});

                # Ignore timer if it already a timer with same title programmed, on other place
                $sql = "select count(*) as cc from TIMERS where File = '$file'
                            and
                            ( ChannelID != '$data->{$Id}->{ChannelID}'
                                or UNIX_TIMESTAMP(NextStartTime) != '$nexttime->{start}'
                                or UNIX_TIMESTAMP(NextStopTime)  != '$nexttime->{stop}'
                            )";
                my $done = $obj->{dbh}->selectrow_hashref($sql);
                next
                    if(ref $done and $done->{cc});
           }

            my $error = 0;
            my $erg = $timermod->saveTimer($data->{$Id}, $timerID ? $timerID : undef);
            foreach my $zeile (@$erg) {
                if($zeile =~ /^(\d{3})\s+(.+)/) {
                    $error = $2 if(int($1) >= 500);
                }
            }
            if($error) {
                $console->err(sprintf(gettext("Can't save timer for '%s' : %s"), $data->{$Id}->{File}, $error))
                    if(ref $console && $autotimerid);
            } else {
                if($timerID) {
                    ++$m;
                        $console->message(sprintf(gettext("Modify timer for '%s'."), $data->{$Id}->{File}))
                            if(ref $console && $autotimerid);
                } else {
                    ++$c;
                        $console->message(sprintf(gettext("Create timer for '%s'."), $data->{$Id}->{File}))
                            if(ref $console && $autotimerid);
                        $obj->news($Id, $data->{$Id}, $a);
                }
            }
        }
        $C += $c;
        $M += $m;
        if($c) {
            my $msg = sprintf(gettext("Create %d timer for '%s'."), $c, $a->{Search});
            if(ref $console && $autotimerid) {
                $console->message($msg);
            }
            else {
                push(@{$log},$msg);
            }
        }
        if($m) {
            my $msg = sprintf(gettext("Modify %d timer for '%s'."), $m, $a->{Search});
            if(ref $console && $autotimerid) {
                $console->message($msg);
            }
            else {
                push(@{$log},$msg);
            }
        }
    }

    $waiter->next(undef,undef,gettext('Read new timer in data base.'))
      if(ref $waiter);

    sleep 1;

    $timermod->readData();

    # last call of waiter
    $waiter->next(++$l,1)
      if(ref $waiter);

    if(ref $console) {
        $console->start() if(ref $waiter);
        unshift(@{$log},sprintf(gettext("Autotimer process has %d timers created and %d timers modified."), $C, $M));
        lg join("\n", @$log);
        $console->message($log);
        $console->link({
            text => gettext("Back to autotimer list"),
            url => "?cmd=alist",
        }) if($console->typ eq 'HTML');
        $console->footer() if(ref $waiter);
    }
}

# ------------------
sub autotimerCreate {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $watcher = shift || return error ('No Watcher!');
    my $console = shift || return error ('No Console');
    my $timerid = shift || 0;
    my $data    = shift || 0;

    $obj->autotimerEdit($watcher, $console, $timerid, $data);

}

# ------------------
sub autotimerEdit {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $watcher = shift || return error ('No Watcher!');
    my $console = shift || return error ('No Console');
    my $timerid = shift || 0;
    my $data    = shift || 0;

    my $mod = main::getModule('CHANNELS');
    my $modT = main::getModule('TIMERS');

    my $epg;
    if($timerid and not ref $data) {
        $epg = $obj->{dbh}->selectrow_hashref("select * from AUTOTIMER where Id = $timerid")
            or return $console->message(sprintf(gettext("Autotimer with ID '%s' is not exist in database!"),$timerid));

            # Channels Ids in Namen umwandeln
            my @channels = map { $_ = $mod->ChannelToPos($_) } split(/[\s|,]+/, $epg->{Channels});
            $epg->{Channels} = \@channels;

            # question erwartet ein Array
            my @infields = split(/\s*,\s*/, $epg->{InFields});
            $epg->{InFields} = \@infields;

            # question erwartet ein Array
            my @weekdays = split(/\s*,\s*/, $epg->{Weekdays});
            $epg->{Weekdays} = \@weekdays;
    } elsif (ref $data eq 'HASH') {
        $epg = $data;
    }

    my $questions = [
        'Id' => {
            typ     => 'hidden',
            def     => $epg->{Id} || 0,
        },
        'Activ' => {
            typ     => 'confirm',
            def     => $epg->{Activ} || 'y',
            msg     => gettext('Switch this autotimer on?'),
        },
        'Done' => {
            typ     => 'confirm',
            def     => $epg->{Done} || 'y',
            msg     => gettext('Ignore retry with same broadcast title and already taked recordings?'),
        },
        'Search' => {
            msg   => gettext("Search (minus will search with NOT this txt)\ni.e.: Enterprise,-Voyager"),
            req   => gettext('This is required!'),
            def   => $epg->{Search} || '',
        },
        'InFields' => {
            msg   => gettext('Search in this EPG fields'),
            typ   => 'checkbox',
            choices   => ['title', 'subtitle', 'description'],
            req   => gettext('This is required!'),
            def   => $epg->{InFields} || ['title','subtitle'],
            check   => sub{
                my $value = shift || return;
                my $data = shift || return error('No Data in CB');
                my @vals = (ref $value eq 'ARRAY') ? @$value : split(/\s*,\s*/, $value);

                foreach my $v (@vals) {
                    unless(grep($_ eq $v, @{$data->{choices}})) {
                        my $ch = join(' ', @{$data->{choices}});
                        return undef, sprintf(gettext("You can choose: %s!"),$ch);
                    }
                }
                return join(',', @vals);
            },
        },
        'Channels' => {
            typ     => 'list',
            def     => $epg->{Channels},
            choices => $mod->ChannelArray('Name'),
            options => 'multi',
            msg     => gettext('Restrict search to this channels'),
            check   => sub{
                my $value = shift || return;
                my @vals;
                foreach my $chname ((ref $value eq 'ARRAY' ? @$value : split(/\s*,\s*/, $value))) {
                    if( my $chid = $mod->PosToChannel($chname) || $mod->NameToChannel($chname)) {
                        push(@vals, $chid);
                    } else {
                        return undef, sprintf(gettext("This channel '%s' is not exists!"),$chname);
                    }
                }
                return join(',', @vals);
            },
        },
         'Start' => {
             typ     => 'string',
             def     => sub{
		             my $value = $epg->{Start} || return "";
                     $value = sprintf('%04d',$epg->{Start});
                     return substr($value, 0, 2) .':'. substr($value, 2, 2);
                 },
             msg     => gettext("Starttime in format 'HH:MM'"),
             check   => sub{
                 my $value = shift || 0;
                 return undef, gettext('You set a start-time without a stop-time!')
                    if(not $data->{Stop} and $value);
        		 return "" if(not $value);
                 my @v = split(':', $value);
                 return undef, gettext('No right time!') if(scalar @v != 2);
                 $value = sprintf('%02d%02d',$v[0],$v[1]);
                 if(int($value) < 2400 and int($value) >= 0) {
                     return sprintf('%04d',$value);
                 } else {
                     return undef, gettext('No right time!');
                 }
             },
         },
         'Stop' => {
             typ     => 'string',
             def     => sub{
    		         my $value = $epg->{Stop} || return "";
                     $value = sprintf('%04d',$epg->{Stop});
                     return $value = substr($value, 0, 2) .':'. substr($value, 2, 2);
                 },
             msg     => gettext("Endtime in format 'HH:MM'"),
             check   => sub{
                 my $value = shift || 0;
                 return undef, gettext('You set a stop-time without a start-time!')
                    if(not $data->{Start} and $value);
        		 return "" if(not $value);
                 my @v = split(':', $value);
                 return undef, gettext('No right time!') if(scalar @v != 2);
                 $value = sprintf('%02d%02d',$v[0],$v[1]);
                 if(int($value) < 2400 and int($value) >= 0) {
                     return sprintf('%04d',$value);
                 } else {
                     return undef, gettext('No right time!');
                 }
             },
        },
        'Weekdays' => {
            msg   => gettext('Search only on this weekdays'),
            typ   => 'checkbox',
            choices   => ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
            def   => $epg->{Weekdays} || ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
            check   => sub{
                my $value = shift || ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
                my $data = shift || return error('No Data in CB');
                my @vals = (ref $value eq 'ARRAY') ? @$value : split(/\s*,\s*/, $value);

                foreach my $v (@vals) {
                    unless(grep($_ eq $v, @{$data->{choices}})) {
                        my $ch = join(' ', @{$data->{choices}});
                        return undef, sprintf(gettext("You can choose: %s!"),$ch);
                    }
                }
                return join(',', @vals);
            },
        },
        'VPS' => {
            typ     => 'confirm',
            def     => $epg->{VPS} || 'n',
            msg     => gettext('Activate VPS for new timer?'),
        },
        'prevminutes' => {
            typ     => 'integer',
            msg     => gettext('Buffer time in minutes before the scheduled end of the recorded program.'),
            def     => $epg->{prevminutes},
            check   => sub{
                my $value = shift || return;
                if($value > 0) {
                    return int($value);
                } else {
                    return undef, gettext('No right Value!');
                }
            },
        },
        'afterminutes' => {
            typ     => 'integer',
            msg     => gettext('Buffer time in minutes after the scheduled end of the recorded program.'),
            def     => $epg->{afterminutes},
            check   => sub{
                my $value = shift || return;
                if($value > 0) {
                    return int($value);
                } else {
                    return undef, gettext('No right Value!');
                }
            },
        },
        'MinLength' => {
            typ     => 'integer',
            msg     => gettext('Minimum length in minutes'),
            def     => $epg->{MinLength} || 0,
            check   => sub{
                my $value = shift || return;
                if($value > 0) {
                    return int($value);
                } else {
                    return undef, gettext('No right Value!');
                }
            },
        },
        'Priority' => {
            typ     => 'integer',
            msg     => sprintf(gettext('Priority (0 .. %d)'),$console->{USER}->{MaxPriority} ? $console->{USER}->{MaxPriority} : 99 ),
            def     => (defined $epg->{Priority} ? $epg->{Priority} : $modT->{Priority}),
            check   => sub{
                my $value = shift || 0;
                if($value >= 0 and $value < 100) {
                    if($console->{USER}->{MaxPriority} and $value > $console->{USER}->{MaxPriority}) {
                        return undef, sprintf(gettext('Sorry, but maximum priority is limited on %d!'), $console->{USER}->{MaxPriority});
                    }
                    return int($value);
                } else {
                    return undef, gettext('No right Value!');
                }
            },
        },
        'Lifetime' => {
            typ     => 'integer',
            msg     => sprintf(gettext('Lifetime (0 .. %d)'),$console->{USER}->{MaxLifeTime} ? $console->{USER}->{MaxLifeTime} : 99 ),
            def     => (defined $epg->{Lifetime} ? $epg->{Lifetime} : $modT->{Lifetime}),
            check   => sub{
                my $value = shift || "";
                if($value >= 0 and $value < 100) {
                    if($console->{USER}->{MaxLifeTime} and $value > $console->{USER}->{MaxLifeTime}) {
                        return undef, sprintf(gettext('Sorry, but maximum lifetime is limited on %d!'), $console->{USER}->{MaxLifeTime});
                    }
                    return int($value);
                } else {
                    return undef, gettext('No right Value!');
                }
            },
        },
        'Dir' => {
            msg     => gettext('Group all recordings on a directory'),
            def     => $epg->{Dir},
        },
    ];

    # Ask Questions
    $data = $console->question(($timerid ? gettext('Edit autotimer')
					 : gettext('Create a new autotimer')), $questions, $data);

    if(ref $data eq 'HASH') {
        delete $data->{Channel};

        # Last chance ;)
        return $console->message(gettext('No Search defined!'))
            unless($data->{Search});

    	$obj->insert($data);

    	$data->{Id} = $obj->{dbh}->selectall_arrayref('SELECT max(ID) FROM AUTOTIMER')->[0][0]
    		if(not $data->{Id});

        $console->message(gettext('Autotimer saved!'));
        lg sprintf('%s autotimer with search "%s" is saved from User: %s',
            ($timerid ? 'New' : 'Changed'),
            $data->{Search},
            $console->{USER}->{Name}
            );
        $obj->autotimer($watcher, $console, $data->{Id}, $data->{refe} );

        $console->link({
            text => gettext("Back to referred side"),
            url => $console->{browser}->{Referer},
        }) if($console->typ eq 'HTML');

    }
    return 1;
}

# ------------------
sub autotimerDelete {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $watcher = shift || return error ('No Watcher!');
    my $console = shift || return error ('No Console');
    my $timerid = shift || return $console->message(gettext("No ID for autotimer to delete! Please use adelete 'aid'"));   # If timerid the edittimer

    my $erg = $obj->{dbh}->do("delete from AUTOTIMER where Id in ($timerid)")
        or return $console->message(sprintf gettext("Autotimer with ID '%s' is not exist in database!"), $timerid);
    $console->message(sprintf gettext("Autotimer %s is deleted."), $timerid);
    lg sprintf('autotimer with id "%s" is deleted from User: %s',
        $timerid,
        $console->{USER}->{Name}
        );
    $console->redirect({url => $console->{browser}->{Referer}, wait => 1})
        if($console->typ eq 'HTML');
}

# ------------------
sub autotimerToggle {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $watcher = shift || return error ('No Watcher!');
    my $console = shift || return error ('No Console');
    my $timerid = shift || return $console->message(gettext("No ID for autotimer to toggle! Please use atoggle 'aid'"));   # If timerid the edittimer

    my $status = $obj->{dbh}->selectrow_arrayref("select Activ from AUTOTIMER where Id = $timerid")->[0]
       or return $console->message(sprintf gettext("Autotimer with ID '%s' is not exist in database!"), $timerid);

    my $newstatus = ($status eq 'n') ? 'y' : 'n';
    my $erg = $obj->{dbh}->do("UPDATE AUTOTIMER set Activ = '$newstatus' where Id = $timerid")
        or return $console->message(sprintf(gettext("Autotimer with ID '%s' is not exist in database!"),$timerid));
    my $text = ($newstatus eq 'n') ? gettext('disabled')
                                   : gettext('activated');
    lg sprintf('autotimer with id "%s" is %s from User: %s',
        $timerid,
        ($newstatus eq 'n' ? 'disabled' : 'activated'),
        $console->{USER}->{Name}
        );

    $console->message(sprintf gettext("Autotimer %s is %s."), $timerid, $text);
    $console->redirect({url => $console->{browser}->{Referer}, wait => 2})
        if($console->typ eq 'HTML');
}

# ------------------
sub list {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $watcher = shift || return error ('No Watcher!');
    my $console = shift || return error ('No Console');
    my $id      = shift || '';
    my $params  = shift;

    my $sql = "select Id, Activ as Act, Search, Channels, Dir, Start, Stop, MinLength as Min from AUTOTIMER where Id like '%$id%'";
    my $fields = fields($obj->{dbh}, $sql);

    my $sortby = "Search";
    $sortby = $params->{sortby}
        if(exists $params->{sortby} && grep(/^$params->{sortby}$/i,@{$fields}));
    $sql .= " order by $sortby";
    if(exists $params->{desc} && $params->{desc} == 1) {
        $sql .= " desc"; }
    else {
        $sql .= " asc"; }

    my $erg = $obj->{dbh}->selectall_arrayref($sql);
    unshift(@$erg, $fields);

    my $mod = main::getModule('CHANNELS');

    $console->table($erg,
        {
            sortable => 1,
            channels => $mod->ChannelHash('Id')
        }
    );
}

# ------------------
sub insert {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return;

    if(ref $data eq 'HASH') {
        my ($names, $vals, $kenn);
        map {
            push(@$names, $_);
            push(@$vals, $data->{$_}),
            push(@$kenn, '?'),
        } sort keys %$data;

        my $sql = sprintf("REPLACE INTO AUTOTIMER (%s) VALUES (%s)",
                join(', ', @$names),
                join(', ', @$kenn),
        );
        my $sth = $obj->{dbh}->prepare( $sql );
        $sth->execute( @$vals );
    } else {
        my $sth = $obj->{dbh}->prepare('REPLACE INTO AUTOTIMER VALUES (?,?,?,?,?,?,?,?,?)');
        $sth->execute( @$data );
    }
}

sub autotimerimport {
    my $obj = shift || return error ('No Object!' );
    my $watcher = shift || return error ('No Watcher!');
    my $console = shift || return error ('No Console');
    my $AT_FILENAME = shift || return $console->message(gettext("No filename to import! Please use aimport '../vdradmind.at'"));
    my $mod = main::getModule ('CHANNELS');
    my $cnt = "0";
    open(AT_FILE, "$AT_FILENAME") || return $console->message(sprintf(gettext("can't open file '%s' : %s"),$AT_FILENAME,$!));
    while(<AT_FILE>) {
        chomp;
        next if ($_ eq "");

        my($active, $pattern, $section, $start, $stop, $episode, $prio,
            $lft, $channel, $directoy) = split(/\:/, $_);

        my $data;
        $data->{Id} = 0;
        if($active eq "1") { $data->{Activ} = 'y'; }
	    else               { $data->{Activ} = 'n'; }

        my @vals;
        $data->{Done} = 'y';
        $data->{Search} = $pattern;
        push(@vals, "title")
            if($section & 1);
        push(@vals, "subtitle")
            if($section & 2);
        push(@vals, "description")
            if($section & 4);
        $data->{InFields} = join(',', @vals);
        if( $channel ne "") {
            if (my $chid = $mod->PosToChannel($channel)) {
                $data->{Channels} = $chid;
            }
        }
        $data->{Priority} = $prio;
        $data->{Lifetime} = $lft;
        $data->{Dir} = $directoy;
        $data->{Start} = $start;
        $data->{Stop} = $stop;
#       $data->{Episode} = $episode; # autotimerimport don't support episode, i belief "1" means File = title~subtitle / "0" means File = title

        $obj->insert($data);
        ++$cnt;
    }
    close (AT_FILE);
    $console->message(sprintf(gettext("%d Autotimer read from file %s."),$cnt,$AT_FILENAME));
    lg sprintf('%d autotimers imported from file "%s" as User: %s',
        $cnt,
        $AT_FILENAME,
        $console->{USER}->{Name}
        );

    $console->redirect({url => "?cmd=alist", wait => 2})
        if($console->typ eq 'HTML');
    return 1;
}

sub autotimerexport {
    my $obj = shift || return error ('No Object!' );
    my $watcher = shift || return error ('No Watcher!');
    my $console = shift || return error ('No Console');
    my $AT_FILENAME = shift || return $console->message(gettext("No filename to export! Please use aexport '../vdradmind.at'"));
    my $id      = shift || '';

    my $mod = main::getModule ('CHANNELS');

    my $sql = "select Activ, Search, InFields, Channels, Dir, Start, Stop, Priority, Lifetime from AUTOTIMER where AUTOTIMER.Id like '%$id%' order by AUTOTIMER.Id";
    my $atlist = $obj->{dbh}->selectall_arrayref($sql);
    my $cnt = "0";
    open(AT_FILE, ">$AT_FILENAME") || return $console->message(sprintf(gettext("can't open file '%s' : %s"),$AT_FILENAME,$!));
    foreach my $data (@$atlist) {
        if($data->[1] ne "" and $data->[2] ne "") {

        my $active = "0";
        my $pattern = $data->[1];
        my $section = "0";
        my $start = "";
        my $stop = "";
        my $episode = "0"; # autotimerexport don't support episode, i belief "1" means File = title~subtitle / "0" means File = title
        my $prio = "";
        my $lft = "";
        my $channel = "";
        my $directoy = "";

        $active = "1" if($data->[0] eq "y");

        $section |= 1 if ($data->[2]=~/^.*title.*$/);
        $section |= 2 if ($data->[2]=~/^.*subtitle.*$/);
        $section |= 4 if ($data->[2]=~/^.*description.*$/);

        if( $data->[3]) {
            foreach my $ch (@{$mod->ChannelArray ('Id')}) {
                if ($data->[3] eq $ch->[0]) { # vdradmin suppport only one Channel
                    $channel = $ch->[1];
                    last;
                }
            }
        }

        $directoy = $data->[4] if($data->[4]);
        $start = $data->[5] if($data->[5] and $data->[5] ne $data->[6]); # Exclude if start and stop if same value e.g. 0000
        $stop = $data->[6] if($data->[6] and $data->[5] ne $data->[6]);
        $prio = $data->[7] if($data->[7]);
        $lft = $data->[8] if($data->[8]);

        print AT_FILE sprintf("%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n",
            $active,$pattern,$section,$start,$stop,$episode,$prio,$lft,$channel,$directoy)
            || return return $console->message(sprintf(gettext("can't write file '%s' : %s"),$AT_FILENAME,$!));
        ++$cnt;
        }
    }
    close (AT_FILE);
    $console->message(sprintf(gettext("%d Autotimer write to file %s"),$cnt,$AT_FILENAME));
    lg sprintf('%d autotimers exported to file "%s" from User: %s',
        $cnt,
        $AT_FILENAME,
        $console->{USER}->{Name}
        );
    $console->redirect({url => "?cmd=alist", wait => 2})
        if($console->typ eq 'HTML');
    return 1;
}

# Routine for the ReportModul to send importand News
# ------------------
sub news {
# ------------------
    my $obj = shift  || return error ('No Object!' );
    my $epgid = shift|| return error ('No EPG Id!' );
    my $epgdata = shift || return error ('No EpgData!');
    my $atdata = shift || return error ('No ATData!');
    my $report = main::getModule('REPORT');

    my $title = sprintf(
        gettext("Autotimer('%s') found EPG: %s"),
        $atdata->{Search}, $epgdata->{Title});
    my $description = sprintf(gettext("Description: %s\nDay: %s At: %s - %s"),
        $epgdata->{Summary}, $epgdata->{Day}, $epgdata->{Start}, $epgdata->{Stop});
    my $cmd = 'display';
    my $id = $epgid;

    $report->news($title, $description, $cmd, $id, 30);
}


1;
