#!/usr/bin/env python
#
#   ConVirt   -  Copyright (c) 2008 Convirture Corp.
#   ======
#
# ConVirt is a Virtualization management tool with a graphical user
# interface that allows for performing the standard set of VM operations
# (start, stop, pause, kill, shutdown, reboot, snapshot, etc...). It
# also attempts to simplify various aspects of VM lifecycle management.
#
#
# This software is subject to the GNU General Public License, Version 2 (GPLv2)
# and for details, please consult it at:
#
#    http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
# 
#
# author : Jd <jd_jedi@users.sourceforge.net>
#

# Module containing classes for VM Settings and handlers

import re,pprint, traceback
import types
import os, sys,copy
import gtk, gtk.glade, gobject


from convirt.core.utils.utils import PyConfig,randomMAC,Worker, fv_map,instantiate_configs,merge_pool_settings,vm_config_write

from convirt.core.model.VM import DiskEntry, ImageDiskEntry, VMConfig, vifEntry
from convirt.core.model.network import NwDef
from convirt.core.model.ImageStore import ImageStore

# NOTE the package name has to be fully qualified. otherwise it instantiate
# another version of dialogs module.
from convirt.client.dialogs import gladefile, update_config_props
from convirt.client.dialogs import showmsg, confirmation,file_selection
from convirt.client.dialogs import ProvStatusDlg, StorageDefinitionDetailsDialog

# progress bar
from convirt.client.TaskProgressWnd import TaskProgressWnd

# IMPORTANT: Needs to vanish
from convirt.client.dialogs import main_context

# TODO : add to widget what type of value to expect.. e.g. int in a textEntry
# and use this in scatter and gather

# util functions and classes
from convirt.core.utils.utils import dynamic_map, uuidToString, randomUUID

from convirt.client.ui_utils import *
from convirt.core.model.storage import *
# Application specific convention
# May be move it to Image or ImageStore
def get_vm_conf_dir():
    return "$VM_CONF_DIR"



