#!/usr/bin/perl
#
# This file is part of App-SpreadRevolutionaryDate
#
# This software is Copyright (c) 2019 by Gérald Sédrati-Dinet.
#
# This is free software, licensed under:
#
#   The GNU General Public License, Version 3, June 2007
#
use strict;
use warnings;
use utf8;

# PODNAME: spread-revolutionary-date
# ABSTRACT: Spread date and time from Revolutionary (Republican) Calendar

use App::SpreadRevolutionaryDate;
App::SpreadRevolutionaryDate->new->spread;

__END__

=pod

=encoding UTF-8

=head1 NAME

spread-revolutionary-date - Spread date and time from Revolutionary (Republican) Calendar

=head1 VERSION

version 0.09

=head1 DESCRIPTION

C<spread-revolutionary-date> is a L<Free Software|https://www.gnu.org/philosophy/free-sw.html> that spreads the current date, expressed in L<French Revolutionary calendar|https://en.wikipedia.org/wiki/French_Republican_calendar>, to various social networks: L<Twitter|https://twitter.com/>, L<Mastodon|https://mastodon.social/>, and the L<Freenode|https://freenode.net/> Internet Relay Chat network.

Moreover, you can easily extend these defaults targets with any desired one, see L</"EXTENDING TO NEW TARGETS">, and even spread something else than the revolutionary date, see L</msgmaker> option and L</"EXTENDING TO NEW MESSAGE MAKERS">.

The French Revolutionary calendar, also called Republican calendar, was introduced during the L<French Revolution|https://en.wikipedia.org/wiki/French_Revolution>, and used from late 1793 to 1805, and also during the L<Paris Commune|https://en.wikipedia.org/wiki/Paris_Commune> in 1871. This was an attempt to get rid of religious and royalist references found in Gregorian calendar when naming measures of Time. Months were given new names based on nature, each day of the year, instead of being named after an associated saint, had a unique name associated with the rural economy: agricultural tools, common animals, grains, pastures, trees, roots, flowers, fruits, plants, and minerals. But this was also an attempt to give more rational in measuring Time, basing measures on decimal system. Instead of weeks, each month was divided into exactly 3 I<décades>, that is ten days; days were divided into ten hours; hours into 100 minutes; and minutes into 100 seconds.

You B<must> have a registered account on each of the targets you want to spread the revolutionary date. And you must get credentials for C<spread-revolutionary-date> to post on Twitter and Mastodon. Finally, you have to configure C<spread-revolutionary-date> to use these credentials, see L</CONFIGURATION> and L</"COMMAND LINE PARAMETERS"> below.

The revolutionary date and time is computed thanks to the L<DateTime::Calendar::FrenchRevolutionary> Perl module, by Jean Forget.

=head1 USAGE

  # Just execute the script in your shell
  # to spread current date to configured accounts on Twitter, Mastodon and Freenode:
  $ spread-revolutionary-date

  # Or, since this script do nothing but calling the L<App::SpreadRevolutionaryDate> Perl module,
  # use this one-liner:
  $ perl -MApp::SpreadRevolutionaryDate -e 'App::SpreadRevolutionaryDate->new->spread;'

  # Test spreading to Mastodon only:
  $ spread-revolutionary-date --targets=mastodon --test

  # Test spreading to Twitter only in English:
  $ spread-revolutionary-date --targets=twitter --test --locale=en

  # Spread acab time to Twitter and Freenode explicit channels
  $ spread-revolutionary-date --targets=twitter \
      --targets=freenode \
      --freenode_channels='#revolution' \
      --freenode_channels='#acab' \
      --revolutionarydate_acab

  # Prompt user for a message to spread to mastodon
  $ spread-revolutionary-date --targets=mastodon \
      --msgwriter=UserPrompt

=head1 CONFIGURATION

Once again: you B<have to> configure C<spread-revolutionary-date> with credentials for registered account on each of the desired targets, so it can spread the revolutionary date on behalf of these accounts.

Configuration options may also be specified as command line parameters, see L</"COMMAND LINE PARAMETERS"> below, which take precedence on options of the configuration file.

The configuration file should lie on C<~/.config/spread-revolutionary-date/spread-revolutionary-date.conf> or C<~/.spread-revolutionary-date.conf>. In case a file is found on both paths, the second one is ignored. The configuration file should use the popular L<INI file format|https://en.wikipedia.org/wiki/INI_file>. A sample configuration file can be found in this distribution at C<etc/sample-spread-revolutionary-date.conf>.

=head2 General options

These options should appear outside of any section of the configuration file.

=head3 targets

