#!/usr/bin/python3 -tt
#
# Manage virtual machines' disks
#
# Copyright 2007 Novell, Inc.
# Authors: Charles Coffing <ccoffing@novell.com>
#          Mike Fritch <mgfritch@novell.com>
#
# This software may be freely redistributed under the terms of the GNU
# general public license.
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 

from __future__ import print_function
from optparse import OptionParser
import os
import sys

#os.environ['PYCHECKER'] = '--stdlib'
#import pychecker.checker

from vmdisks.diskmap import DiskMap
import vminstall.msg


def list_disks(args):
    # FIXME: clean up python doc comment
    """
    %{PDEV} - Physical device name of the disk
    %{PSIZE} - Physical (actual) disk size in 512-byte blocks 
    %{VSIZE} - Virtual disk size in 512-byte blocks
    %{PSIZE_MB} - Physical (actual) disk size in megabytes (MB)
    %{VSIZE_MB} - Virtual disk size in megabytes (MB)
    %{PTYPE} - Physical type (e.g. file | phy | iscsi)
    %{VTYPE} - Virtual type (e.g. cdrom | disk)
    %{MODE} - read | write
    %{VM_NAME} - Name of the virtual machine that contains the disk image
    %{VM_UUID} - UUID of the virtual machine that contains the disk image
    """
 
#    disk_map = {
#        'file:/var/lib/xen/images/sles10/disk0':((<disk object>, <vmdef object>), (<disk object>, <vmdef object>)),
#        'phy:/dev/hda':((<disk object>, <vmdef object>))
#    }

    disk_map = DiskMap().disk_map
    format_line = '%-40{PDEV} %-7{VTYPE} %-8{PSIZE_MB} %-12{VM_NAME}\n'
    if args:
        format_line = args[0]

    # figure out any escaped strings (e.g. \t, \n, etc.)
    format_line = format_line.decode('string_escape')       

    # prep the format_line and figure out the format order
    format_types = ['{PDEV}', '{PSIZE}', '{VSIZE}', '{PSIZE_MB}', '{VSIZE_MB}', '{VTYPE}', '{PTYPE}', '{MODE}', '{VM_NAME}', '{VM_UUID}']
    format_order = []

    class Done:
        pass
    class Index:
        def __init__(self):
            self.index = 0 # current index in string
            self.percent_index = None # last index of percent '%' char
        def advance(self, n=1):
            if self.index+n < len(format_line):
                self.index += n
            else:
                raise Done()

    index = Index()

    try:
        while index.index < len(format_line):
            if format_line[index.index] is '%':
                index.percent_index = index.index
                index.advance()
                if format_line[index.index] != '%':
                    if format_line[index.index] in ('-', '+'):
                        index.advance();
                    while format_line[index.index].isdigit():
                        index.advance()
                    if format_line[index.index] is '.':
                        index.advance()
                    while format_line[index.index].isdigit():
                        index.advance()
                    for prefix in format_types:
                        if format_line[index.index:].startswith(prefix):
                            format_order.append(prefix)
                            format_line = format_line[:index.index] + 's' + format_line[index.index+len(prefix):]
                            index.percent_index = None
                            break
                if index.percent_index != None:
                    # Did not match a format_type, escape the '%' char
                    format_line = format_line[:index.percent_index] + '%' + format_line[index.percent_index:]
                    index.percent_index = None
            index.advance()
    except Done:
        if index.percent_index != None:
            # Did not match a format_type, escape the '%' char
            format_line = format_line[:index.percent_index] + '%' + format_line[index.percent_index:]

    # Generate the output
    for k in disk_map.keys():
        for i in disk_map[k]:
            # i[0] == VMDisk
            # i[1] == VMDef
            format_values = []
            for format_type in format_order:
                s = ''
                if format_type is '{PDEV}':
                    s = k
                elif format_type is '{PSIZE}':
                    blocks = i[0].get_size()
                    if blocks is not None:
                        s = str(blocks)
                elif format_type is '{VSIZE}':
                    blocks = i[0].get_virtual_size()
                    if blocks is not None:
                        s = str(blocks)
                elif format_type is '{PSIZE_MB}':
                    blocks = i[0].get_size()
                    if blocks is not None:
                        s = str(blocks/(2*1024.0))
                elif format_type is '{VSIZE_MB}':
                    blocks = i[0].get_virtual_size()
                    if blocks is not None:
                        s = str(blocks/(2*1024.0))
                elif format_type is '{VTYPE}':
                    s = i[0].get_vdevtype()
                elif format_type is '{PTYPE}':
                    s = i[0].get_proto()
                elif format_type is '{MODE}':
                    if i[0].get_ro():
                        s = 'ro'
                    else:
                        s = 'rw'
                elif format_type is '{VM_NAME}':
                    if i[1]:
                        s = i[1].name
                elif format_type is '{VM_UUID}':
                    if i[1]:
                        s = i[1].uuid
                format_values.append(s)
            sys.stdout.write(format_line % tuple(format_values))


if __name__ == "__main__":
    parser = OptionParser(description="""Manages virtual machine disk images.  Consult the man page for complete usage and examples.""")

    parser.add_option('-l', '--list', action='store_true', dest='list',
                      help="list disk images")
    parser.add_option('-m', '--manage', type='string',
                      help="manage a disk image", metavar="PDEV")
    parser.add_option('-u', '--unmanage', type='string',
                      help="un-manage a disk image", metavar="PDEV")
    parser.add_option('-c', '--create', action='store_true', dest='create',
                      help="create a disk image")
    parser.add_option('-d', '--delete', type='string',
                      help="delete a disk image", metavar="PDEV")

    (options, args) = parser.parse_args()

    try:
        if options.list:
            list_disks(args)
        elif options.manage:
            DiskMap().manage(options.manage)
        elif options.unmanage:
            DiskMap().unmanage(options.unmanage)
        elif options.create:
#            DiskMap().create(options.create)
            print('FIXME: CLI create disk...')
        elif options.delete:
            DiskMap().delete(options.delete)
        elif 'DISPLAY' in os.environ:
            import vmdisks.gtk
            vmdisks.gtk.run()
    except:
        raise
#    except KeyboardInterrupt:
#        sys.stderr.write('%s\n' % (vminstall.msg.aborted))
#        sys.exit(1)
#    except Exception, e:
#        sys.stderr.write('%s: %s\n' % (vminstall.msg.error, str(e)))
#        sys.exit(1)

    # FIXME:
    # GUI may have other threads going.  Tear down.
    # May still be creating disk image; tear down.
