# BBCNews Ticker v1.3
# Copyright (c) 2002-2004 Gordon Johnston (gordonj@newswall.org.uk)
# Designed for Slimserver v 5.0 and above

# http://newswall.org.uk/~slimp3/news_ticker.html

# Contains code from SlimServer which is:  Copyright (c) 2001-2004 Sean Adams, Slim Devices Inc.

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License, 
# version 2.

package Plugins::BbcNews;
use strict;

# USER DEFINED CONSTANTS - You can configure the ticker here

# Automatic Refresh Frequency (sec). The frequency at which the ticker refreshes.
# Default 120 seconds (2 minutes)
# Set to 0 to disable automatic refresh
my $refresh_interval = 120;

# Disable Screensaver. Set this to 1 (one) to disable the screensaver whilst the BBC plugin is displayed
# You can set this and still use the plugin as a screensaver
# Set to 0 (zero) if you do not want to disable the screensaver.
my $screensaver_disable = 1;

# Auto Scroll Speed
# Delay in seconds before ticker automatically moves to the next news topic (disabled by default)
my $auto_scroll = 0;

# Auto Scroll Screensaver Speed
# As auto_scroll, above, but only applied when plugin in running as a screensaver.
# Any keypress exits the screensaver so ticker must move between topics automatically (32 seconds by default)
my $auto_scroll_screensaver = 32;

# Item Seperator. This is inserted between each item of news.
my $item_seperator = ' --- ';

# Wrap Around. Set to 0 (zero) if you would like the ticker to stop when scrolling with the remote reaches
#              the final news catagory 
my $wrap = 1;

# Current date masking. Set this to 1 (one) to hide the date when displaying the ticker text
# The date can always be viewed in the 'World News' category, so by default this option is on
my $date_hide = 1;

# The url for the bbc news ticker
my $bbcnews_location = 'http://tickers.bbc.co.uk/tickerdata/story2.dat';

# The BBC News Ticker is split into 8 news topics.
# You can specify the topics you want to display and their ordering here:
# See below for a key to the topic numbers

# show all
#my @display_stack=(2,3,4,5,6,7,8);
#my @display_stack_left=();
#my $display_current=1;

# no travel
# we hide travel by default as it doesn't display anything useful
my @display_stack=(2,3,4,5,6,8);
my @display_stack_left=();
my $display_current=1;

# Topics are:

my @news_description=(
	'NEWS DESCRIPTIONS',	#Topic Numbers
	'WORLD NEWS',		#1
	'UK NEWS',		#2
	'SPORTS NEWS',		#3
	'BUSINESS NEWS',	#4
	'SCI-TECH NEWS',	#5
	'WEATHER',		#6
	'TRAVEL NEWS',		#7
	'FINANCE'		#8
);

######
# CHANGELOG
######
#
# 1.3 - Final Released 28/Jun/04
# 1.3 - Beta Released 10/May/04
#
# NEW - Can run as a 'screensaver'. Press 'play' to activate whilst using plugin or select in the web interface
# NEW - Auto Scoll - Required for screensaver but can also be used in normal use
#
######
#
# 1.2 - Final Released 26/Apr/04
# 1.2 - Beta Released 28/Mar/04
#
# NEW - Automatic refresh of news at defined interval.
# NEW - Surpresses the display of the date on each news topic.
# NEW - User definable article seperator.
# NEW - Started Changelog and To-do list.
# FIX - Safer screensaver disabling code.
#
######
#
# 1.1 - Released 11/Feb/04
#
######
# TODO
######
#
# Funky integration into the web interface. Watch this space.
# Visible in 'top level' menu of player. Waiting for slimserver code to stabilise before implementing
#
######

# INTERNAL VARIABLES and STUFF!. Do not edit.
use Slim::Buttons::Common;
use Slim::Web::RemoteStream;
use Slim::Control::Command;
use Slim::Utils::Strings qw (string);
use Slim::Utils::Timers;
use Slim::Utils::Misc;
use Socket;
use vars qw($VERSION);
$VERSION = substr(q$Revision: 1.3 $,10);
my @thenews ;
my $state = "wait";
my $refresh_last = 0;
my $screensaver_timeout = 0;
my $screensaver_reset_interval = 0;
my $running_as = 'plugin';
# $refresh_min is the minimum time in seconds between refreshes of the ticker from the BBC.
# Please do not lower this value. It prevents excessive queries to the BBC.
# This value is ignored when a refresh is manually requested via the remote.
my $refresh_min = 30; 

