""" Implementation of commands to insert freesites.

    Copyright (C) 2009 Darrell Karbott

    This library 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.0 of the License, or (at your option) any later version.

    This library 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 library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

    Author: djk@isFiaD04zgAgnrEC5XJt1i4IE7AkNPqhBG5bONi6Yks
"""


import os

from ConfigParser import ConfigParser

from mercurial import util

from fcpconnection import FCPError
from fcpclient import FCPClient, get_file_infos, set_index_file

def write_default_config(ui_, repo):
    """ Write a default freesite.cfg file into the repository root dir. """
    file_name = os.path.join(repo.root, 'freesite.cfg')

    if os.path.exists(file_name):
        raise util.Abort("Already exists: %s" % file_name)

    out_file = open(file_name, 'w')
    try:
        out_file.write("""[default]
# Human readable site name.
site_name = default
# Directory to insert from relative to the repository root.
site_dir = site_root
# Optional external file to load the site key from, relative
# to the directory your .infocalypse/infocalypse.ini file
# is stored in. This file should contain ONLY the SSK insert
# key up to the first slash.
#
# If this value is not set the insert SSK for the repo is
# used.
#site_key_file = example_freesite_key.txt
#
# Optional file to display by default.  If this is not
# set index.html is used.
#default_file = index.html
""")
    finally:
        out_file.close()

    ui_.status('Created config file:\n%s\n' % file_name)
    ui_.status('You probably want to edit at least the site_name.\n')

def read_freesite_cfg(ui_, repo, params, stored_cfg):
    """ Read param out of the freesite.cfg file. """
    cfg_file = os.path.join(repo.root, 'freesite.cfg')

    ui_.status('Using config file:\n%s\n' % cfg_file)
    if not os.path.exists(cfg_file):
        ui_.warn("Can't read: %s\n" % cfg_file)
        raise util.Abort("Use --createconfig to create freesite.cfg")

    parser = ConfigParser()
    parser.read(cfg_file)
    if not parser.has_section('default'):
        raise util.Abort("Can't read default section of config file?")

    params['SITE_NAME'] = parser.get('default', 'site_name')
    params['SITE_DIR'] = parser.get('default', 'site_dir')
    if parser.has_option('default','default_file'):
        params['SITE_DEFAULT_FILE'] = parser.get('default', 'default_file')
    else:
        params['SITE_DEFAULT_FILE'] = 'index.html'

    if params.get('SITE_KEY'):
        return # key set on command line

    if not parser.has_option('default','site_key_file'):
        params['SITE_KEY'] = ''
        return # Will use the insert SSK for the repo.

    key_file = parser.get('default', 'site_key_file', 'default')
    if key_file == 'default':
        ui_.status('Using repo insert key as site key.\n')
        params['SITE_KEY'] = 'default'
        return # Use the insert SSK for the repo.
    try:
        # Read private key from specified key file relative
        # to the directory the .infocalypse config file is stored in.
        key_file = os.path.join(os.path.dirname(stored_cfg.file_name),
                                key_file)
        ui_.status('Reading site key from:\n%s\n' % key_file)
        params['SITE_KEY'] = open(key_file, 'rb').read().strip()
    except IOError:
        raise util.Abort("Couldn't read site key from: %s" % key_file)

    if not params['SITE_KEY'].startswith('SSK@'):
        raise util.Abort("Stored site key not an SSK?")

def get_insert_uri(params):
    """ Helper function builds the insert URI. """
    if params['SITE_KEY'] == 'CHK@':
        return 'CHK@/'
    return '%s/%s-%i/' % (params['SITE_KEY'],
                          params['SITE_NAME'], params['SITE_INDEX'])

# Convert SSK to USK so n00b5 don't phr34k out.
def show_request_uri(ui_, params, uri):
    """ Helper function to print the request URI."""
    if uri.startswith('SSK@'):
        request_uri = 'U%s/%s/%i/' % (uri.split('/')[0][1:],
                                      params['SITE_NAME'],
                                      params['SITE_INDEX'])
    else:
        request_uri = uri
    ui_.status('RequestURI:\n%s\n' % request_uri)

def execute_putsite(ui_, repo, params):
    """ Run the putsite command. """
    def progress(dummy, msg):
        """ Message callback which writes to the hg ui instance."""

        if msg[0] == 'SimpleProgress':
            ui_.status("Progress: (%s/%s/%s)\n" % (msg[1]['Succeeded'],
                                                   msg[1]['Required'],
                                                   msg[1]['Total']))
        else:
            ui_.status("Progress: %s\n" % msg[0])


    if params.get('SITE_CREATE_CONFIG', False):
        write_default_config(ui_, repo)
        return

    # Remove trailing /
    params['SITE_KEY'] = params['SITE_KEY'].split('/')[0].strip()
    insert_uri = get_insert_uri(params)
    site_root = os.path.join(repo.root, params['SITE_DIR'])

    ui_.status('Default file: %s\n' % params['SITE_DEFAULT_FILE'])
    ui_.status('Reading files from:\n%s\n' % site_root)

    infos = get_file_infos(site_root)

    try:
        set_index_file(infos, params['SITE_DEFAULT_FILE'])
    except ValueError:
        raise util.Abort("Couldn't read %s" % params['SITE_DEFAULT_FILE'])

    ui_.status('--- files ---\n')

    for info in infos:
        ui_.status('%s %s\n' % (info[0], info[1]))
    ui_.status('---\n')

    if params['DRYRUN']:
        ui_.status('Would have inserted to:\n%s\n' % insert_uri)
        ui_.status('But --dryrun was set.\n')
        return

    client = FCPClient.connect(params['FCP_HOST'],
                               params['FCP_PORT'])
    client.in_params.default_fcp_params['DontCompress'] = False
    client.message_callback = progress
    try:
        ui_.status('Inserting to:\n%s\n' % insert_uri)
        try:
            request_uri = client.put_complex_dir(insert_uri, infos)[1]['URI']
            show_request_uri(ui_, params, request_uri)
        except FCPError, err:
            if err.is_code(9): # magick number for collision
                ui_.warn('An update was already inserted on that index.\n'
                         + 'Set a later index with --index and try again.\n')
                raise util.Abort("Key collision.")
            else:
                ui_.warn(str(err) + '\n')
                raise util.Abort("FCP Error")
    finally:
        client.close()

MSG_FMT = """InsertURI:
%s
RequestURI:
%s

This is what you need to put in a site_key_file file:
%s
"""

def execute_genkey(ui_, params):
    """ Run the genkey command. """
    client = FCPClient.connect(params['FCP_HOST'],
                               params['FCP_PORT'])

    client.message_callback = lambda x, y : None # silence.
    resp = client.generate_ssk()
    ui_.status(MSG_FMT % (resp[1]['InsertURI'], resp[1]['RequestURI'],
                          resp[1]['InsertURI'].split('/')[0] +'/'))