#!/usr/bin/env python

"""Fiona command line interface"""

import code
import json
import logging
import pprint
import sys
import warnings

import click
import six.moves

import fiona

FIELD_TYPES_MAP_REV = {v: k for k, v in fiona.FIELD_TYPES_MAP.items()}

warnings.simplefilter('default')

def configure_logging(verbosity):
    log_level = max(10, 30 - 10*verbosity)
    logging.basicConfig(stream=sys.stderr, level=log_level)

# The CLI command group.
@click.group(help="Fiona command line interface.")
@click.option('--verbose', '-v', count=True, help="Increase verbosity.")
@click.option('--quiet', '-q', count=True, help="Decrease verbosity.")
@click.pass_context
def cli(ctx, verbose, quiet):
    verbosity = verbose - quiet
    configure_logging(verbosity)
    ctx.obj = {}
    ctx.obj['verbosity'] = verbosity

# Commands are below.

# Info command.
@cli.command(short_help="Print information about a data file.")
@click.argument('src_path', type=click.Path(exists=True))
@click.option('--indent', default=2, type=int, 
              help="Indentation level for pretty printed output")
@click.pass_context
def info(ctx, src_path, indent):
    verbosity = ctx.obj['verbosity']
    logger = logging.getLogger('rio')
    try:
        with fiona.drivers(CPL_DEBUG=verbosity>2):
            with fiona.open(src_path) as src:
                output = src.meta
                output.update(bbox=src.bounds, count=len(src))
                pprint.pprint(output, indent=indent)
        sys.exit(0)
    except Exception:
        logger.exception("Failed. Exception caught")
        sys.exit(1)

# Insp command.
@cli.command(short_help="Open a data file and start an interpreter.")
@click.argument('src_path', type=click.Path(exists=True))
#@click.option('--mode', type=click.Choice(['r', 'r+']), default='r', help="File mode (default 'r').")
@click.pass_context
def insp(ctx, src_path):
    verbosity = ctx.obj['verbosity']
    logger = logging.getLogger('fio')
    try:
        with fiona.drivers(CPL_DEBUG=verbosity>2):
            with fiona.open(src_path) as src:
                code.interact(
                    'Fiona %s Interactive Inspector (Python %s)\n'
                    'Type "src.schema", "next(src)", or "help(src)" '
                    'for more information.' %  (
                        fiona.__version__, '.'.join(
                            map(str, sys.version_info[:3]))),
                    local=locals())
            sys.exit(0)
    except Exception:
        logger.exception("Failed. Exception caught")
        sys.exit(1)

# Translate command.
@cli.command(short_help="Translate GeoJSON to another vector format.")
@click.argument('input', type=click.File('r'), required=True)
@click.argument('dst_path', type=click.Path(), required=True)
@click.option('--driver', required=True, help="Output format driver name.")
@click.option('--x-json-seq/--x-json-obj', default=False,
              help="Read a LF-delimited JSON sequence (default is object). Experimental.")
@click.pass_context
def translate(ctx, input, dst_path, driver, x_json_seq):
    verbosity = ctx.obj['verbosity']
    logger = logging.getLogger('fio')
    try:
        if x_json_seq:
            feature_gen = six.moves.filter(
                lambda o: o.get('type') == 'Feature',
                map(json.loads, input))
        else:
            collection = json.load(input)
            feature_gen = iter(collection['features'])

        # Use schema of first feature as a template.
        # TODO: schema specified on command line?
        first = next(feature_gen)
        schema = {'geometry': first['geometry']['type']}
        schema['properties'] = {
            k: FIELD_TYPES_MAP_REV[type(v)]
            for k, v in first['properties'].items()}

        with fiona.drivers(CPL_DEBUG=verbosity>2):
            with fiona.open(
                    dst_path, 'w',
                    driver=driver,
                    crs={'init': 'epsg:4326'},
                    schema=schema) as dst:
                dst.write(first)
                dst.writerecords(feature_gen)
        sys.exit(0)
    except IOError:
        logger.info("IOError caught")
        sys.exit(0)
    except Exception:
        logger.exception("Failed. Exception caught")
        sys.exit(1)

if __name__ == '__main__':
    cli()
