#!/usr/bin/python3
#
# This file is part of Plinth.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

"""
Configuration helper for ikiwiki
"""

import argparse
import os
import shutil
import subprocess


CONFIG_ENABLE = '/etc/apache2/conf-enabled/ikiwiki.conf'
CONFIG_FILE = '/etc/apache2/conf-available/ikiwiki.conf'
SETUP_WIKI = '/etc/ikiwiki/plinth-wiki.setup'
SETUP_BLOG = '/etc/ikiwiki/plinth-blog.setup'
SITE_PATH = '/var/www/ikiwiki'
WIKI_PATH = '/var/lib/ikiwiki'

apache_cgi_configuration = '''
Alias /ikiwiki /var/www/ikiwiki
AddHandler cgi-script .cgi

<Directory /var/www/ikiwiki>
    Options +ExecCGI
</Directory>
'''

ikiwiki_setup_automator = '''
#!/usr/bin/perl
# Ikiwiki setup automator for Plinth.

require IkiWiki::Setup::Automator;

our $wikiname=$ARGV[0];
our $admin=$ARGV[1];
if (($wikiname eq "") || ($admin eq "")) {
	print "Usage: ikiwiki -setup /etc/ikiwiki/plinth-wiki.setup wiki_name admin_name";
	exit;
}

our $wikiname_short=IkiWiki::Setup::Automator::sanitize_wikiname($wikiname);

IkiWiki::Setup::Automator->import(
	wikiname => $wikiname,
	adminuser => [$admin],
	rcs => "git",
	srcdir => "/var/lib/ikiwiki/$wikiname_short",
	destdir => "/var/www/ikiwiki/$wikiname_short",
	repository => "/var/lib/ikiwiki/$wikiname_short.git",
	dumpsetup => "/var/lib/ikiwiki/$wikiname_short.setup",
	url => "/ikiwiki/$wikiname_short",
	cgiurl => "/ikiwiki/$wikiname_short/ikiwiki.cgi",
	cgi_wrapper => "/var/www/ikiwiki/$wikiname_short/ikiwiki.cgi",
	add_plugins => [qw{goodstuff websetup httpauth}],
	rss => 1,
	atom => 1,
	syslog => 1,
)
'''

ikiwiki_setup_automator_blog = '''
#!/usr/bin/perl
# Ikiwiki setup automator for Plinth (blog version).

require IkiWiki::Setup::Automator;

our $wikiname=$ARGV[0];
our $admin=$ARGV[1];
if (($wikiname eq "") || ($admin eq "")) {
	print "Usage: ikiwiki -setup /etc/ikiwiki/plinth-blog.setup blog_name admin_name";
	exit;
}

our $wikiname_short=IkiWiki::Setup::Automator::sanitize_wikiname($wikiname);

IkiWiki::Setup::Automator->import(
	wikiname => $wikiname,
	adminuser => [$admin],
	rcs => "git",
	srcdir => "/var/lib/ikiwiki/$wikiname_short",
	destdir => "/var/www/ikiwiki/$wikiname_short",
	repository => "/var/lib/ikiwiki/$wikiname_short.git",
	dumpsetup => "/var/lib/ikiwiki/$wikiname_short.setup",
	url => "/ikiwiki/$wikiname_short",
	cgiurl => "/ikiwiki/$wikiname_short/ikiwiki.cgi",
	cgi_wrapper => "/var/www/ikiwiki/$wikiname_short/ikiwiki.cgi",
	add_plugins => [qw{goodstuff websetup comments calendar sidebar trail httpauth}],
	rss => 1,
	atom => 1,
	syslog => 1,
	example => "blog",
	comments_pagespec => "posts/* and !*/Discussion",
	archive_pagespec => "page(posts/*) and !*/Discussion",
	global_sidebars => 0,
	discussion => 0,
	tagbase => "tags",
)
'''