This option can be specified multiple times, with values as strings. It explicitly defines targets where the revolutionary date should be spread to. Any value set for this option should be a valid target: any of the three default targets (C<twitter>, C<mastodon>, or C<freenode>) or some new target if you have extended this application (see L</"EXTENDING TO NEW TARGETS">). If this option is not defined, the revolutionary date is spread on all three default targets: C<twitter>, C<mastodon>, and C<freenode>.

=head3 msgmaker

This option can only be specified once, with a value as string. Spread a message computed by the class defined by the value of this option, defaults to C<RevolutionaryDate>. The C<Value> (case sensitive) of this option should correspond to an existing C<App::SpreadRevolutionaryDate::MsgMaker::Value> class consuming L<App::SpreadRevolutionaryDate::MsgMaker> role. Message makers values pre-defined in this distribution are C<RevolutionaryDate>, which spreads the revolutionary date, and C<PromptUser>, which prompts the user for the message to be spread (with confirmation). See L</"EXTENDING TO NEW MESSAGE MAKERS"> for details on using a new value for this option.

=head3 locale

This option can only be specified once, with a value as string. Spread with chosen language. As of L<DateTime::Calendar::FrenchRevolutionary> 0.14, locale is limited to C<'en'> or C<'fr'>, defaults to C<'fr'>.

=head3 test

This boolean option takes no value, either it is defined or not. If defined, do not actually spread the revolutionary date, just print it on standard output for Twitter and Mastodon, and send it on configured test channels for Freenode (see L</"test_channels"> below).

=head3 acab I<DEPRECATED>

This option is I<deprecated> since version 0.09 of this distribution and may be removed in future release. Please use L</"RevolutionaryDate acab option"> option below.

=head3 twitter I<DEPRECATED>

This option is I<deprecated> since version 0.07 of this distribution and may be removed in future release. Please use L</targets> option below. Spread on Twitter explicitly. If none of the C<twitter>, C<mastodon>, C<freenode> option is set, the revolutionary date is spread on all of these three targets.

=head3 mastodon I<DEPRECATED>

This option is I<deprecated> since version 0.07 of this distribution and may be removed in future release. Please use L</targets> option below. Spread on Mastodon explicitly. If none of the C<twitter>, C<mastodon>, C<freenode> option is set, the revolutionary date is spread on all of these three targets.

=head3 freenode I<DEPRECATED>

This option is I<deprecated> since version 0.07 of this distribution and may be removed in future release. Please use L</targets> option below. Spread on Freenode explicitly. If none of the C<twitter>, C<mastodon>, C<freenode> option is set, the revolutionary date is spread on all of these three targets.

=head2 Twitter options

These options are credentials for C<spread-revolutionary-date> to spread on a Twitter account. You have to get them from your L<Twitter API account|https://apps.twitter.com/> with C<write> access level. They should be defined in the C<[twitter]> section of the configuration file.

=head3 consumer_key

This option can only be specified once, with a value as string: your Twitter Consumer API key for this application.

=head3 consumer_secret

This option can only be specified once, with a value as string: your Twitter Consumer API secret key for this application.

=head3 access_token

This option can only be specified once, with a value as string: your Twitter Access token for this application.

=head3 access_token_secret

This option can only be specified once, with a value as string: your Twitter Access token secret for this application.

=head2 Mastodon options

These options are credentials for C<spread-revolutionary-date> to spread on a Mastodon account. You have to get them from your L<Mastodon instance API account|https://mstdn.fr/settings/applications> with C<write> scope. Note that Mastodon is a decentralized network with multiple instances, the previous link is for L<mstdn.fr|https://mstdn.fr> instance, please replace url with your preferred instance. They should be defined in the C<[mastodon]> section of the configuration file.

=head3 instance

This option can only be specified once, with a value as string: the domain name of your instance, eg: C<mastodon.social>, C<mstdn.fr>, etc.

=head3 client_id

This option can only be specified once, with a value as string: your Mastodon Client key for this application.

=head3 client_secret

This option can only be specified once, with a value as string: your Mastodon Client secret for this application.

=head3 access_token

This option can only be specified once, with a value as string: your Mastodon Access token for this application.

=head2 Freenode options

The first two options are credentials for C<spread-revolutionary-date> to spread on a Freenode account. See L<https://freenode.net/kb/answer/registration> to find out how to register an account on Freenode. They should be defined in the C<[twitter]> section of the configuration file.

=head3 nickname

This option can only be specified once, with a value as string: your Freenode nickname.

=head3 password

This option can only be specified once, with a value as string: your Freenode password.

=head3 channels