# dialog for adding/editing disk
class VMDiskEditDlg(Container):
    # constructor
    def __init__(self,
                 storage_manager,
                 disk_entry,
                 is_remote, 
                 managed_node=None,
                 server_pool=None,
                 mode = "ADD",
                 parent_mode = None,
                 parent=None ):
        Container.__init__(self)
        self.storage_manager = storage_manager
        self.disk_entry = disk_entry
        self.is_remote = is_remote
        self.managed_node = managed_node
        self.server_pool = server_pool
        self.mode = mode
        self.parent_mode = parent_mode
        self.parent = parent
        self.ui_init()
        self.old_device = disk_entry.device # save the orig device

    def ui_init(self):
        wtree = gtk.glade.XML(gladefile, "VMDiskEditDlg")
        self.dialog = get_widget(wtree,"VMDiskEditDlg")
        if self.parent:
            self.dialog.set_transient_for(self.parent)
        self.init_widgets(wtree, ['disk_entry_table',
                                  
                                  'vm_disk_options_label',
                                  'vm_disk_options_combo',
                                  
                                  'vm_disk_type_label',
                                  'vm_disk_type_combo',
                                  
                                  'vm_disk_size_label',
                                  'vm_disk_size_entry',
                                  'vm_disk_size_mb_label',
                                  
                                  "vm_disk_location_label",
                                  "vm_disk_location_entry",
                                  "vm_disk_location_selector_btn",
                                  "vm_disk_shared_storage_btn",
                                  
                                  "vm_disk_fs_label",
                                  "vm_disk_fs_combo",

                                  
                                  "vm_disk_is_remote_label",
                                  "vm_disk_is_remote_checkbox",

                                  "vm_ref_disk_location_label",
                                  "vm_ref_disk_location_entry",
                                  "vm_ref_disk_location_selector_btn",

                                  "vm_ref_disk_type_label",
                                  "vm_ref_disk_type_combo",

                                  "vm_ref_disk_format_label",
                                  "vm_ref_disk_format_combo",
                                  

                                  "vm_disk_device_label",
                                  "vm_disk_device_combo_entry",
                                  
                                  "vm_device_access_mode_label",
                                  "vm_device_access_mode_combo",
                                  
                                  
                                  "vm_disk_cancel_btn",
                                  "vm_disk_ok_btn",
                                  ])

        init_combo(self.widgets.vm_disk_options_combo,
                   self.get_disk_options_map(),
                   self.get_disk_options_order())

        if self.parent_mode in ["EDIT_IMAGE", "PROVISION_VM"]:
            init_combo(self.widgets.vm_disk_type_combo,
                       self.get_disk_type_map() )
        else:
            init_combo(self.widgets.vm_disk_type_combo,
                       self.get_disk_type_map_4_vm_config() )
            
        init_combo(self.widgets.vm_disk_fs_combo,
                   self.get_disk_fs_map() )

        init_combo(self.widgets.vm_ref_disk_type_combo,
                   self.get_ref_disk_type_map())

        init_combo(self.widgets.vm_ref_disk_format_combo,
                   self.get_ref_disk_image_format_map())

        
        init_combo(self.widgets.vm_device_access_mode_combo,
                   self.get_device_mode_map() )
        
        init_combo(self.widgets.vm_disk_device_combo_entry,
                   self.get_device_map())
        
        # setup handlers for the buttons                   
        wtree.signal_autoconnect(
                {#"on_vm_disk_ok_btn_clicked": self.on_ok_clicked,
                 #"on_vm_disk_cancel_btn_clicked": self.on_cancel_clicked,
                 "on_vm_disk_location_selector_btn_clicked": self.on_disk_location_selector_clicked,
                 "on_vm_disk_shared_storage_btn_clicked": self.on_disk_shared_storage_clicked,
                 "on_vm_ref_disk_location_selector_btn_clicked": self.on_ref_disk_location_selector_clicked,
                 "on_vm_disk_options_combo_changed": self.on_vm_disk_options_changed,
                 "on_vm_ref_disk_type_combo_changed": self.on_ref_disk_type_changed,
                 "on_vm_disk_type_combo_changed": self.on_disk_type_changed,
                 })        

        self.update_widgets(self.mode)
        
    def get_disk_entry(self):
        return self.disk_entry

    def get_device_map(self):
        return { "hda": "hda",
                 "hdb" : "hdb",
                 "hdc" : "hdc",
                 "hdc:cdrom" : "hdc:cdrom",
                 "hdd": "hdd"
                 }

    def get_disk_options_map(self):
        return { "Create New Disk": "CREATE_DISK",
                 "Use Physical Device" : "USE_DEVICE",
                 "Use ISO File" : "USE_ISO",
                 "Clone Reference Disk" : "USE_REF_DISK",
                 }
    
    def get_disk_options_order(self):
        return [ "Create New Disk",
                 "Use Physical Device" ,
                 "Use ISO File",
                 "Clone Reference Disk" 
                ]

    def get_disk_type_map_4_vm_config(self):
        return { "File (VBD)": ("file", ""),
                 "QCOW": ("tap:qcow", ""),
                 "VMDK": ("tap:vmdk", ""),
                 "Physical Device" : ("phy", "")
                }



    def get_disk_type_map(self):
        return { "File (VBD)": ("file", "VBD"),
                 "QCOW": ("tap:qcow", "qcow2"),
                 "VMDK": ("tap:vmdk", "vmdk"),
                 "Logical Volume" : ("phy", "LVM")
                }

    def get_disk_type_map_4_ref_disk(self):
        return { "File (VBD)": ("file", "VBD"),
                 "Logical Volume" : ("phy", "LVM"),
                 "Select Existing Device": ("phy", ""),
                 "QCOW": ("tap:qcow", "qcow2"),
                 "VMDK": ("tap:vmdk", "vmdk"),
                }

    def get_disk_type_order_4_ref_disk(self):
        return [ "File (VBD)",
                 "Logical Volume" ,
                 "Select Existing Device",
                 "QCOW" ,
                 "VMDK",
                ]


    def get_disk_type_map_4_existing_disk(self):
        return { "Select Existing Device": ("phy", "")
               }

    def get_disk_type_map_4_iso(self):
        return { "Select ISO ": ("file", "ISO")
               }


    
    def get_device_mode_map(self):
        return { "Read-Only": "r",
                 "Read-Write" : "w",
                 "Read-ForceWrite" : "w!"}


    def get_ref_disk_type_map(self):
        return { "Disk Image": "disk_image",
                 "Disk Content" : "disk_content" } 


    def get_ref_disk_image_format_map(self):
        return { "Raw": "raw",
                 "dir-gzipped-chunks" : "dir-gzipped-chunks",
                 ".bz2": "bzip",
                 ".gz" : "gzip",
                 ".zip": "zip",
                 ".tar": "tar",
                 ".tar.gzip": "tar_gzip",
                 ".tar.bz2" : "tar_bzip",
                 }
      


    def get_ref_disk_content_format_map(self):
        return { 
                # ".bz2": "bzip", (Need to add to provision.sh)
                # ".gz" : "gzip", (Need to add to provision.sh)
                 ".zip": "zip",
                 ".tar": "tar",
                 ".tar.gzip": "tar_gzip",
                 ".tar.bz2" : "tar_bzip",
                 "directory":"dir" 
                 }
      



    def get_disk_fs_map(self):
        return {"None": "",
                "ext3": "ext3",
                "ext2" : "ext2",
                "swap" : "swap"}



    # handlers
    def on_vm_disk_options_changed(self, widget):
        option = get_value(self.widgets.vm_disk_options_combo)
        value_map = []
        order=None
        if self.parent_mode in ["EDIT_IMAGE", "PROVISION_VM"]:

            if option == self.disk_entry.CREATE_DISK:
                value_map = self.get_disk_type_map()  
            elif option == self.disk_entry.USE_DEVICE:
                value_map = self.get_disk_type_map_4_existing_disk()
            elif option == self.disk_entry.USE_ISO:
                 value_map = self.get_disk_type_map_4_iso() 
            elif option == self.disk_entry.USE_REF_DISK :
                value_map = self.get_disk_type_map_4_ref_disk()
                order = self.get_disk_type_order_4_ref_disk()
        else:
            value_map = self.get_disk_type_map_4_vm_config()  


        init_combo(self.widgets.vm_disk_type_combo,
                   value_map, order)
            
        if (self.disk_entry.type, self.disk_entry.disk_type) in value_map:
            set_value(self.widgets.vm_disk_type_combo,
                      (self.disk_entry.type, self.disk_entry.disk_type))
        else :
            # select the first one.
            model = self.widgets.vm_disk_type_combo.get_model()
            iter = model.get_iter_first()
            if iter:
                self.widgets.vm_disk_type_combo.set_active_iter(iter)

        if option == self.disk_entry.USE_ISO:
            set_value(self.widgets.vm_device_access_mode_combo, "r")
            set_value(self.widgets.vm_disk_device_combo_entry, "hdc:cdrom")

        self.update_widgets(self.mode)
            
    def on_disk_type_changed(self, widget):
        option = get_value(self.widgets.vm_disk_options_combo)
        show_size = True
        if option == self.disk_entry.USE_REF_DISK:
            if get_value(self.widgets.vm_disk_type_combo) == ("phy","LVM"):
                show_size = True
            else:
                show_size = False
        elif option in (self.disk_entry.USE_DEVICE, self.disk_entry.USE_ISO) :
            show_size = False

        # disable the disk size in edit mode.
        if self.parent_mode in ( "EDIT_VM_CONFIG", "EDIT_VM_INFO") :
            show_size = False

        for widget in ("vm_disk_size_entry",
                       "vm_disk_size_label",
                       "vm_disk_size_mb_label"):
            self.widgets[widget].set_property("visible",show_size)


    def on_ref_disk_type_changed(self, widget):
        map = {}
        if get_value(self.widgets.vm_ref_disk_type_combo) == "disk_image":
            map = self.get_ref_disk_image_format_map()
        else:
            map = self.get_ref_disk_content_format_map()

        print "Reinitializing vm_ref_disk_format with "
        pprint.pprint(map)
        init_combo(self.widgets.vm_ref_disk_format_combo,map)
        set_value(self.widgets.vm_ref_disk_format_combo, "")
                   

    def on_disk_location_selector_clicked(self, widget):
        file_selector(widget,self.managed_node,
                      field=self.widgets.vm_disk_location_entry,
                      fstype="open", parentwin=None)
        print "disk_location_selector_clicked"

    def on_ref_disk_location_selector_clicked(self, widget):
        file_selector(widget,self.managed_node,
                      field=self.widgets.vm_ref_disk_location_entry,
                      fstype="open", parentwin=None)
        print "ref_disk_location_selector_clicked"

    def on_disk_shared_storage_clicked(self, widget):
        print "disk_shared_storage_clicked"
        dlg = StorageDefinitionDetailsDialog()
        ret = dlg.show(None,
                       storage_manager=self.storage_manager,
                       shared_storage_id = None,
                       managed_server = self.managed_node,
                       group = self.server_pool,
                       mode = "SELECT")

        if not ret:
            return


        disk_info = dlg.get_selected_volume()
        
        print disk_info

                

        if disk_info:
            # validate
            if self.parent_mode in ["PROVISION_VM"]:
                option = get_value(self.widgets.vm_disk_options_combo)
                if option == self.disk_entry.CREATE_DISK:
                    if disk_info.type != NFS:
                        showmsg("Invalid selection : New disks can be created on file type storage only.\n Please select a file based (NFS) storage.")
                        return
                elif option == self.disk_entry.USE_DEVICE:
                    if disk_info.type == NFS:
                        showmsg("Invalid selection : File based storage(NFS) storage can not be selected for existing disks.\n Please select iSCSI or AOE storage.")
                        return

            
            if disk_info.type == AOE:
                set_value(self.widgets.vm_disk_location_entry, disk_info.disk)
                set_value(self.widgets.vm_disk_type_combo, ("phy", ""))
            elif disk_info.type == iSCSI:
                set_value(self.widgets.vm_disk_location_entry,
                          disk_info.interface)
                set_value(self.widgets.vm_disk_type_combo, ("phy", ""))
            elif disk_info.type == NFS:
                if disk_info.name == disk_info.disk : #mount point selected
                    d_name = ""
                    if self.mode == "ADD":
                        d_name = "$VM_NAME.disk.xm"
                    else:
                        loc = get_value(self.widgets.vm_disk_location_entry)
                        if loc:
                            # replace the directory with the mount point
                            # selected. reasonable guess.
                            base = os.path.basename(loc)
                            if base:
                                d_name = base

                    new_loc = os.path.join(disk_info.disk, d_name)
                    set_value(self.widgets.vm_disk_location_entry,new_loc)

                else:
                    set_value(self.widgets.vm_disk_location_entry,
                              disk_info.disk)
                
                if get_value(self.widgets.vm_disk_type_combo)[0] == "phy":
                    if self.parent_mode == "EDIT_VM_CONFIG":
                        set_value(self.widgets.vm_disk_type_combo, ("file", ""))
                    else:
                        set_value(self.widgets.vm_disk_type_combo, ("file", "VBD"))
            # mark the disk as remote        
            set_value(self.widgets.vm_disk_is_remote_checkbox, True)

    # handlers end

    # Container 
    def update_widgets(self, mode):
        Container.update_widgets(self, mode)
        self.on_disk_type_changed(self.widgets.vm_disk_type_combo)
        
    def get_widgets_to_hide(self, mode):
        wth = []
        wth.append(self.widgets.vm_disk_is_remote_label)
        wth.append(self.widgets.vm_disk_is_remote_checkbox)
                                     
        if self.server_pool is None:
            wth.append(self.widgets.vm_disk_shared_storage_btn)

        if self.parent_mode not in ["EDIT_IMAGE", "PROVISION_VM"]:
            for widget_name in [ 'vm_disk_options_label',
                                 'vm_disk_options_combo',
                                  
                                 #'vm_disk_type_label',
                                 #'vm_disk_type_combo',
                                  
                                  'vm_disk_size_label',
                                  'vm_disk_size_entry',
                                  'vm_disk_size_mb_label',
                                  
                                 # "vm_disk_location_label",
                                 # "vm_disk_location_entry",
                                 # "vm_disk_location_selector_btn",
                                 # "vm_disk_shared_storage_btn",
                                  
                                  "vm_disk_fs_label",
                                  "vm_disk_fs_combo",

                                 # "vm_disk_is_remote_label",
                                 # "vm_disk_is_remote_checkbox",

                                  "vm_ref_disk_location_label",
                                  "vm_ref_disk_location_entry",
                                  "vm_ref_disk_location_selector_btn",

                                  "vm_ref_disk_type_label",
                                  "vm_ref_disk_type_combo",

                                  "vm_ref_disk_format_label",
                                  "vm_ref_disk_format_combo",
                                 ]:
                wth.append(self.widgets.get(widget_name))

        option = get_value(self.widgets.vm_disk_options_combo)

        if option == self.disk_entry.CREATE_DISK:
            for widget_name in ["vm_ref_disk_location_label",
                                "vm_ref_disk_location_entry",
                                "vm_ref_disk_location_selector_btn",
                                
                                "vm_ref_disk_type_label",
                                "vm_ref_disk_type_combo",
                                
                                "vm_ref_disk_format_label",
                                "vm_ref_disk_format_combo",
                                #"vm_disk_shared_storage_btn"
                                ]:
                wth.append(self.widgets.get(widget_name))
        elif option in (self.disk_entry.USE_DEVICE,
                        self.disk_entry.USE_ISO):
            for widget_name in ['vm_disk_type_label',
                                'vm_disk_type_combo',

                                'vm_disk_size_label',
                                'vm_disk_size_entry',
                                'vm_disk_size_mb_label',

                                "vm_ref_disk_location_label",
                                "vm_ref_disk_location_entry",
                                "vm_ref_disk_location_selector_btn",
                                
                                "vm_ref_disk_type_label",
                                "vm_ref_disk_type_combo",
                                
                                "vm_ref_disk_format_label",
                                "vm_ref_disk_format_combo",
                                ]:
                wth.append(self.widgets.get(widget_name))
        elif option == self.disk_entry.USE_REF_DISK:
            for widget_name in [#'vm_disk_type_label',
                                #'vm_disk_type_combo',

                                #'vm_disk_size_label',
                                #'vm_disk_size_entry',
                                #'vm_disk_size_mb_label',

                                ]:
                wth.append(self.widgets.get(widget_name))
        
        if option == self.disk_entry.USE_ISO:
            for widget_name in [ "vm_disk_fs_label",
                                 "vm_disk_fs_combo",
                                 ]:
                wth.append(self.widgets.get(widget_name))
        return wth

    def get_widgets_to_disable(self, mode):
        return []

    def validate(self):
        errs = []
        if not get_value(self.widgets.vm_disk_type_combo):
            errs.append("Disk Type can not be empty")
        if not get_value(self.widgets.vm_disk_location_entry):
            errs.append("Disk Location can not be empty")
        if not get_value(self.widgets.vm_disk_device_combo_entry):
            errs.append("VM Disk name can not be empty")
        if not get_value(self.widgets.vm_device_access_mode_combo):
            errs.append("VM Disk access mode can not be empty")
        return errs

    def scatter(self, context):
        disk_entry = context
        

        # additional widgets
        if self.parent_mode in ["EDIT_IMAGE", "PROVISION_VM"]:
            for widget, val in (
                ( "vm_disk_options_combo", disk_entry.option),
                ( "vm_disk_size_entry", disk_entry.size),
                ( "vm_disk_fs_combo", disk_entry.fs_type),
                ( "vm_ref_disk_location_entry", disk_entry.image_src),
                ( "vm_ref_disk_type_combo", disk_entry.image_src_type),
                ( "vm_ref_disk_format_combo", disk_entry.image_src_format),
                ):
                set_value(self.widgets[widget], val)

            if not disk_entry.fs_type:
                self.widgets.vm_disk_fs_combo.set_active(0)
                
        for widget, val in (("vm_disk_location_entry",
                             disk_entry.filename),
                            ( "vm_disk_device_combo_entry", disk_entry.device),
                            ( "vm_disk_type_combo",
                              (disk_entry.type, disk_entry.disk_type)),
                            ( "vm_device_access_mode_combo", disk_entry.mode),
                            ( "vm_disk_is_remote_checkbox", self.is_remote),
                            ):
            print widget, val
            set_value(self.widgets[widget], val)



    def gather(self, context):
        disk_entry = context
        (type, disk_type) = get_value(self.widgets.vm_disk_type_combo)
        location = get_value(self.widgets.vm_disk_location_entry)
        device_name = get_value(self.widgets.vm_disk_device_combo_entry)
        device_mode = get_value(self.widgets.vm_device_access_mode_combo)

        self.disk_entry.type = type
        self.disk_entry.filename = location
        self.disk_entry.device = device_name
        self.disk_entry.mode = device_mode
        self.is_remote = get_value(self.widgets.vm_disk_is_remote_checkbox)


        print "DISK TYPE is ", disk_type
        if isinstance(self.disk_entry, ImageDiskEntry):
            self.disk_entry.disk_type = disk_type
            self.disk_entry.option = get_value(self.widgets.vm_disk_options_combo)
            self.disk_entry.size = get_value(self.widgets.vm_disk_size_entry)
            self.disk_entry.fs_type = get_value(self.widgets.vm_disk_fs_combo)
            self.disk_entry.image_src = get_value(self.widgets.vm_ref_disk_location_entry)
            self.disk_entry.image_src_type = get_value(self.widgets.vm_ref_disk_type_combo)
            self.disk_entry.image_src_format = get_value(self.widgets.vm_ref_disk_format_combo)


    def save(self, context):
        pass # required stuff done in gather.
    
    ## TBD : Validate the dialogbox pattern
    def show(self):
        ret = None
        
        self.scatter(self.disk_entry)
        while ret != gtk.RESPONSE_DELETE_EVENT :
            ret = self.dialog.run()
            if ret in (gtk.RESPONSE_CANCEL, gtk.RESPONSE_OK):
                if (ret == gtk.RESPONSE_OK):
                    try:
                        msgs = self.validate()
                        if msgs is None or len(msgs) == 0:
                            self.gather(self.disk_entry)
                            self.save(self.disk_entry)
                            break
                        else:
                            show_validation_msgs(msgs, self.dialog)
                    except Exception, ex:
                        traceback.print_exc()
                        showmsg("Ex :" + str(ex), self.dialog)
                else:
                    break

        self.dialog.destroy()
        return ret
    
    
    
