#!/usr/bin/env python
# Copyright (C) 2010 Samuel Abels.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2, as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
import os
import sys
import time
import codecs
from optparse  import OptionParser
from Exscript  import __version__
from Exscriptd import Client, Order

parser = OptionParser(usage   = '%prog [options] ip[:port] [filename]',
                      version = __version__)
parser.add_option('--user', '-u',
                  dest    = 'user',
                  metavar = 'STRING',
                  help    = '''
The username on the server.
'''.strip())
parser.add_option('--password', '-p',
                  dest    = 'password',
                  metavar = 'STRING',
                  help    = '''
The password on the server.
'''.strip())
parser.add_option('--wait', '-w',
                  dest    = 'wait',
                  action  = 'store_true',
                  default = False,
                  help    = '''
After placing the order, wait until it is completed.
'''.strip())
parser.add_option('--csv',
                  dest    = 'csv',
                  action  = 'store_true',
                  default = False,
                  help    = '''
The order is using CSV format.
'''.strip())
parser.add_option('--encoding',
                  dest    = 'encoding',
                  metavar = 'STRING',
                  default = 'utf-8',
                  help    = '''
The encoding of the input file when using --csv. Defaults to utf8.
'''.strip())
parser.add_option('--service',
                  dest    = 'service',
                  metavar = 'STRING',
                  help    = '''
Send to the service with the given name, instead of
the service that is specified in the order.
'''.strip())
parser.add_option('--status', '-s',
                  dest    = 'status',
                  metavar = 'STRING',
                  help    = '''
Prints the status of the order with the given id and exit.
'''.strip())
parser.add_option('--test',
                  dest    = 'test',
                  action  = 'store_true',
                  default = False,
                  help    = '''
Print the XML formatted order to stdout.
'''.strip())
parser.add_option('--order-get',
                  dest    = 'order_get',
                  metavar = 'INTEGER',
                  help    = '''
Prints the order with the given id.
'''.strip())
parser.add_option('--order-count',
                  dest    = 'order_count',
                  action  = 'store_true',
                  default = False,
                  help    = '''
Prints the total number of orders.
'''.strip())
parser.add_option('--order-list',
                  dest    = 'order_list',
                  action  = 'store_true',
                  default = False,
                  help    = '''
Lists the last 50 orders.
'''.strip())
parser.add_option('--task-get',
                  dest    = 'task_get',
                  metavar = 'INTEGER',
                  help    = '''
Prints the task with the given id.
'''.strip())
parser.add_option('--task-count',
                  dest    = 'task_count',
                  metavar = 'INTEGER',
                  help    = '''
Prints the number of tasks in the order with the given id.
'''.strip())
parser.add_option('--task-list',
                  dest    = 'task_list',
                  metavar = 'INTEGER',
                  help    = '''
Lists the last 50 tasks of the order with the given id.
'''.strip())
parser.add_option('--quite', '-q',
                  dest    = 'quite',
                  action  = 'store_true',
                  default = False,
                  help    = '''
Do not write anything to stdout.
'''.strip())

# Parse options.
options, args = parser.parse_args(sys.argv)
args.pop(0)

if not options.test:
    if not options.user:
        parser.error('Required option --user not set')
    if not options.password:
        parser.error('Required option --password not set')

try:
    address = args.pop(0)
except IndexError:
    parser.error('ip argument missing')

if options.status:
    pass
elif options.order_get:
    pass
elif options.order_count:
    pass
elif options.order_list:
    pass
elif options.task_get:
    pass
elif options.task_count:
    pass
elif options.task_list:
    pass
else:
    try:
        filename = args.pop(0)
    except IndexError:
        parser.error('order argument missing')

if args:
    parser.error('too many arguments')

def say(*args):
    if not options.quite:
        sys.stdout.write(' '.join(str(a) for a in args) + '\n')

def print_table(rows):
    if not rows:
        return
    widths = [1 for h in rows[0]]
    for row in rows:
        for n, col in enumerate(row):
            widths[n] = max(widths[n], len(str(col)) + 2)
    for i, row in enumerate(rows):
        for n, col in enumerate(row):
            sys.stdout.write(str(col).ljust(widths[n]))
        print
        if i == 0:
            print '-' * sum(widths)

client = Client(address, options.user, options.password)

if options.status:
    status, progress, closed = client.get_order_status_from_id(options.status)
    print status, '%.1f%%' % (progress * 100.0), closed
    sys.exit(0)
elif options.order_get:
    order = client.get_order_from_id(int(options.order_get))
    print 'ID:',          order.get_id()
    print 'Service:',     order.get_service_name()
    print 'Status:',      order.get_status()
    print 'Description:', order.get_description()
    print 'Created by:',  order.get_created_by()
    print 'Created:',     order.get_created_timestamp()
    print 'Closed:',      order.get_closed_timestamp()
    sys.exit(0)
elif options.order_count:
    print client.count_orders()
    sys.exit(0)
elif options.order_list:
    rows = [('OrderID',
             'Service',
             'Description',
             'Status',
             'Progress',
             'Created by',
             'Created',
             'Closed')]
    for order in client.get_order_list(offset = 0, limit = 100):
        row = (order.get_id(),
               order.get_service_name(),
               order.get_description(),
               order.get_status(),
               order.get_progress_percent(),
               order.get_created_by(),
               str(order.get_created_timestamp()),
               str(order.get_closed_timestamp() or 'open'))
        rows.append(row)
    print_table(rows)
    sys.exit(0)
elif options.task_get:
    task = client.get_task_from_id(int(options.task_get))
    print 'ID:',         task.get_id()
    print 'Name:',       task.get_name()
    print 'Status:',     task.get_status()
    print 'Started:',    task.get_started_timestamp()
    print 'Closed:',     task.get_closed_timestamp()
    print 'Logfile:',    task.get_logfile()
    print 'Trace file:', task.get_tracefile()
    sys.exit(0)
elif options.task_count:
    print client.count_tasks(int(options.task_count))
    sys.exit(0)
elif options.task_list:
    rows = [('TaskID',
             'Name',
             'Status',
             'Progress',
             'Started',
             'Closed')]
    for task in client.get_task_list(int(options.task_list), 0, 100):
        row = (task.get_id(),
               task.get_name(),
               task.get_status(),
               '%.1f' % (task.get_progress() * 100.0),
               str(task.get_started_timestamp()),
               str(task.get_closed_timestamp() or 'open'))
        rows.append(row)
    print_table(rows)
    sys.exit(0)

try:
    codecs.lookup(options.encoding)
except LookupError:
    parser.error('no such encoding: ' + str(options.encoding))

if options.csv:
    if not options.service:
        parser.error('Need --service when using --csv.')
    order = Order.from_csv_file(options.service, filename, options.encoding)
else:
    order = Order.from_xml_file(filename)
    if options.service:
        order.set_service_name(options.service)

if options.test:
    print order.toxml()
    sys.exit(0)

client.place_order(order)
say('Placed order', order.id)

if options.wait:
    while True:
        status, progress, closed = client.get_order_status_from_id(order.id)
        say('Status:', status)
        if closed is not None:
            print 'Order', order.id, 'closed',
            print 'in status', status, 'on', str(closed) + '.'
            break
        time.sleep(1)
