#!/usr/bin/python

__version__='$Rev$'
__release__='0'

import sys, optparse, re

import mitsfs

parser = optparse.OptionParser(usage = 'usage: %prog [options]',
                               version = '%prog '+__version__)
parser.add_option('-i', '--inventory', dest='inventory',
                  help='Specify inventory to manipulate')

def main(args):
    global dex
    
    program = args[0] or 'invent'
    mitsfs.banner(program, __release__, __version__)
    dex = mitsfs.dexdb(client=program, dsn=mitsfs.database_dsn)

    options, args = parser.parse_args(args)

    set_inventory(options.inventory)

    try:
        mitsfs.menu([
            ('I', 'switch to a different Inventory', inventory_switch),
            ('L', 'List Boxes', listboxes),
            ('S', 'Show Box', showbox),
            ('E', 'Edit Box', editbox),
            ('F', 'mark as Found', markfound),
            ('Q', 'Quit', quit),
            ])
    except EOFError:
        pass

def quit(line):
    raise EOFError()

def inventory_switch(line):
    if not line:
        line = mitsfs.read('inventory? ',
                           history='inventory',
                           callback=lambda:  iter(dex.cursor.execute('select inventory_code from inventory')))
    print
    set_inventory(line.strip())

def set_inventory(inventory):
    global inventory_id
    
    if not inventory:
        q = ('select inventory_code, inventory_id, inventory_desc'
             ' from inventory order by inventory_stamp desc limit 1')
        a = ()
    else:
        q = ('select inventory_code, inventory_id, inventory_desc'
             ' from inventory where inventory_code=%s')
        a = (inventory,)

    ((inventory_code, inventory_id, inventory_desc),) = \
                      dex.cursor.execute(q, a)

    print 'Working on %s: %s' % (inventory_code, inventory_desc)
    
def showbox(box):
    q = dex.getcursor().execute
    if not box:
        box = mitsfs.read('box? ', history='box',
                          callback=lambda: iter(q('select distinct found_tag from inventory_found'
                                                  ' where inventory_id=%s and not inventory_reshelved', (inventory_id,))))
    if not box:
        return
    for (format, title_id) in \
        q('select format, title_id from inventory_found natural join format natural join pinkdex'
          ' where found_tag=%s and inventory_id=%s and not inventory_reshelved order by authors, titles', (box, inventory_id)):
        print '%3.3s' % format, mitsfs.title(dex, title_id)

def listboxes(line):
    print
    
    results = dex.cursor.execute(
        'select distinct found_tag, count(title_id) from inventory_found'
        ' where inventory_id=%s and not inventory_reshelved'
        ' group by found_tag order by found_tag',
        (inventory_id,)).fetchall()
    
    if len(results) == 0:
        print 'No boxes with anything in them.'
    else:
        results = [['label', 'items'],['------', '------']] + [[str(s) for s in l] for l in results]
        print mitsfs.tabulate(results)

def editbox(box):
    q = dex.getcursor().execute
    if not box:
        box = mitsfs.read('box? ', history='box',
                          callback=lambda: iter(q('select distinct found_tag from inventory_found'
                                                  ' where inventory_id=%s and not inventory_reshelved', (inventory_id,))))
    if not box:
        return
    books = q('select inventory_found_id, format, title_id, inventory_reshelved'
              ' from inventory_found natural join format natural join pinkdex'
              ' where found_tag=%s and inventory_id=%s'
              ' order by authors, titles', (box, inventory_id)).fetchall()
    for (index, (found_id, format, title_id, reshelved)) in enumerate(books):
        print '%3d. %-3.3s%s%s' % (index, format, ' ' if not reshelved else '*', mitsfs.title(dex, title_id))
    while True:
        n = mitsfs.read('#? ', history='booknum').strip()
        if not n:
            break
        try:
            n = int(n)
            found_id, format, title_id, reshelved = books[n]
        except:
            continue
        print mitsfs.title(dex, title_id)
        print format, 'reshelved' if reshelved else 'present'
        while True:
            x = mitsfs.read('toggle Reshelved or change Format: ', history='rorf').strip().upper()
            if x not in ('R', 'F'):
                continue
            if x == 'R':
                reshelved = not reshelved
                print 'now','reshelved' if reshelved else 'present'
                q('update inventory_found set inventory_reshelved = %s where inventory_found_id = %s',
                  (reshelved, found_id))
                dex.db.commit()
            elif x == 'F':
                while True:
                    f = mitsfs.read('format: ', history='rorf',
                                    callback=lambda: iter(q('select format from format'))).strip().upper()
                    try:
                        (format_id,) = q('select format_id from format where format=%s', f)
                    except:
                        continue
                    q('update inventory_found set format_id = %s where inventory_found_id = %s',
                      (format_id, found_id))
                    break
            break

def markfound(preload):
    q = dex.getcursor().execute

    if preload:
        preload = re.split(r'[`<]', preload)[:2]
        preload = mitsfs.propdict(authortxt = preload[0],
                                  titletxt = preload[1] if len(preload) > 1 else '')
    else:
        preload = None
    
    title = mitsfs.specify(dex, preload=preload)
    if not title:
        return

    missing = list(q('select inventory_entry_id, shelfcode, inventory_packet_name, missing_count'
                     ' from inventory_entry natural join shelfcode'
                     ' natural join inventory_missing natural join inventory_packet'
                     ' where inventory_id=%s and title_id=%s and missing',
                     (inventory_id, title.title_id)))

    if not len(missing):
        print 'Nothing found'
        print
        return

    if len(missing) == 1:
        row = missing[0]
    else:
        print mitsfs.tabulate([(str(n), shelfcode, packet, str(count))
                               for (n, (entry_id, shelfcode, packet, count))
                               in enumerate(missing)])
        print
        while True:
            n = mitsfs.read('#? ', callback=lambda: (str(x) for x in xrange(0, len(missing))))
            try:
                n = int(n)
                if not (0 <= n < len(missing)):
                    continue
            except ValueError:
                continue
        row = missing[n]

    entry_id, shelfcode, packet, count = row

    print shelfcode, packet, count, 'missing'
    if mitsfs.readyes('Mark as found? '):
        q('update inventory_missing set missing=false where inventory_entry_id=%s',
          (entry_id,))
        dex.db.commit()
        print 'done'
    print

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