# Nw Inteface Dialog
class VMNwEditDlg(Dlg):
    def __init__(self,mode, parent_mode, nw_manager, managed_node, 
                 vif_entry, nw_def, parent):
        Dlg.__init__(self)
        self.context=dynamic_map()
        self.context.mode=mode
        self.context.parent_mode = parent_mode
        self.context.vif_entry = vif_entry
        self.context.nw_def = nw_def
        self.context.nw_manager = nw_manager
        self.context.managed_node = managed_node
        self.parent = parent
        self.ui_init()

    def ui_init(self):
        wtree = gtk.glade.XML(gladefile, "VMNwEditDlg")
        self.dialog = get_widget(wtree,"VMNwEditDlg")
        if self.parent:
            self.dialog.set_transient_for(self.parent)
        self.init_widgets(wtree, [
                                  'available_nw_label',
                                  'available_nw_combo',

                                  'specify_mac_address_checkbox',
                                  'mac_address_label',
                                  'mac_address_entry',
                                  'mac_autogen_txt'
                                  
                                  ])

        wtree.signal_autoconnect({"on_specify_mac_address_checkbox_toggled":
                                      self.on_auto_mac_toggled,
                                  
                                  })

    def on_auto_mac_toggled(self, widget):
        if widget.get_active():
            self.widgets.mac_address_entry.set_property("sensitive", True)
        else:
            self.widgets.mac_address_entry.set_property("sensitive", False)

    def show(self):
        return self.run_dlg(self.context)

    def update_widgets(self, mode):
        Dlg.update_widgets(self,mode)
        self.on_auto_mac_toggled(self.widgets.specify_mac_address_checkbox)

    def get_widgets_to_hide(self, mode):
        wth = []
        parent_mode = self.context.parent_mode
        if parent_mode in ["EDIT_VM_CONFIG", "EDIT_VM_INFO"]:
            wth.append(self.widgets.specify_mac_address_checkbox)
            wth.append(self.widgets.mac_autogen_txt)
        return wth


    def get_widgets_to_disable(self, mode):
        wtd = []
        return wtd

    def validate(self):
        errs = []
        if get_value(self.widgets.specify_mac_address_checkbox):
            mac_value = get_value(self.widgets.mac_address_entry)
        else:
            mac_value = "$AUTOGEN_MAC"

        bridge_value = get_value(self.widgets.available_nw_combo)
        if not bridge_value:
            errs.append("No network selected.")
        if not mac_value:
            errs.append("Please specify a mac address")
        if self.context.parent_mode not in ["EDIT_IMAGE", "PROVISION_VM"]:
            if mac_value == "$AUTOGEN_MAC":
                errs.append("Please specify a mac address")
        
        return errs

    def init_nw_combo(self, context):
        nw_manager = context.nw_manager
        mode = context.mode
        parent_mode = context.parent_mode
        
        if parent_mode in ["EDIT_IMAGE",]:
            init_combo(self.widgets.available_nw_combo,
                       { "Default" : "$DEFAULT_BRIDGE",
                         "xenbr0" : "xenbr0",
                         "xenbr1" : "xenbr1",
                         "xenbr2" : "xenbr2",
                         "br0": "br0",
                         "br1": "br1",
                         "br2": "br2",
                         "eth0": "eth0",
                         "eth1": "eth1",
                         "eth2": "eth2",
                       })
        else: # "PROVISION_VM", "EDIT_VM_CONFIG"
            nw_map = {}
            all_bridges = []
            bridges = self.context.managed_node.get_bridge_info()
            for nw in nw_manager.get_defns(None, 
                                           self.context.managed_node.hostname):
                bridge=None
                network = None
                if nw.ipv4_info and nw.ipv4_info.ip_network:
                    network = nw.ipv4_info.ip_network
                
                if nw.bridge_info and nw.bridge_info.name:
                    bridge = nw.bridge_info.name

                
                if bridge and network:
                    desc = "%s (%s, %s)" % (nw.name, 
                                            bridge,
                                            network)
                elif bridge:
                    desc = "%s (%s)" % (nw.name, 
                                        bridge,)
                elif network:
                    desc = "%s (%s)" % (nw.name, 
                                        network,)

                if nw.bridge_info and nw.bridge_info.name:
                    nw_map[desc] =  nw.bridge_info.name

            if parent_mode == "PROVISION_VM":
                nw_map["Default"] = "$DEFAULT_BRIDGE"

            for n in bridges.itervalues():
                name = n["name"]
                if name not in nw_map.itervalues():
                    desc = name + " network"
                    if n.get("network"):
                        desc = "%s (%s,%s)" % (desc, name, n["network"])
                    nw_map[desc] = name

            init_combo(self.widgets.available_nw_combo,
                       nw_map)
                       

    def scatter(self, context):
        vif = context.vif_entry

        self.init_nw_combo(context)

        if vif.get_mac() == "$AUTOGEN_MAC" or vif.get_mac() == "":
            set_value(self.widgets.specify_mac_address_checkbox, False)
        else:
            set_value(self.widgets.specify_mac_address_checkbox, True)
            set_value(self.widgets.mac_address_entry,vif.get_mac())
            
        set_value(self.widgets.available_nw_combo, vif.get_bridge())

    def gather(self, context):
        # get value from the widgets.
        if get_value(self.widgets.specify_mac_address_checkbox):
            mac_value = get_value(self.widgets.mac_address_entry)
        else:
            mac_value = "$AUTOGEN_MAC"

        bridge_value = get_value(self.widgets.available_nw_combo)
            
        print "Bridge Name = ", bridge_value
        print "Mac value = ", mac_value

        vif_entry = context.vif_entry
        vif_entry.set_mac(mac_value)
        vif_entry.set_bridge(bridge_value)

    def save(self, context):
        pass