# Plugin descriptions
# If anyone would like to suggest translations, please do via email to gordonj@newswall.org.uk

sub getDisplayName() {return string('PLUGIN_BBCNEWS')}

sub strings() { return q!
PLUGIN_BBCNEWS
	EN	BBC News Ticker
	
PLUGIN_BBCNEWS_WAIT
	EN	Please wait requesting...

PLUGIN_BBCNEWS_ERROR
	EN	Failed to retrieve ticker - Press '->'

PLUGIN_BBCNEWS_SCREENSAVER
	EN	BBC News Ticker - Screensaver

PLUGIN_BBCNEWS_SCREENSAVER_ENABLE
	EN	Activating ticker as current screensaver

PLUGIN_BBCNEWS_SCREENSAVER_DISABLE
	EN	Returning to default screensaver
!};

# button functions
# These functions are run when the respective button is pressed on the remote

my %functions = (
	'left' => sub {
		#Return to previous menu
		my $client=shift;
		if ($screensaver_disable) {
			Slim::Utils::Timers::killTimers($client, \&screensaverTimerReset);
		        Slim::Utils::Timers::killTimers($client, \&autoScrollTimer);
		}
		Slim::Buttons::Common::popModeRight($client);
		return;
},
	'up' => sub {
		#move 'up' the list of news topics
		my $client = shift;
		&nextTopic($client);
		$client->lines(\&lines);
		Slim::Display::Display::update($client);;
		return;
},

	'down' => sub {
		#move 'down' the list of news topics
		my $client = shift;
		&previousTopic($client);
		$client->lines(\&lines);
		Slim::Display::Display::update($client);;
		return;
},
	'right' => sub {
		#Refresh the news
	        my $client = shift;
                my @oldlines = Slim::Display::Display::curLines($client);
		$state='wait';
		$client->lines(\&lines);
                Slim::Display::Display::update($client);
		#user requested refresh, override $refresh_min
		$refresh_last = 0;
		&retrieveNews($client);
		return;
},

	'play' => sub {
	        #press 'play' to activate screensaver
		my $client = shift;
                if (Slim::Utils::Prefs::clientGet($client,'screensaver') ne 'SCREENSAVER.bbcnews') {
                        Slim::Utils::Prefs::clientSet($client,'screensaver','SCREENSAVER.bbcnews');
                        my ($line1, $line2) = (string('PLUGIN_BBCNEWS_SCREENSAVER'), string('PLUGIN_BBCNEWS_SCREENSAVER_ENABLE'));
                        Slim::Display::Animation::showBriefly($client, $line1, $line2);
                } else {
                        Slim::Utils::Prefs::clientSet($client,'screensaver','screensaver');
                        my ($line1, $line2) = (string('PLUGIN_BBCNEWS_SCREENSAVER'), string('PLUGIN_BBCNEWS_SCREENSAVER_DISABLE'));
                        Slim::Display::Animation::showBriefly($client, $line1, $line2);
                }
		


}
);

sub nextTopic {
		my $client = shift;
                #if there are no topics left then wrap around if selected (always wrap when running as screensaver)
                if( (!@display_stack) && ( $wrap || $running_as eq 'screensaver') ) {
                        @display_stack=@display_stack_left;
                        @display_stack_left=();
                }
                #Move up the list of topics
                if(@display_stack) {
                        push @display_stack_left, ($display_current);
                        $display_current=shift @display_stack;
                }
		if ($client) {
			Slim::Display::Display::update($client);;
		}
}


sub previousTopic {
		my $client = shift;
                #if there are no topics left then wrap around if selected (always wrap when running as screensaver)
                if ( (!@display_stack_left) && ( $wrap || $running_as eq 'screensaver') ) {
                        @display_stack_left=@display_stack;
                        @display_stack=();
                }
                #Move down the list of topics
                if(@display_stack_left){
                        unshift @display_stack, ($display_current);
                        $display_current=pop @display_stack_left;
                }
		if ($client) {
			Slim::Display::Display::update($client);;
		};
}

sub getFunctions {
	#export the functions to SlimServer
	return \%functions;
}

