#! /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 fetch 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

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)
            bckd.close()
        else:
            self.space = build_space(data_point, self.name)
        return self.space.connect(self.uri)

    def do_fetch(self):
        with self.connect():
            point = {}
            query_dims = []
            for name, values in self.split_args():
                point[name] = values
                query_dims.append(name)

            print '\t'.join(chain(
                    query_dims,
                    (m for m, _ in self.space._measures)
                    ))

            for res in self.space.dice(point, skipzero=True):
                dims = ('/'.join(map(str, res[d])) for d in query_dims)
                msrs = (str(res[m]) for m, _ in self.space._measures)
                print '\t'.join(chain(dims, msrs))

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

    def drill(self, name, values):
        dim = getattr(self.space, name)
        for sibling in dim.explode(values):
            for res in dim.drill(sibling):
                print '/'.join(map(str, res))

    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, fetch 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)

    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()