class GeneralPage(Page):

    def __init__(self, context):
        Page.__init__(self)
        self.context = context
        self.storage_manager = self.context.storage_manager
        self.managed_node = self.context.managed_node
        self.ui_init(context)
        [self.DISK_TYPE,
         self.DISK_LOCATION,
         self.VM_DEVICE,
         self.DEVICE_MODE,
         self.DISK_SHARED,
         self.DISK_ENTRY ] = range(6)
        
        [ self.NW_TYPE,
          self.NW_NAME,
          self.NW_DEFINITION,
          self.NW_MAC,
          self.VIF_ENTRY,
          self.NW_ENTRY] = range(6)

    def ui_init(self, context):
        wtree = context.wtree

        self.init_widgets(wtree, ["vm_name_label",
                                  "vm_config_filename_label",
                                  "vm_name_entry",
                                  "vm_config_filename_entry",
                                  "vm_config_filename_selector_btn",
                                  "vm_memory_entry",
                                  "vm_vcpu_spinbtn",
                                  "vm_disks_view",
                                  "vm_disk_add_btn",
                                  "vm_disk_props_btn",
                                  "vm_disk_remove_btn",
                                  "vm_nw_view",
                                  "vm_nw_add_btn",
                                  "vm_nw_props_btn",
                                  "vm_nw_remove_btn",
                                  "general_page_content",
                                  'vm_general_label'])
        
        view = self.widgets.vm_disks_view
        model = gtk.ListStore(gobject.TYPE_STRING, # type
                              gobject.TYPE_STRING, # location/ filename
                              gobject.TYPE_STRING, # guest device name
                              gobject.TYPE_STRING, # device access mode
                              gobject.TYPE_BOOLEAN, # shared storage ?
                              gobject.TYPE_PYOBJECT) # disk object
        view.set_model(model)
        self.init_disks_view()
        self.setup_disk_handlers(wtree)


        nw_view = self.widgets.vm_nw_view
        nw_model = gtk.ListStore(gobject.TYPE_STRING,   # NW Type
                                 gobject.TYPE_STRING,   # Name
                                 gobject.TYPE_STRING,   # Network Definition
                                 gobject.TYPE_STRING,   # MAC
                                 gobject.TYPE_PYOBJECT, # VifEntry object
                                 gobject.TYPE_PYOBJECT) # NWDef object.
        nw_view.set_model(nw_model)
        self.init_nw_view()
        self.setup_nw_handlers(wtree)


        self.page_content_widget = self.widgets[ 'general_page_content' ]
        self.page_tab_widget = self.widgets.vm_general_label

        # action handlers.
        wtree.signal_autoconnect({"on_vm_config_filename_selector_btn_clicked":
                                 (file_selector,
                                  self.managed_node,
                                  self.widgets.vm_config_filename_entry),
                                  "on_vm_name_changed": self.on_vm_name_changed}
                                 )
        

    def on_combo_changed(self, model):
        print "on changed called "

    def init_nw_view(self):
        textrenderer = gtk.CellRendererText()
        view = self.widgets.vm_nw_view
        columns = [ ("Name",1), ("Details",2), ("MAC",3)]
        for c, index in columns:
            tree_column = gtk.TreeViewColumn(c, textrenderer,
                                             text=index)
            if c== "Details":
                tree_column.set_max_width(40)
                tree_column.set_expand(True)
            if c=="Name":
                tree_column.set_max_width(20)
                tree_column.set_expand(True)

            tree_column.set_resizable(True)
            view.append_column(tree_column)
      
    def on_vm_name_changed(self, widget):
        if self.context.mode == "PROVISION_VM":
            t = os.path.join(get_vm_conf_dir(), widget.get_text())
            self.widgets.vm_config_filename_entry.set_text(t)

    def get_conf_dir():
        return "$VM_CONFIG"
     
    # give page widgets to the notebook
    def get_page_widgets():
        return self.page_tab_widget, self.page_content_widget

    # handle enable/disable via Container
    def update_widgets(self, mode):
        Container.update_widgets(self, mode)
        
    def get_widgets_to_hide(self, mode):
        if mode == "EDIT_IMAGE":
            return [ self.widgets[w] for w in ["vm_name_label",
                                               "vm_config_filename_label",
                                               "vm_name_entry",
                                               "vm_config_filename_selector_btn",
                                               "vm_config_filename_entry"
                                               ]]        
        return []

    def get_widgets_to_disable(self, mode):
        if mode in ["EDIT_VM_CONFIG",]:
            return [ self.widgets[w] for w in ["vm_name_entry",
                                               "vm_config_filename_selector_btn",
                                               "vm_config_filename_entry"
                                               ]]        
        if mode in ["EDIT_VM_INFO",]:
           wth =  [ self.widgets[w] for w in [
                                              "vm_name_entry",
                                              "vm_config_filename_entry",
                                              "vm_config_filename_selector_btn",
                                              "vm_disk_props_btn",
                                              "vm_nw_view",
                                              "vm_nw_add_btn",
                                              "vm_nw_props_btn",
                                              "vm_nw_remove_btn",
                                              ]]
           if not self.context.vm_config:
               wth.append(self.widgets.vm_disk_add_btn)
               wth.append(self.widgets.vm_disk_remove_btn)
               wth.append(self.widgets.vm_disks_view)
                         
           return wth
        return []

    def scatter(self, context):
        mode = context.mode
        vm_config = context.get("vm_config")
        if vm_config:
            for widget, config_attr in (("vm_name_entry", "name"),
                                        ("vm_config_filename_entry", "filename"),
                                        ("vm_memory_entry", "memory"),
                                        ("vm_vcpu_spinbtn", "vcpus")):
                set_value(self.widgets[widget], vm_config.get(config_attr))
            self.scatter_disks(context)
            self.scatter_nw(context)
            if mode == "PROVISION_VM":
                set_value(self.widgets.vm_config_filename_entry,
                          get_vm_conf_dir())

        if mode == "EDIT_VM_INFO":
            vm_info = self.context.vm_info
            for widget, config_attr in (("vm_name_entry", "name"),
                                        ("vm_memory_entry", "memory"),
                                        ("vm_vcpu_spinbtn", "online_vcpus")):
                set_value(self.widgets[widget], vm_info[config_attr]) #KLUDGE
        
    def gather(self, context):
        mode = context.mode
        vm_config = context.get("vm_config")
        if mode in ["EDIT_VM_CONFIG", "PROVISION_VM", "EDIT_IMAGE"] and \
               vm_config:
            for widget, config_attr in (("vm_name_entry", "name"),
                                        ("vm_config_filename_entry", "filename"),
                                        ("vm_memory_entry", "memory"),
                                        ("vm_vcpu_spinbtn", "vcpus")):
                value = get_value(self.widgets[widget])
                if widget in ("vm_memory_entry", "vm_vcpu_spinbtn"):
                    value = int(value)
                if config_attr == 'filename' :
                    vm_config.set_filename(value)
                else:
                    vm_config[config_attr] = value
            self.gather_disks(context)
            self.gather_nw(context)

        elif mode in ["EDIT_VM_INFO"] and context.vm_info:
            for widget, config_attr in ( ("vm_memory_entry", "memory"),
                                         ("vm_vcpu_spinbtn", "online_vcpus"), ):
                value = get_value(self.widgets[widget])
                value = int(value)
                context.vm_info[config_attr] = value
            self.gather_disks(context)
                         
    def validate(self):
        errmsgs = []

        filename = get_value(self.widgets.vm_config_filename_entry)

        if not filename and self.context.mode != "EDIT_VM_INFO":
            errmsgs.append("You must specify a file name.")

        value = get_value(self.widgets.vm_memory_entry)
        try:
            value = int(value)
        except:
            errmsgs.append("Specify a proper integer value for the Memory.")

        if self.context.mode != "EDIT_IMAGE":
            vm_name = get_value(self.widgets.vm_name_entry) 
            if not vm_name:
                errmsgs.append("You must specify a name for the VM.")

            elif self.context.mode == "PROVISION_VM" and \
                     self.managed_node.is_resident(vm_name):
                errmsgs.append("Running VM with the same name exists.")

            if vm_name:
                x = vm_name
                if re.sub(ImageStore.INVALID_CHARS_EXP,"", x) != x:
                    errmsgs.append("VM name can not contain special chars %s" % ImageStore.INVALID_CHARS)  

        value = get_value(self.widgets.vm_memory_entry)
        try:
            value = int(value)
        except:
            errmsgs.append("Specify a proper integer value for the Memory.")


        return errmsgs


    # disks related functions. Override them if ur disk info/structure
    # looks different

    def init_disks_view(self):
        textrenderer = gtk.CellRendererText()
        view = self.widgets.vm_disks_view
        columns = ["Type", "Location", "VM Device", "Mode"]
        for c in columns:
            tree_column = gtk.TreeViewColumn(c, textrenderer,
                                            text=columns.index(c))
            if c == "Location":
                tree_column.set_max_width(200)
                tree_column.set_expand(True)
            tree_column.set_resizable(True)
            view.append_column(tree_column)
        # Add shared or not check box
        # column for fixed toggles
        renderer = gtk.CellRendererToggle()
        renderer.connect('toggled', self.shared_toggled, view.get_model())

        tree_column = gtk.TreeViewColumn('Shared', renderer, active=4)
        view.append_column(tree_column)
        

    def setup_disk_handlers(self, wtree):
        wtree.signal_autoconnect(
                {"on_disk_add_btn_clicked": self.on_disk_add_clicked,
                 "on_disk_edit_btn_clicked": self.on_disk_edit_clicked,
                 "on_disk_remove_btn_clicked": self.on_disk_remove_clicked,
                 "on_vm_disks_view_row_activated": self.handle_row_activated,
                 })
        #self.widgets.vm_disks_view.connect("row-activated",
        #                                   self.handle_row_activated)


    def shared_toggled(self, cell, path, model):
        # get toggled iter
        iter = model.get_iter((int(path),))
        shared = model.get_value(iter, self.DISK_SHARED)

        # toggle it
        shared = not shared

        # set new value
        model.set(iter, self.DISK_SHARED, shared)
        
    def handle_row_activated(self, treeview, path, column):
        self.on_disk_edit_clicked(self.widgets.vm_disk_props_btn)

    def get_disk_edit_dlg(self, disk, is_remote,
                          managed_node, server_pool, mode, parent_mode,
                          parentwin):
        return VMDiskEditDlg(self.storage_manager,
                             disk, is_remote, managed_node,
                             server_pool, mode, parent_mode, parentwin)

    def get_nw_edit_dlg(self, mode, 
                        parent_mode, 
                        nw_manager, managed_node,
                        vif_entry, nw_entry, 
                        parentwin) :
        return VMNwEditDlg( mode, 
                        parent_mode, 
                        nw_manager, managed_node, 
                        vif_entry, nw_entry, 
                        parentwin) 



    def get_new_disk_entry(self, image_conf = None):
        return ImageDiskEntry(("file","","","w"), image_conf)
    
    def on_disk_add_clicked(self, widget):
        
        if self.context.provisioning_page:
            self.context.provisioning_page.gather(self.context)

        new_disk = self.get_new_disk_entry(self.context.image_config)
        dlg = self.get_disk_edit_dlg(new_disk, False, self.managed_node,
                                     self.context.server_pool,
                                     "ADD",
                                     self.context.mode, # parent_mode
                                     self.context.parent_win)
        
        ret = dlg.show()
        if ret == gtk.RESPONSE_OK:
            iter = self.append_disk_entry(new_disk)
            model = self.widgets.vm_disks_view.get_model()
            model.set_value(iter, self.DISK_SHARED, dlg.is_remote)
            self.update_image_conf_model(new_disk)



    def on_disk_edit_clicked(self, widget):
        (model, iter) = self.widgets.vm_disks_view.get_selection().get_selected()
        # Take the latest values from provisioing page and set it in
        # disk Entry
        disk_entry = model.get_value(iter,self.DISK_ENTRY)
        
        if self.context.provisioning_page:
            self.context.provisioning_page.gather(self.context)

        disk_entry.set_image_conf(self.context.image_conf)
        
        if iter:
            dlg = self.get_disk_edit_dlg(disk_entry,
                                         model.get_value(iter,self.DISK_SHARED),
                                         self.managed_node,
                                         self.context.server_pool,
                                         "EDIT",
                                         self.context.mode, # parent_mode
                                         self.context.parent_win)
            ret = dlg.show()
            if ret == gtk.RESPONSE_OK:
                disk_entry = dlg.disk_entry
                is_remote  = dlg.is_remote
                model.set_value(iter, self.DISK_TYPE, disk_entry.type)
                model.set_value(iter, self.DISK_LOCATION, disk_entry.filename)
                model.set_value(iter, self.VM_DEVICE, disk_entry.device)
                model.set_value(iter, self.DEVICE_MODE, disk_entry.mode)
                model.set_value(iter, self.DISK_SHARED, is_remote)
                model.set_value(iter, self.DISK_ENTRY, disk_entry)
                self.update_image_conf_model(disk_entry, dlg.old_device)



    # update the image conf and call scatter to update the model
    def update_image_conf_model(self, disk_entry, old_device = None):
        if not disk_entry:
            return

        if not self.context.image_config:
            return

        # update the image_conf
        device = disk_entry.device

        if old_device and device != old_device:
            print "## Device change detected from ", old_device, device
            
            old_create_var = old_device + "_disk_create"
            old_image_src_var = old_device + "_image_src"
            old_image_src_type_var = old_device + "_image_src_type"
            old_image_src_format_var = old_device + "_image_src_format"
            old_size_var = old_device + "_disk_size"
            old_disk_fs_type_var = old_device + "_disk_fs_type"
            old_disk_type_var = old_device + "_disk_type"

            # device changed. lets clear values for old device
            # ASSUME : Uniq devices
            for var, value in ((old_create_var, ""),
                               (old_size_var, 0),
                               (old_disk_fs_type_var, ""),
                               (old_disk_type_var, ""),
                               (old_image_src_var, ""),
                               (old_image_src_type_var, ""),
                               (old_image_src_format_var, "")
                           ):
                print "delting ", var
                del self.context.image_config[var]
            

        # Vars
        # Strip :cdrom from the device.
        pos = device.find(":cdrom")
        if pos > -1:
            device=device[0:pos]

        create_var = device + "_disk_create"
        image_src_var = device + "_image_src"
        image_src_type_var = device + "_image_src_type"
        image_src_format_var = device + "_image_src_format"
        size_var = device + "_disk_size"
        disk_fs_type_var = device + "_disk_fs_type"
        disk_type_var = device + "_disk_type"

        create_value = None
        if disk_entry.option == disk_entry.CREATE_DISK:
            create_value = "yes"
        if disk_entry.option == disk_entry.USE_REF_DISK:
            if disk_entry.type == "phy" and disk_entry.disk_type == "":
                create_value = ""
            else:
                create_value = "yes"

        if not create_value or create_value != "yes":
            disk_entry.size = 0
            if disk_entry.option != disk_entry.USE_REF_DISK:
                disk_entry.image_src = ""
                disk_entry.image_src_type = ""
                disk_entry.image_src_format = ""
            
           
        for var, value in ((create_var, create_value),
                           (size_var, disk_entry.size),
                           (disk_fs_type_var, disk_entry.fs_type),
                           (disk_type_var, disk_entry.disk_type),
                           (image_src_var, disk_entry.image_src),
                           (image_src_type_var, disk_entry.image_src_type),
                           (image_src_format_var, disk_entry.image_src_format),
                           ):
            if value:
                print "*** updating ", var, value
                self.context.image_config[var] = value
            else:
                del self.context.image_config[var]

        # now image conf is updated, call the scatter on the prov page.
        if self.context.provisioning_page:
            self.context.provisioning_page.scatter(self.context)
        

    def on_disk_remove_clicked(self,widget):
        (model, iter) = self.widgets.vm_disks_view.get_selection().get_selected()
        if iter:
            model.remove(iter)

    
    def append_disk_entry(self, disk_entry):
        view = self.widgets.vm_disks_view
        model = view.get_model()
        cfg = self.context.vm_config
        if cfg :
            is_remote = cfg.get_storage_stats().get_remote(disk_entry.filename)

        #print "SCATTER", disk_entry.filename, is_remote
        iter = model.append([disk_entry.type, disk_entry.filename,
                             disk_entry.device, disk_entry.mode, is_remote,
                             disk_entry])
        
