#! /usr/bin/env python2

"""
Usage example:

$ mng load data.json --db=mydb --name=myspace
$ mng drill category=Electronics
Electronics/Television & Video
Electronics/Computers
Electronics/Camera & Photo
$ mng dice category="Electronics/Television & Video"
category    total
Electronics/Television & Video  20.0
Electronics/Computers  10.0
Electronics/Camera & Photo      30.0
"""

import ConfigParser
import argparse
import json
import os
from itertools import chain, izip

from menger import build_space, backend, measure
from menger.space import UserError

class Cli(object):

    def __init__(self, action=[], db='mng.db', name='Space'):
        self.action = action[0]
        self.action_args = action[1:]
        self.uri = db
        self.name = name

    def connect(self, data_point=None):
        if data_point is None:
            bckd = backend.get_backend(self.uri)
            self.space = bckd.build_space(self.name)
        else:
            self.space = build_space(data_point, self.name)
        return self.space.connect(self.uri)

    def do_dice(self):
        with self.connect():
            args = list(self.split_args())

            # Pre-fill args without values
            for pos, (name, values) in enumerate(args):
                if not values:
                    args[pos] =  (name, ('*',))

            # Add measures if none is provided
            with_msr = False
            for name, _ in args:
                if not hasattr(self.space, name):
                    continue
                if isinstance(getattr(self.space, name), measure.Measure):
                    with_msr = True
                    break
            if not with_msr:
                args.extend([(m.name, None) for m in self.space._measures])

            # Query DB
            try:
                results = self.space.dice(args)
            except UserError, e:
                print 'Error:', e
                return

            # Output columns
            cols = list(n for n,_ in args)
            print '\t'.join(cols)

            # Output Results
            for res in results:
                for c in cols:
                    if isinstance(res[c], tuple):
                        res[c] = '/'.join(map(str, res[c]))
                print '\t'.join(str(res[c]) for c in cols)

    def do_drill(self):
        with self.connect():
            for name, values in self.split_args():
                self.drill(name, values)

    def do_info(self):
        with self.connect():
            print 'Dimensions'
            for dim in self.space._dimensions:
                print ' ' + dim.name
            print 'Measures'
            for msr in self.space._measures:
                print ' ' + msr.name

    def drill(self, name, values):
        if not hasattr(self.space, name):
            exit('"%s" has no dimension "%s"' % (
                    self.space._name, name))

        dim = getattr(self.space, name)
        for name in dim.drill(values):
            print '/'.join(values + (name,))

    def do_load(self):
        for path in self.action_args:
            fh = open(path)
            first = next(fh, "").strip()
            if not first:
                print 'File %s ignored' % path
                continue
            first = json.loads(first)

            with self.connect(first):
                self.space.load([first])
                self.space.load((json.loads(l.strip()) for l in fh))
                fh.close()

    def split_args(self):
        for arg in self.action_args:
            if '=' in arg:
                name, values = arg.split('=')
                values = tuple(values.split('/'))
                if not hasattr(self.space, name):
                    exit('"%s" has no dimension "%s"' % (
                            self.space._name, name))

                dim = getattr(self.space, name)

                if dim.type == 'integer':
                    values = tuple(v if v == '*' else int(v) for v in values)
            else:
                name = arg
                values = tuple()
            yield name, values

def main():

    parser = argparse.ArgumentParser(description='Menger CLI.')

    parser.add_argument('action', help='drill, dice, info or load', nargs='+')
    parser.add_argument('--db', '-d', help='Database URI', default="mng.db")
    parser.add_argument('--name', '-n', help='Space name', default="Space")

    config_args = {}
    if os.path.exists('.mng'):
        config = ConfigParser.ConfigParser()
        config.read('.mng')
        config_args.update(config.items('default'))

    parse_args = parser.parse_args()

    args = {}
    for key in ('db', 'name', 'action'):
        args[key] = config_args.get(key) or getattr(parse_args, key) #FIXME cli options should taks precedence on config file

    cli = Cli(**args)
    if not hasattr(cli, 'do_' + cli.action):
        exit('Unkown action "%s"' % cli.action)
    getattr(cli, 'do_' + cli.action)()


if __name__ == '__main__':
    main()
