#!/usr/bin/env python
import clustohttp
import jinja2

import difflib
import logging
import optparse
import socket
import sys

log = logging.getLogger('clusto-template')


def serversort(servers):
    return list(sorted(servers, key=lambda x: (x.datacenter, x.name)))


def do_template(template, outputfile, template_root, name):
    tenv = jinja2.Environment(trim_blocks=True,
        loader=jinja2.FileSystemLoader(template_root))
    tenv.filters['serversort'] = serversort

    clusto = clustohttp.ClustoProxy()

    server = clusto.get_by_name(name)
    log.debug('Templating for server %s with role %s', server, server.role)

    try:
        template = tenv.get_template(template)
    except jinja2.TemplateNotFound:
        raise ValueError('Unable to find template %s under root %s', template, template_root)

    output = template.render(server=server, clusto=clusto, set=set)

    if outputfile == '-':
        sys.stdout.write(output)
    else:
        try:
            with open(outputfile, 'r') as f:
                existing = f.read()
            if existing == output:
                log.info('Rendered template matches output file, not overwriting.')
                return 0
        except Exception:
            log.warning('Unable to read target file, assuming empty')
            existing = ''

        diff = difflib.context_diff([existing], [output], lineterm='\n')
        for line in diff:
            logging.debug(line)

        with open(outputfile, 'w') as fd:
            fd.write(output)
    return 0


def main():
    parser = optparse.OptionParser(
        usage='%prog [options] <template> <output file>')
    parser.add_option('-r', '--root', dest='template_root',
        default='/usr/share/python-clustoclient/templates',
        help='Absolute path to template directory')
    parser.add_option('-n', '--name', dest='name',
        default=socket.gethostname().split('.', 1)[0],
        help='Name of the clusto object to query attributes from. Default ' +
             'is this system\'s hostname without a domain part')
    parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
        help='Writes status messages and a diff to stderr if the output ' +
             'file differs from the existing file on disk')
    options, args = parser.parse_args()

    handler = logging.StreamHandler()
    handler.setLevel(logging.DEBUG if options.verbose else logging.WARNING)
    handler.setFormatter(logging.Formatter('%(levelname)s %(message)s'))
    log.setLevel(logging.DEBUG if options.verbose else logging.WARNING)
    log.addHandler(handler)
    logging.getLogger('clustohttp').addHandler(handler)

    if len(args) < 2:
        parser.error('not enough args')
    template, outputfile = args[:2]

    try:
        return do_template(template, outputfile, options.template_root, options.name)
    except Exception:
        logging.exception('Failed to template')
        return 1


if __name__ == '__main__':
    sys.exit(main())