##      model.append([disk.get_type(),
##                    disk.get_location(),
##                    disk.get_device_name(),
##                    disk.get_mode()])
        return iter
    
    def scatter_disks(self, context):
        vm_config = context.vm_config
        disks = vm_config.getDisks(context.image_config)

        if disks:
            view = self.widgets.vm_disks_view
            model = view.get_model()
            model.clear()

            if context.mode in ["EDIT_VM_INFO"]:
                temp_list=[]
                for disk_data in disks:
                    temp_list.append(str(disk_data))
                vm_config["init_disks"]=temp_list
            else:
                if "init_disks" in vm_config.keys():
                    del vm_config["init_disks"]

            for disk in disks:
                self.append_disk_entry(disk)

    def gather_disks(self, context):
        vm_config = context.vm_config
        if not vm_config:
            return
        view = self.widgets.vm_disks_view
        model = view.get_model()
        disks = []
        iter = model.get_iter_first()
        while iter:
            disk_entry = model.get_value(iter, self.DISK_ENTRY)
            disks.append(repr(disk_entry))
            iter = model.iter_next(iter)

        vm_config["disk"] = disks
        # reiterate (as set_remote/update_stats requires disks to be added
        # in the config
        s_stat = vm_config.get_storage_stats()
        iter = model.get_iter_first()
        while iter:
            de = model.get_value(iter, self.DISK_ENTRY)
            is_remote = model.get_value(iter, self.DISK_SHARED)
            #print "### GATHER ",  de.filename, is_remote
            s_stat.set_remote(de.filename, is_remote)
            iter = model.iter_next(iter)
            
        #print vm_config
        #print "VM DISK GATHER : ", vm_config["STORAGE_STATS"]


    # Virtual Network interface functions
    def setup_nw_handlers(self, wtree):
        wtree.signal_autoconnect(
                {"on_nw_add_btn_clicked": self.on_nw_add_clicked,
                 "on_nw_edit_btn_clicked": self.on_nw_edit_clicked,
                 "on_nw_remove_btn_clicked": self.on_nw_remove_clicked,
                 "on_nw_view_row_activated": self.handle_nw_row_activated,
                 })

    def on_nw_edit_clicked(self, widget):
        (model, iter) = self.widgets.vm_nw_view.get_selection().get_selected()
        # Take the latest values from provisioing page and set it in
        # nw Entry
        if iter:
            (vif_entry, nw_entry) = (model.get_value(iter,self.VIF_ENTRY),
                                     model.get_value(iter,self.NW_ENTRY))
            dlg = self.get_nw_edit_dlg("EDIT", 
                                       self.context.mode, 
                                       self.context.nw_manager,  
                                       self.context.managed_node,
                                       vif_entry, nw_entry, 
                                       self.context.parent_win) 
        
            ret = dlg.show()
            if ret == gtk.RESPONSE_OK:
                nw = self.find_nw(vif_entry, self.context)
                (nw_type, nw_name, nw_desc, nw_mac) = self.get_nw_details(vif_entry, nw)
                model = self.widgets.vm_nw_view.get_model()
                model.set_value(iter, self.NW_TYPE, nw_type)
                model.set_value(iter, self.NW_NAME, nw_name)
                model.set_value(iter, self.NW_DEFINITION, nw_desc)
                model.set_value(iter, self.NW_MAC, nw_mac)
                model.set_value(iter, self.VIF_ENTRY, vif_entry)
                model.set_value(iter, self.NW_ENTRY, nw_entry)
                
                self.update_vif_in_vm_config_model()

    #update Misc tab model!!! from gen_page
    def update_vif_in_vm_config_model(self):
        self._gather_nw(self.context)
        if self.context.misc_page:
            self.context.misc_page.scatter(self.context)

    def get_new_nw_entry(self, image_conf = None):
        return (vifEntry('mac=$AUTOGEN_MAC,bridge=$DEFAULT_BRIDGE'), None)


    def on_nw_add_clicked(self, widget):
        if self.context.mode in ["EDIT_IMAGE","PROVISION_VM"]:
            (vif_entry, nw_entry) = self.get_new_nw_entry(self.context.image_config)
        else:
            # generate mac address and get the DEFAULT_BRIDGE if any
            mac=randomMAC()
            if self.context.managed_node is not None:
                bridge = self.context.managed_node.get_default_bridge()

            if not bridge:
                bridge="xenbr0"
            if self.context.managed_node.platform == 'kvm':
                bridge='br0'
                
            vif_entry=vifEntry('mac=%s,bridge=%s' % (mac,bridge))
            nw_entry = None
        dlg = self.get_nw_edit_dlg("ADD", 
                                   self.context.mode, 
                                   self.context.nw_manager,  
                                   self.context.managed_node,
                                   vif_entry, nw_entry, 
                                   self.context.parent_win) 
        
        ret = dlg.show()
        if ret == gtk.RESPONSE_OK:
            iter  = self.append_nw_entry(vif_entry)
            self.update_vif_in_vm_config_model()
        else:
            print "ret from nw append/edit dialog :", ret


    def on_nw_remove_clicked(self,widget):
        (model, iter) = self.widgets.vm_nw_view.get_selection().get_selected()
        if iter:
            model.remove(iter)
            self.update_vif_in_vm_config_model()
            
    def handle_nw_row_activated(self, treeview, path, column):
        self.on_nw_edit_clicked(self.widgets.vm_nw_props_btn)


    def find_nw(self, vif, context):
        nw_manager = context.nw_manager
        
        bridge_name = vif.get_bridge()
        for defn in nw_manager.get_defns(None,
                                         self.context.managed_node.hostname):
            if defn.bridge_info and defn.bridge_info.name == bridge_name:
                return defn
    
    # given the context give reasonable entries to display.
    def get_nw_details(self, vif, nw):
        nw_bridge_name = vif.get_bridge()
        nw_mac = vif.get_mac()
        if nw_mac == "$AUTOGEN_MAC":
            nw_mac = "Autogenerated"

        if nw_bridge_name == "$DEFAULT_BRIDGE":
            nw_bridge_name = "Default"

        if not nw:
            nw_name = nw_bridge_name + " Network"
            nw_type = NwDef.PUBLIC_NW
            nw_desc = nw_bridge_name
        else:
            nw_name = nw.name
            nw_type = nw.type
            nw_desc = "%s (%s)" % (nw.get_definition(), vif.get_bridge())
            

        return (nw_type, nw_name, nw_desc, nw_mac)

    def scatter_nw(self, context):
        vm_config = context.vm_config
        if not vm_config:
            return
        vifs = vm_config.getNetworks()
        model = self.widgets.vm_nw_view.get_model()
        model.clear()
        for vif in vifs:
            self.append_nw_entry(vif)

    def append_nw_entry(self, vif_entry):
        nw = self.find_nw(vif_entry, self.context)
        (nw_type, nw_name, nw_desc, nw_mac) = self.get_nw_details(vif_entry, nw)
        model = self.widgets.vm_nw_view.get_model()
        iter = model.append([nw_type, nw_name, nw_desc,
                             nw_mac,
                             vif_entry, nw])
            
    def _gather_nw(self, context):
        vm_config = context.vm_config
        if not vm_config:
            return
        view = self.widgets.vm_nw_view
        model = view.get_model()
        vifs = []
        iter = model.get_iter_first()
        while iter:
            vif_entry = model.get_value(iter, self.VIF_ENTRY)
            vifs.append(repr(vif_entry))
            iter = model.iter_next(iter)

        vm_config["vif"] = vifs



    def gather_nw(self, context):
        # everything handled by _gather_nw and update_vif_in_misc_page
        pass
    