def parse_arguments():
    """Return parsed command line arguments as dictionary."""
    parser = argparse.ArgumentParser()
    subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')

    # Setup ikiwiki site
    subparsers.add_parser('setup', help='Perform first time setup operations')

    # Get whether ikiwiki site is enabled
    subparsers.add_parser('get-enabled',
                          help='Get whether ikiwiki site is enabled')

    # Enable ikiwiki site
    subparsers.add_parser('enable', help='Enable ikiwiki site')

    # Disable ikiwiki site
    subparsers.add_parser('disable', help='Disable ikiwiki site')

    # Get wikis and blogs
    subparsers.add_parser('get-sites', help='Get wikis and blogs')

    # Create a wiki
    create_wiki = subparsers.add_parser('create-wiki', help='Create a wiki')
    create_wiki.add_argument('--wiki_name', help='Name of new wiki')
    create_wiki.add_argument('--admin_name', help='Administrator account name')
    create_wiki.add_argument('--admin_password',
                             help='Administrator account password')

    # Create a blog
    create_blog = subparsers.add_parser('create-blog', help='Create a blog')
    create_blog.add_argument('--blog_name', help='Name of new blog')
    create_blog.add_argument('--admin_name', help='Administrator account name')
    create_blog.add_argument('--admin_password',
                             help='Administrator account password')

    # Delete a wiki or blog
    delete = subparsers.add_parser('delete', help='Delete a wiki or blog.')
    delete.add_argument('--name', help='Name of wiki or blog to delete.')

    return parser.parse_args()


def subcommand_setup(_):
    """Perform first time setup operations."""
    setup()


def subcommand_get_enabled(_):
    """Get whether ikiwiki site is enabled."""
    if os.path.isfile(CONFIG_ENABLE):
        print('yes')
    else:
        print('no')


def subcommand_enable(_):
    """Enable ikiwiki site."""
    subprocess.check_call(['a2enconf', 'ikiwiki'])
    subprocess.check_call(['service', 'apache2', 'reload'])


def subcommand_disable(_):
    """Disable ikiwiki site."""
    subprocess.check_call(['a2disconf', 'ikiwiki'])
    subprocess.check_call(['service', 'apache2', 'reload'])


def subcommand_get_sites(_):
    """Get wikis and blogs."""
    try:
        sites = os.listdir(SITE_PATH)
        print('\n'.join(sites))
    except FileNotFoundError:
        pass


def subcommand_create_wiki(arguments):
    """Create a wiki."""
    pw_bytes = arguments.admin_password.encode()
    proc = subprocess.Popen(
        ['ikiwiki', '-setup', SETUP_WIKI,
         arguments.wiki_name, arguments.admin_name],
        stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
    outs, errs = proc.communicate(input=pw_bytes + b'\n' + pw_bytes)
    print(outs)
    print(errs)


def subcommand_create_blog(arguments):
    """Create a blog."""
    pw_bytes = arguments.admin_password.encode()
    proc = subprocess.Popen(
        ['ikiwiki', '-setup', SETUP_BLOG,
         arguments.blog_name, arguments.admin_name],
        stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
    outs, errs = proc.communicate(input=pw_bytes + b'\n' + pw_bytes)
    print(outs)
    print(errs)


def subcommand_delete(arguments):
    """Delete a wiki or blog."""
    html_folder = os.path.join(SITE_PATH, arguments.name)
    wiki_folder = os.path.join(WIKI_PATH, arguments.name)

    try:
        shutil.rmtree(html_folder)
        shutil.rmtree(wiki_folder)
        shutil.rmtree(wiki_folder + '.git')
        os.remove(wiki_folder + '.setup')
        print('Deleted {0}'.format(arguments.name))
    except FileNotFoundError:
        print('Error: {0} not found.'.format(arguments.name))
        exit(1)


def setup():
    """Write Apache configuration and wiki/blog setup scripts."""
    if not os.path.exists(SITE_PATH):
        os.makedirs(SITE_PATH)

    subprocess.check_call(['a2enmod', 'cgi'])

    with open(CONFIG_FILE, 'w') as conffile:
        conffile.write(apache_cgi_configuration)

    with open(SETUP_WIKI, 'w') as setupfile:
        setupfile.writelines(ikiwiki_setup_automator)

    with open(SETUP_BLOG, 'w') as setupfile:
        setupfile.writelines(ikiwiki_setup_automator_blog)

    subprocess.check_call(['service', 'apache2', 'restart'])


def main():
    """Parse arguments and perform all duties."""
    arguments = parse_arguments()

    subcommand = arguments.subcommand.replace('-', '_')
    subcommand_method = globals()['subcommand_' + subcommand]
    subcommand_method(arguments)


if __name__ == '__main__':
    main()