This option can be specified multiple times, with values as strings. C<spread-revolutionary-date> will spread on every channel specified with this option. This option should be specified at least one time if L</test> option is not set. It is ignored if L</test> option is set.

=head3 test_channels

This option can be specified multiple times, with values as strings. C<spread-revolutionary-date> will spread on every channel specified with this option. This option should be specified at least one time if L</test> option is set. It is ignored if L</test> option is not set.

=head2 RevolutionaryDate acab option

This boolean option takes no value, either it is defined or not. If defined, instead of spreading the current date and time, pretend that decimal time is 1:31:20 (which corresponds to 03:08:56 UTC, 04:08:56 Paris winter time, or 05:08:56 Paris summer time, in sexagesimal scale used by common Anglo-Babylonian Time). The C<acab> option should be defined in the C<[revolutionarydate]> section of the configuration file. It is only used if L</msgmaker> option is C<RevolutionaryDate>.

=head2 PromptUser default option

This option can only be specified once, with a value as string. Instead of spreading the revolutionary date, prompt user (with confirmation) for the message to be spread, with a default value (if user enters nothing when prompted). If C<default> option is not defined, the default message is C<'Goodbye old world, hello revolutionary worlds'> if the user enters nothing when prompted. The C<default> option should be defined in the C<[promptuser]> section of the configuration file. It is only used if L</msgmaker> option is C<PromptUser>.

=head1 COMMAND LINE PARAMETERS

Any command line parameter takes precedence on the corresponding option specified on the confiuration file, see L</"CONFIGURATION> below.

=head2 General parameters

=head3 --targets | -tg

Same as L</targets> configuration option below.

=head3 --msgmaker | -mm

Same as L</msgmaker> configuration option below.

=head3 --locale | -l

Same as L</locale> configuration option below.

=head3 --test | --no | -n

Same as L</test> configuration option below.

=head3 --acab | -a I<DEPRECATED>

Same as L</acab> configuration option below.

=head3 --twitter | -t I<DEPRECATED>

Same as L</twitter> configuration option below.

=head3 --mastodon | -m I<DEPRECATED>

Same as L</mastodon> configuration option below.

=head3 --freenode | -f I<DEPRECATED>

Same as L</freenode> configuration option below.

=head2 Twitter parameters

These parameters specify credentials for C<spread-revolutionary-date> to spread on a Twitter account. You have to get them from your L<Twitter API account|https://apps.twitter.com/> with C<write> access level.

=head3 --twitter_consumer_key | -tck

Same as L</consumer_key> configuration option below.

=head3 --twitter_consumer_secret | -tcs

Same as L</consumer_secret> configuration option below.

=head3 --twitter_access_token | -tat

Same as L</access_token> configuration option below.

=head3 --twitter_access_token_secret | -tats

Same as L</access_token_secret> configuration option below.

=head2 Mastodon parameters

These parameters specify credentials for C<spread-revolutionary-date> to spread on a Mastodon account. You have to get them from your L<Mastodon instance API account|https://mstdn.fr/settings/applications> with C<write> scope. Note that Mastodon is a decentralized network with multiple instances, the previous link is for L<mstdn.fr|https://mstdn.fr> instance, please replace url with your preferred instance.

=head3 --mastodon_instance | -mi

Same as L</instance> configuration option below.

=head3 --mastodon_client_id | -mci

Same as L</client_id> configuration option below.

=head3 --mastodon_client_secret | -mcs

Same as L</client_secret> configuration option below.

=head3 --mastodon_access_token | -mat

Same as L</access_token> configuration option below.

=head2 Freenode parameters

The first two parameters are credentials for C<spread-revolutionary-date> to spread on a Freenode account. See L<https://freenode.net/kb/answer/registration> to find out how to register an account on Freenode.

=head3 --freenode_nickname | -fn

Same as L</nickname> configuration option below.

=head3 --freenode_password | -fp

Same as L</password> configuration option below.

=head3 --freenode_channels | -fc

Same as L</channels> configuration option below.

=head3 --freenode_test_channels | -tc

Same as L</test_channels> configuration option below.

=head2 --revolutionarydate-acab

Same as L</"RevolutionaryDate acab option"> configuration option below.

=head2 --promptuser-default

Same as L</"PromptUser default option"> configuration option below.

=head1 EXTENDING TO NEW TARGETS