class BootPage(Page):
    def __init__(self, context):
        Page.__init__(self)
        self.context = context
        self.ui_init(context)
        
    def ui_init(self, context):
        wtree = context.wtree

        self.init_widgets(wtree, ["kernel_label",
                                  "vm_kernel_entry",
                                  "kernel_selector_btn",
                                  "kernel_hbox",
                                  "ramdisk_label",
                                  "vm_ramdisk_entry",
                                  "ramdisk_selector_btn",
                                  "ramdisk_hbox",
                                  "vm_root_device_label",
                                  "vm_root_device_entry",
                                  "vm_kernel_args_label",
                                  "vm_kernel_args_entry",
                                  "vm_on_power_off_combo",
                                  "vm_on_reboot_combo",
                                  "vm_on_crash_combo",
                                  'boot_page_content',
                                  'vm_boot_param_label',
                                  'vm_boot_param_table'])



        self.page_content_widget = self.widgets.boot_page_content
        self.page_tab_widget     = self.widgets.vm_boot_param_label

        for widget in ("vm_on_power_off_combo",
                       "vm_on_reboot_combo",
                       "vm_on_crash_combo"):
            init_combo(self.widgets[widget], self.get_shutdown_event_map())

        wtree.signal_connect("on_kernel_selector_btn_clicked",
                             self.on_kernel_selector_clicked)
        wtree.signal_connect("on_ramdisk_selector_btn_clicked",
                             self.on_ramdisk_selector_clicked)



    def on_kernel_selector_clicked(self, widget):
        file_selector(widget,self.context.managed_node,
                      field=self.widgets.vm_kernel_entry,
                      fstype="open", parentwin=None)


    def on_ramdisk_selector_clicked(self, widget):
        file_selector(widget,self.context.managed_node,
                      field=self.widgets.vm_ramdisk_entry,
                      fstype="open", parentwin=None)



    def get_shutdown_event_map(self):
        return { "Destroy" : "destroy",
                 "Restart" :"restart",
                 "Preserve" : "preserve",
                 "Rename-Restart" : "rename-restart"
                 }

    def get_page_widgets():
        return self.page_tab_widget, self.page_content_widget

    # container methods
    def get_widgets_to_hide(self, mode):
        return []

    def get_widgets_to_disable(self, mode):
        if mode == "EDIT_VM_INFO":
            return [ self.widgets[w] for w in["kernel_label",
                                              "vm_kernel_entry",
                                              "kernel_selector_btn",
                                              "kernel_hbox",
                                              "vm_ramdisk_label",
                                              "ramdisk_entry",
                                              "ramdisk_selector_btn",
                                              "ramdisk_hbox",
                                              "vm_root_device_entry",
                                              "vm_kernel_args_entry",
                                              "vm_on_power_off_combo",
                                              "vm_on_reboot_combo",
                                              "vm_on_crash_combo",
                                              ]]
        
        return []

    def scatter(self, context):
        mode = context.mode
        vm_config = context.get("vm_config")
        if vm_config:
            for widget, config_attr in (("vm_kernel_entry", "kernel"),
                                        ("vm_ramdisk_entry", "ramdisk"),
                                        ("vm_root_device_entry", "root"),
                                        ("vm_kernel_args_entry", "extra"),
                                        ("vm_on_power_off_combo",
                                         "on_shutdown"),
                                        ("vm_on_reboot_combo", "on_reboot"),
                                        ("vm_on_crash_combo", "on_crash")
                                        ):
                set_value(self.widgets[widget], vm_config.get(config_attr))

    def gather(self, context):
        mode = context.mode
        vm_config = context.get("vm_config")
        if mode in ["EDIT_VM_CONFIG", "PROVISION_VM", "EDIT_IMAGE"] and \
               vm_config:
            for widget, config_attr in (("vm_kernel_entry", "kernel"),
                                        ("vm_ramdisk_entry", "ramdisk"),
                                        ("vm_root_device_entry", "root"),
                                        ("vm_kernel_args_entry", "extra"),
                                        ("vm_on_power_off_combo",
                                         "on_shutdown"),
                                        ("vm_on_reboot_combo", "on_reboot"),
                                        ("vm_on_crash_combo", "on_crash")
                                        ):
                vm_config[config_attr] = get_value(self.widgets[widget])


class MiscPage(Page):
    def __init__(self, context, exclude_list = []):
        Page.__init__(self)
        self.context = context
        self.exclude_list = exclude_list
        self.ui_init(context)
        self.context.misc_page = self # Kludge


    def ui_init(self, context):
        wtree = context.wtree
        self.init_widgets(wtree, ["vm_props_view",
                                  "add_vm_props_btn",
                                  "remove_vm_props_btn",
                                  "misc_page_content",
                                  "misc_props_label"])

        self.page_content_widget = self.widgets.misc_page_content
        self.page_tab_widget = self.widgets.misc_props_label
        self.editor_view = PropertyEditorView(self.widgets.vm_props_view)

        # signal handlers
        wtree.signal_autoconnect(
            {"on_vm_props_add_clicked": self.editor_view.on_props_add,
             "on_vm_props_remove_clicked": self.editor_view.on_props_remove
             })

    def get_page_widgets():
        return self.page_tab_widget, self.page_content_widget

    # container methods
    
    def get_widgets_to_hide(self, mode):
        return []

    def get_widgets_to_disable(self, mode):
        if mode == "EDIT_VM_INFO":
            return [ self.widgets[w] for w in[ "vm_props_view",
                                               "add_vm_props_btn",
                                               "remove_vm_props_btn",
                                              ]]
        
        return []


    def scatter(self, context):
        mode = context.mode
        vm_config = context.get("vm_config")
        if vm_config :
            display_list = []
            if vm_config is not None:
                if mode != "EDIT_IMAGE":
                    customizable = vm_config.get_customizable_options()
                else:
                    customizable = vm_config.keys()
                for key in vm_config:
                    if key not in self.exclude_list and \
                       key not in vm_config.get_computed_options() and \
                       (mode == "EDIT_IMAGE" or key != vm_config.CUSTOMIZABLE_OPTIONS):
                        display_list.append(key)

                display_list.sort()
                # TBD : fold in ondisk ... here
                #editable = self.ondisk.get_active() and key in customizable
                editable = key in customizable

                model = self.editor_view.get_model()
                model.clear()
                for key in display_list:
                    iter = model.append()

                    model.set(iter,
                              0, key,
                              1, vm_config[key],
                              2, False,
                              3, editable,
                              4, not editable)

    def gather(self, context):
        vm_config = context.vm_config
        mode = context.mode
        if mode in ["EDIT_VM_CONFIG", "PROVISION_VM", "EDIT_IMAGE"] and \
               vm_config:
            model = self.widgets.vm_props_view.get_model()
            #+ self.domconfig.get_computed_options()
            update_config_props(vm_config,
                                model,
                                self.exclude_list)