sub retrieveNews {

	my $client = shift;

	my $now = time();

	if ( $now - $refresh_last > $refresh_min ) {
        	my $sock = Slim::Web::RemoteStream::openRemoteStream($bbcnews_location, $client);	
		if ($sock)		{
			#import the news from the socket 
		        my $cur_story=1;
			@thenews=();
		        while(<$sock>) {
				if (/^STORY (.)/) {
					$cur_story=$1;
				} elsif (/^HEADLINE (.*)/) {
		                        $thenews[$cur_story].=$1.$item_seperator;
				}
			}
			$sock->close;;
			$refresh_last = $now;
		};
	}
	$state='';
	if ($client) {
		Slim::Display::Display::update($client);;
	}
}

sub setMode {
	#This is executed each time the Ticker is selected from the plugins/extras menu.
	my $client = shift;
        $state= 'wait';
	$running_as = 'plugin';

        $client->lines(\&lines);
        $refresh_last = 0;
        &retrieveNews($client);


	if ($auto_scroll) {
                Slim::Utils::Timers::setTimer($client, time() + $auto_scroll, \&autoScrollTimer);
	}

	if ($screensaver_disable) {
		$screensaver_timeout=Slim::Utils::Prefs::clientGet($client,"screensavertimeout");
		$screensaver_reset_interval = $screensaver_timeout / 2;
		if ($screensaver_reset_interval < 1) { $screensaver_reset_interval = 1; };
		Slim::Utils::Timers::setTimer($client, time()+$screensaver_reset_interval, \&screensaverTimerReset);
	}
}

sub screensaverTimerReset {

	my $client = shift;
	my $now = time();

	Slim::Hardware::IR::setLastIRTime($client,$now);
	Slim::Utils::Timers::setTimer($client,$now+$screensaver_reset_interval, \&screensaverTimerReset);

}

sub autoScrollTimer {

	my $client = shift;

	&nextTopic($client);
	if ($running_as eq 'plugin' && ($auto_scroll > 0)) {
		Slim::Utils::Timers::setTimer($client, time() + $auto_scroll, \&autoScrollTimer);
	} else {
		Slim::Utils::Timers::setTimer($client, time() + $auto_scroll_screensaver, \&autoScrollTimer);
	}
}
		

sub lines {
	#This returns the 2 lines to display on the unit 
	my $client = shift;
	my ($line1, $line2);
	my $now = time();

	if ( $refresh_interval && ( $now - $refresh_last > $refresh_interval ) ) {
		&retrieveNews($client);
	}

        $line1 = "BBC News - ".$news_description[$display_current];

	if ($state eq 'wait') {
		$line2 = string('PLUGIN_BBCNEWS_WAIT');
	} 
	elsif (exists($thenews[$display_current])) {
                $line2 = $thenews[$display_current];

		if ($date_hide && ($line2 =~ /(.*)\s*[^\d]\d{1,2}\s[a-zA-Z]*\s\d{4}(.*)/) ) {
			$line2=$1.$2;
		}
        } else {
                $line2 = string('PLUGIN_BBCNEWS_ERROR');
        }

	return ($line1, $line2);
}	

sub screenSaver() {
        Slim::Utils::Strings::addStrings(&strings());
        Slim::Buttons::Common::addSaver('SCREENSAVER.bbcnews', getScreensaverBbcNews(), \&setScreensaverBbcNewsMode,\&leaveScreenSaverBbcNews,string('PLUGIN_BBCNEWS_SCREENSAVER'));
}

my %screensaverBbcNewsFunctions = (
        'done' => sub  {
		my ($client, $funct, $functarg) = @_;
       		Slim::Buttons::Common::popMode($client);
		$client->update();
		#pass along ir code to new mode if requested
		if (defined $functarg && $functarg eq 'passback') {
			Slim::Hardware::IR::resendButton($client);
		}
	}
);

sub getScreensaverBbcNews {
        return \%screensaverBbcNewsFunctions;
}

sub setScreensaverBbcNewsMode() {

        my $client = shift;
	
        $state= 'wait';
        $running_as = 'screensaver';                                                                                                                                                               
	Slim::Utils::Timers::setTimer($client, time() + $auto_scroll_screensaver, \&autoScrollTimer);

	$client->lines(\&lines);
        $refresh_last = 0;
        &retrieveNews($client);


}

sub leaveScreenSaverBbcNews {

	#kill timers
	my $client = shift;
	Slim::Utils::Timers::killTimers($client, \&autoScrollTimer);

}

1;

__END__