Version 0.07 of this distribution is a complete redesign of the API, taking advantage of L<Moose>, the postmodern object system for Perl 5, allowing to easily extend C<spread-revolutionary-date> to other targets than the default ones (C<Twitter>, C<Mastondon> and C<Freenode>.

To add a new target, you should write a new class in the C<App::SpreadRevolutionaryDate::Target::> namespace (that is: the class should be C<App::SpreadRevolutionaryDate::Target::Mytarget> for a new C<Mytarget> target), that consumes the L<App::SpreadRevolutionaryDate::Target> role. See L<App::SpreadRevolutionaryDate::Target/DESCRIPTION> for a comprehensive description of this role.

The name of the target should be added as a value of the L</targets> option in lower case.

Such a target class is actually just a wrapper. Usually a target has to use an existing specific module (which can be a C<Moose> class or not) to perform the actual work of posting a message according the specific target protocol, after having complied with any potential required authentication. Such authentication should be carried on by the constructor or, along with posting, by the required C<spread> method of the target class.

To perform authentication and to post a message, there is a strong likelihood that the new target requires specific parameters (for eg. tokens, keys, account name, password, channels, etc.). These parameters should be defined as required attributes of the target class. Values for such attributes should be set in the L<configuration file|/CONFIGURATION>, inside a section named after the target in lower case (C<[mytarget]>), or as L<command line parameters|/"COMMAND LINE PARAMETERS"> prefixed with the name of the target in lower case, followed by an underscore (C<--mytarget_myparam>).

Should you extend C<spread-revolutionary-date> to a new target, we advise you to have a look on how default targets are implemented: L<App::SpreadRevolutionaryDate::Target::Twitter> with L<Net::Twitter::Lite::WithAPIv1_1> C<worker>, L<App::SpreadRevolutionaryDate::Target::Mastodon> with L<Mastodon::Client> C<worker>. Both are using L<OAuth2 protocol|https://oauth.net/2/> to perform authentication. The third default target, C<App::SpreadRevolutionaryDate::Target::Freenode>, uses a L<chatbot|https://en.wikipedia.org/wiki/Chatbot>: L<App::SpreadRevolutionaryDate::Target::Freenode::Bot> subclassing L<Bot::BasicBot>. You can also see a very simple example with a test file provided in this distribution at C<t/new_target.t>, which just prints out the revolutionary date on the standard output using core module L<IO::Handle>.

=head1 EXTENDING TO NEW MESSAGE MAKERS

It is even easier to spread whatever you want instead of the revolutionary date. You should write a new class in the C<App::SpreadRevolutionaryDate::MsgMaker::> namespace (that is: the class should be C<App::SpreadRevolutionaryDate::MsgMaker::MyMsgMaker> for a new C<MyMsgMaker> message maker), that consumes the L<App::SpreadRevolutionaryDate::MsgMaker> role. See L<App::SpreadRevolutionaryDate::MsgMaker/DESCRIPTION> for a comprehensive description of this role.

The name of the message maker should be set as a value of the L</msgmaker> option in lower case.

Such a message maker class is actually just a wrapper. Usually a message maker has to use an existing specific module (which can be a C<Moose> class or not) to craft the message. L<App::SpreadRevolutionaryDate::Target::MsgMaker::RevolutionaryDate> uses L<DateTime::Calendar::FrenchRevolutionary>, while L<App::SpreadRevolutionaryDate::Target::MsgMaker::PromptUser> is based on L<IO::Prompt::Hooked>. You may need for example L<LWP> to extract the message from a fetched web page or service, or L<XML::Feed> to build it from a L<RSS|https://en.wikipedia.org/wiki/RSS> feed, or L<DBI> to retrieve it from a database, or nothing at all to spread a fixed message, etc.

If your new message maker class needs specific parameters (other than C<locale>, which comes with  L<App::SpreadRevolutionaryDate::MsgMaker> role), they should be defined as attributes of this class. Values for such attributes should be set in the L<configuration file|/CONFIGURATION>, inside a section named after the message maker in lower case (C<[mymsgmaker]>), or as L<command line parameters|/"COMMAND LINE PARAMETERS"> prefixed with the name of the message maker in lower case, followed by an underscore (C<--mytarget_myparam>).

Have a look to the L<App::SpreadRevolutionaryDate::Target::MsgMaker::PromptUser> class, it shows a simple example on how to extend C<spread-revolutionary-date> to a new message maker.

=head1 SEE ALSO

=over

=item L<App::SpreadRevolutionaryDate>

=item L<DateTime::Calendar::FrenchRevolutionary>

=item L<AppConfig>

=item L<Net::Twitter::Lite::WithAPIv1_1>

=item L<Mastodon::Client>

=item L<Bot::BasicBot>

=back

=head1 AUTHOR

Gérald Sédrati-Dinet <gibus@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2019 by Gérald Sédrati-Dinet.

This is free software, licensed under:

  The GNU General Public License, Version 3, June 2007

=cut