class ProvisionPage(Page):
    def __init__(self, context):
        Page.__init__(self)
        self.context = context
        self.ui_init(context)

    def ui_init(self, context):
        wtree = context.wtree
        self.init_widgets(wtree, ["prov_props_view",
                                  "prov_props_update_image_check_btn",
                                  "add_image_props_btn",
                                  "remove_image_props_btn",
                                  "prov_page_content",
                                  "provisioning_label",
                                  ])
        
        self.prov_page_content_widget = self.widgets.prov_page_content
        self.prov_page_tab_widget = self.widgets.provisioning_label

        self.editor_view = PropertyEditorView(self.widgets.prov_props_view)

        # Kiudge : required by disk edit handlers
        self.context.provisioning_page = self

        # signal handlers
        wtree.signal_autoconnect(
            {"on_image_props_add_clicked": self.editor_view.on_props_add,
             "on_image_props_remove_clicked": self.editor_view.on_props_remove
             })


    def get_page_widgets(self):
        return (self.prov_page_tab_widget,self.prov_page_content_widget)

    def get_widgets_to_hide(self, mode):
        return [self.widgets.prov_props_update_image_check_btn,]


    def get_widgets_to_disable(self, mode):
        return []


    def scatter(self, context):
        mode = context.mode
        if mode in ["PROVISION_VM", "EDIT_IMAGE"]:
            display_list = []
            image_config = context.image_config
            if image_config is not None:
                if mode != "EDIT_IMAGE" :
                    customizable = image_config.get_customizable_options()
                else:
                    customizable = image_config.keys()

                for key in image_config:
                    if  key not in image_config.get_computed_options() and \
                           (mode == "EDIT_IMAGE" or key != self.context.image_config.CUSTOMIZABLE_OPTIONS):
                        display_list.append(key)

                display_list.sort()
                model = self.editor_view.get_model()
                model.clear()
                for key in display_list:
                    iter = model.append()
                    #editable = self.ondisk.get_active() and key in customizable
                    editable = key in customizable
                    model.set(iter,
                              0, key,
                              1, image_config[key],
                              2, False,
                              3, editable,
                              4, not editable)


    def gather(self, context):
        image_config = context.image_config
        mode = self.context.mode
        if mode in ["PROVISION_VM", "EDIT_IMAGE"] and \
               image_config:
            model = self.widgets.prov_props_view.get_model()
            #+ self.domconfig.get_computed_options()
            update_config_props(image_config,
                                model)
    def validate(self):
        errmsgs = []

        model = self.editor_view.get_model()
        iter = model.get_iter_first()
        while iter:
            (key, val) = (model.get_value(iter, 0),
                          model.get_value(iter, 1))
            if key in ("VM_CONF_DIR", "VM_DISKS_DIR"):
                if val and val.find(" ") > -1:
                    errmsgs.append("Provisioning Tab : %s can not contain spaces '%s'" % (key,val))

            iter=model.iter_next(iter)

        return errmsgs
            

class VMNotebook(Notebook, Page):
    def __init__(self, context):
        Page.__init__(self)
        self.context = context
        wtree = context.wtree
        self.exclude_list = self.get_exclude_list()
        Notebook.__init__(self, get_widget(wtree,"vm_notebook"))
        
        self.ui_init(context)

    # information already collected via other tabs and should be
    # excluded from the misc tab.
    def get_exclude_list(self):
        return [ "name", "memory", "kernel", "ramdisk", "root",
                 "cpus", "extra", "vcpus", "on_shutdown",
                 "on_reboot", "on_crash", "bootloader", "disk", "STORAGE_STATS" ]


    def ui_init(self, context):
        wtree = context.wtree
        self.init_widgets(wtree, ['vm_vm_label'])
        self.page_tab_widget = get_widget(wtree, "vm_vm_label")
        self.page_content_widget = get_widget(wtree, "vm_notebook")

    # Required by Notebook
    def get_pages(self):
        return  [("general_page", self.get_gen_page()),
                 ("boot_page", self.get_boot_page()),
                 ("misc_page", self.get_misc_page())]

    def get_gen_page(self):
        return GeneralPage(self.context)

    def get_boot_page(self):
        return BootPage(self.context)

    def get_misc_page(self):
        return MiscPage(self.context, self.get_exclude_list())

    # Required by Page
    def get_page_widgets(self):
        return (self.page_tab_widget, self.page_content_widget)



    
# contains the VM and Provisioning tabs/pages
class SettingsNotebook(Notebook):
    def __init__(self, context):
        self.context = context
        wtree = context.wtree
        Notebook.__init__(self, get_widget(wtree,"settings_notebook"))
        self.ui_init(context)
        
    def ui_init(self, context):
        wtree = context.wtree
        self.init_widgets(wtree, [])

    def get_pages(self):
        return [("vm_notebook", self.get_vm_notebook_page()),
                ("provisioning_page", self.get_provisioning_page()) ]

    def get_vm_notebook_page(self):
        return VMNotebook(self.context)

    def get_provisioning_page(self):
        return ProvisionPage(self.context)

    def update_widgets(self,mode):
        if not mode in ["PROVISION_VM", "EDIT_IMAGE"]:
            self.remove_page("provisioning_page")
        Notebook.update_widgets(self, mode)
        

# Class containing basic VM settings facilities
class VMSettingsDlg(Container):
    # mode : EDIT_VM_CONFIG, EDIT_VM_INFO, PROVISION_VM, EDIT_IMAGE
    # vm_config : config to be edited
    # vm : required for running vm information and change run time info
    # server_pool : server_pool context for using pool level properties.
    def __init__(self, mode, ctx, 
                 parent_win = None):
        Container.__init__(self)
        self.context = dynamic_map()
        self.context.mode = mode
        self.context.image_store = ctx.image_store
        self.context.managed_node = ctx.managed_node
        self.context.storage_manager = ctx.storage_manager
        self.context.nw_manager = ctx.nw_manager
        self.context.vm = ctx.vm
        if ctx.vm:
            self.context.vm_info = ctx.vm.get_info()
            self.context.vm_config = ctx.vm.get_config()
        
        self.context.image_id = ctx.image_id
        self.context.image_group_id = ctx.image_group_id
        self.context.server_pool = ctx.server_pool
        self.parent_win = parent_win
        self.context.new_vm_callback = ctx.new_vm_callback
        self.context.platform = ctx.platform
        self.hack_dont_change_mode = False
        self.hack_init_combos = True

        #
        if self.context.vm and self.context.vm.is_resident():
            print "Changing mode to EDIT_VM_INFO"
            self.context.mode = "EDIT_VM_INFO"

        if self.context.mode in ["EDIT_IMAGE", "PROVISION_VM"]:
           self.initialize_image_context(self.context,
                                         self.context.image_id)
                    
        
        self.ui_init(self.context)
        
        self.init_image_group_combo(self.context.image_store,
                                    self.context.image_group_id, mode,
                                    self.context.platform)
        self.init_image_combo(self.context.image_store,
                              self.context.image_group_id, mode)

        self.hack_init_combos = False
        

    def ui_init(self, context):
        wtree = gtk.glade.XML(gladefile, "VMSettingsDlg")
        context.wtree = wtree
        self.dialog = get_widget(wtree,"VMSettingsDlg")
        if self.parent_win:
            self.dialog.set_transient_for(self.parent_win)
        # add dialog to the context,
        # so that it can be used as parent for other transient dlg.
        context.parent_win = self.dialog 

        # whether to operate on vm config or vm info
        self.init_widgets(wtree, ["change_settings_label",
                                  "mem_radio",
                                  "disk_radio",
                                  "server_name_label",
                                  "server_name",
                                  "image_name_label",
                                  "image_combo",
                                  "image_group_name_label",
                                  "image_group_combo" ])
                           
        # Notebook and tabs
        self.settings_notebook = self.get_settings_notebook()

        # event handlers
        wtree.signal_autoconnect({"on_image_changed":self.on_image_changed,
                                  "on_image_group_changed":self.on_image_group_changed,
                                  "on_mem_radio_toggled" : self.mode_changed,
                                  #"on_disk_radio_clicked" : self.mode_changed
                                  }
                                 )


    def mode_changed(self, widget):
        if self.hack_dont_change_mode:
            return 
        if self.widgets.mem_radio.get_active():
            if self.context.vm and self.context.vm.is_resident():
                self.context.mode = "EDIT_VM_INFO"
                print "changed mode to ", self.context.mode
            else:
                print "ERROR : No vm_info for switching to EDIT_VM_INFO mode"
                return
        else:
            if self.context.vm_config != None:
                self.context.mode = "EDIT_VM_CONFIG"
                print "changed mode to ", self.context.mode
            else:
                print "ERROR : No vm_config for switching to EDIT_VM_CONFIG mode"
                return

        self.update_widgets(self.context.mode)
        self.scatter(self.context)

    def get_settings_notebook(self):
        return SettingsNotebook(self.context)

    # When image group changes, 
    #    get all the images for the selected image group
    #    select the 1st image in the list.
    def on_image_group_changed(self, widget):
        if self.hack_init_combos:
            return
        image_group_id = get_value(self.widgets.image_group_combo)
        if self.context.mode == "PROVISION_VM":
            if self.context.managed_node is None:
                return
            if image_group_id is not None and image_group_id.strip() != '':
                self.init_image_combo(self.context.image_store,
                                      image_group_id,
                                      self.context.mode)

                iter = self.widgets.image_combo.get_model().get_iter_first()
                if iter:
                    self.widgets.image_combo.set_active_iter(iter)
                self.on_image_changed(None)
                
    def on_image_changed(self, widget):
        if self.hack_init_combos:
            return
        image_id = get_value(self.widgets.image_combo)
        if self.context.managed_node is None:
            return
        if self.context.mode == "PROVISION_VM":

            if image_id is not None and image_id.strip() != '':
                self.initialize_image_context(self.context,image_id)
            
            if self.context.server_pool is not None:
                self.grp_settings = self.context.server_pool.getGroupVars()
                merge_pool_settings(self.context.vm_config,
                                          self.context.image_config,
                                          self.grp_settings, True) 
            self.settings_notebook.scatter(self.context)

    # all widgets
    def get_widgets_to_disable(self, mode):
        if mode in ["EDIT_IMAGE",]:
            return [ self.widgets[w] for w in ["image_combo", "image_group_combo"
                                               ]]
        if mode in ["EDIT_VM_INFO", "EDIT_VM_CONFIG"]:
            wlist = ["image_combo", "image_group_combo"]
            if self.context.vm is None or self.context.vm.is_resident()==False:
                wlist.append("mem_radio")
            if self.context.vm_config is None:
                wlist.append("disk_radio")
            return [ self.widgets[w] for w in wlist ]

        #If image id and group id are available then lock them.
        if mode in ["PROVISION_VM",]:
            if self.context.image_id is not None and self.context.image_group_id is not None:
                return [ self.widgets[w] for w in ["image_combo", "image_group_combo"] ]
        

                        
        return []

    def get_widgets_to_hide(self, mode):
        if mode in [ "PROVISION_VM"]:
            return [ self.widgets[w] for w in [
                                               "change_settings_label",
                                               "mem_radio",
                                               "disk_radio"
                                               ]]
        if mode in ["EDIT_IMAGE",]:
            return [ self.widgets[w] for w in [
                                                "change_settings_label",
                                                "mem_radio",
                                                "disk_radio",
                                                "server_name_label",
                                                "server_name"
                ]]

        if mode in [ "EDIT_VM_CONFIG", "EDIT_VM_INFO" ]:
            return [ self.widgets[w] for w in [ "image_group_combo",
                                                "image_group_name_label" 
                                                ]]
        return []


    def update_widgets(self, mode):
        Container.update_widgets(self, mode)
        self.settings_notebook.update_widgets(mode)

    # take a context available and populate UI
    def scatter(self, context):
        # code to scatter cotnext in to widgets
        image_store = context.image_store
        managed_node = context.managed_node
        mode = context.mode
        vm_config = context.vm_config

        if mode in ["PROVISION_VM", "EDIT_IMAGE"]:
            if self.context.image_group_id:
                self.hack_init_combos = True
                set_value(self.widgets.image_group_combo,
                          self.context.image_group_id)
                self.hack_init_combos = False
            else :
                iter = self.widgets.image_group_combo.get_model().get_iter_first()
                if iter:
                    self.widgets.image_group_combo.set_active_iter(iter)

                
        if mode in ["EDIT_VM_CONFIG", "EDIT_VM_INFO"]:
            if vm_config:
                #print "setting combo value "
                set_combo_value(self.widgets.image_combo,
                                vm_config.get('image_id')
                                )
        elif mode in ["EDIT_IMAGE", "PROVISION_VM" ]:
            #print "#### setting combo to  ", self.context.image_id
            set_value(self.widgets.image_combo, self.context.image_id)
    

        self.widgets.server_name.set_text(managed_node.hostname)
        # call the contained elements to do the same.
        self.settings_notebook.scatter(context)



    # update the context with the changes from the UI.
    def gather(self, context):
        # code to gather info from the widgets and update context

        # let contained elements also do the same.
        self.settings_notebook.gather(context)


    def validate(self):
        # validate local stuff


        # validate notebook.
        return self.settings_notebook.validate()

    # Initialize image group combobox.
    # If image group id is provided, then set it.
    def init_image_group_combo(self, image_store, image_group_id,
                               mode, platform = None):
        image_group_combo = self.widgets.image_group_combo
        model = image_group_combo.get_model()
        model.clear()
        # populate the image list
        image_group = None
        if image_group_id is not None :
            i_group = image_store.get_image_group(image_group_id)
        image_groups = image_store.get_image_groups()
        image_group_map = {}

        for image_group in image_groups.itervalues():
 
            if mode == "PROVISION_VM":
                count = 0
                images = image_group.get_images()
                for image in images.itervalues():
                    try:
                        if self.context.managed_node.is_image_compatible(image):
                            count=count+1
                            break
                    except Exception, ex:
                        traceback.print_exc()
                        print "Error initializing image group %s,%s,%s" % \
                            (image_group.get_name(), image.get_name(), str(ex))
                if count > 0:        
                    image_group_map[image_group.get_name()] = image_group.get_id()
                else:
                    print "Skipping Image group '%s' as no suitable images found." % (image_group.get_name())

            else:
                image_group_map[image_group.get_name()] = image_group.get_id()
            

        
        init_combo(self.widgets.image_group_combo, image_group_map)


    def init_image_combo(self, image_store, image_group_id,
                         mode):
        image_combo = self.widgets.image_combo
        model = image_combo.get_model()
        model.clear()
        # populate the image list
        image_group = None
        images = None
        image_map = {}
        if image_group_id is not None :
            image_group = image_store.get_image_group(image_group_id)
            images = image_group.get_images()
        else:
            images = image_store.get_images()

        for image in images.itervalues():
            try: 
                if mode != "EDIT_IMAGE":
                    if image.is_template:
                        continue
                if mode == "PROVISION_VM" and self.context.managed_node is not None:
                    if not self.context.managed_node.is_image_compatible(image):
                        print "skipping image ", image.get_name(), image.get_platform(), self.context.managed_node.get_platform(),image.is_hvm()
                        continue
                    else:
                        print "Adding image to Combo ", image.get_name(), image.get_platform(), self.context.managed_node.get_platform(), image.is_hvm()
                image_map[image.get_name()] = image.get_id()
            except Exception, ex:
                traceback.print_exc()
                print "Error adding image %s, %s" % (image.get_name(),str(ex))
                

        #import pprint; pprint.pprint(image_combo)
        init_combo(self.widgets.image_combo, image_map)

        
    def show(self):
        mode = self.context.mode
        self.update_widgets( mode)

        ## special case
        
        vm = self.context.vm
        self.hack_dont_change_mode = True
        if mode == "EDIT_VM_INFO":
            set_value(self.widgets.mem_radio, True)
        else:
            set_value(self.widgets.disk_radio, True)
        self.hack_dont_change_mode = False
        
        self.scatter(self.context)
        ret = None

        while ret != gtk.RESPONSE_DELETE_EVENT :
            ret = self.dialog.run()
            if ret in (gtk.RESPONSE_CANCEL, gtk.RESPONSE_OK):
                if ret == gtk.RESPONSE_OK:
                    try:
                        msgs = self.validate()
                        if not msgs or len(msgs) == 0:
                            self.gather(self.context)
                            self.save(self.context)
                            break
                        else:
                            show_validation_msgs(msgs, self.context.parent_win)
                    except Exception, ex:
                        traceback.print_exc()
                        showmsg("Ex :" + str(ex), self.context.parent_win)
                else:
                    break

        self.dialog.destroy()
        return ret

    ## This should get cut over to ImageStore/Image functions.
    ## so no need to mess around with local_node
    def initialize_image_context(self, context, image_id):
        image = self.context.image_store.get_image(image_id)
        if not image:
            return
        vm_config,img_config = image.get_configs()
        self.context.vm_config = vm_config

        if self.context.mode == "PROVISION_VM":
            self.context.vm_config["name"] = ""
        
        # get the image conf related properties
        self.context.image_config = img_config


    def save(self, context):
        vm_config = context.vm_config

        initial_disks=[]
        final_disks=[]
        
        if context.mode in ["EDIT_VM_CONFIG", ]:
            vm_config.update_storage_stats()
        if context.mode in ["EDIT_VM_CONFIG", "EDIT_IMAGE"]:
            vm_config.write()
        if context.mode == "EDIT_IMAGE":
            self.context.image_config.write()
        if context.mode == "PROVISION_VM":
            self.kick_off_provisioning(context)
        if context.mode == "EDIT_VM_INFO":
            vm = self.context.vm
            mem = self.context.vm_info["memory"]
            vcpus = self.context.vm_info["online_vcpus"]
            vm.setMem(mem)
            vm.setVCPUs(vcpus)
            
            # if there is no associated vm config.
            # skip rest of the things.
            # This will also enable the Dom0 mem setting 
            # changes.
            if not vm_config:
                print "No associated VM config found."
                return

            # update the vmconfig for the next run
            vm_config["memory"] = mem
            vm_config["vcpus"] = vcpus

            initial_disks=vm_config["init_disks"]
            del vm_config["init_disks"]

            final_disks=vm_config["disk"]

            detach_disk_list=[]
            attach_disk_list=[]
            if initial_disks:
                detach_disk_list=[val for val in initial_disks if val not in final_disks]
                attach_disk_list=[val for val in final_disks if val not in initial_disks]
            else:
                attach_disk_list=final_disks

#            print "attach==",attach_disk_list
#            print "detach==",detach_disk_list

            if detach_disk_list:
                vm.detachDisks(detach_disk_list)
            if attach_disk_list:
                vm.attachDisks(attach_disk_list)

            vm_config.update_storage_stats()
            vm_config.write()

    def kick_off_provisioning(self, context):
        # instantiate the configs
        v_config = copy.copy(self.context.vm_config)
        i_config = copy.copy(self.context.image_config)

        # add/set a uui to the config
        v_config["uuid"] = uuidToString(randomUUID())

        # create is_remote map by position.
        # COMPLETE HACK need to think if this can be handled better.
        
        img_name = self.widgets.image_combo.get_active_text()
        image_id = get_value(self.widgets.image_combo)

        callback = self.context.new_vm_callback

        store,managed_node,vm_config_file=vm_config_write(context,image_id,v_config,
                                            i_config,img_name)
        out = None
        exit_code = None
        log = None
        try:
            progress = TaskProgressWnd("Provisioning Image : "+ \
                                       img_name,
                                       "Provisioning...",
                                       can_cancel=False)

            progress.update(progress.START_PULSE, "Provisioning...")
            vm_name =  v_config["name"]
            w = Worker(lambda :store.execute_provisioning_script(
                                     managed_node,
                                     image_id,
                                     v_config,
                                     i_config),
                       lambda ret=None: self.suc_callback(managed_node,
                                                          vm_name,
                                                          vm_config_file,
                                                          progress,
                                                          ret,
                                                          callback),
                       lambda ex=None: self.failure_cb(progress,
                                                       ex)
                       )
            w.start()
            progress.show(parentwin =self.dialog)

        finally:
            pass

    def suc_callback(self, managed_node, vm_name,vm_config_file,
                     progress, ret, new_vm_callback):
        progress.set_return_val(ret)
        if ret :
            (out, exit_code, log) = ret
            print "============ LOG ============" 
            print log
            print "============ OUT ============"
            print out
        if exit_code == 0:
            progress.update(progress.COMPLETE, vm_name + ": Provisioning successful")
            try:
                gtk.gdk.threads_enter()
                managed_node.add_dom_config(vm_config_file)
            finally:
                gtk.gdk.threads_leave()
                
            # already protected code.
            if new_vm_callback:
                new_vm_callback(managed_node.hostname, select=False)
        else:
            progress.update(progress.CLOSE, vm_name + ": Provisioning failed.")
            msg = vm_name +  ": Provisioning Failed"
            try:
                gtk.gdk.threads_enter()
                provisioning_status_dlg = ProvStatusDlg()
                provisioning_status_dlg.show(None, # widget
                                             msg,
                                             managed_node,
                                             log_filename=log,
                                             output=out,
                                             parentwin = None)
            finally:
                gtk.gdk.threads_leave()
            
            return
        

    def failure_cb(self,progress, ex):
        # both functions are safe and gtk locks not required.
        progress.set_exception(ex)
        progress.update(progress.COMPLETE, "Error while provisioning.\n" + \
                            str(ex))
        




    
    
    
