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

import types
import os, sys, re
import gtk, gtk.glade, gobject
import xmlrpclib
import convirt.core.utils.constants
from convirt.core.model.ManagedNode import ManagedNode, NodeException
from convirt.core.model.VM import VM
from convirt.core.model.storage import *
from convirt.core.utils.NodeProxy import Node
from convirt.core.utils.utils import XMConfig, is_host_remote, randomMAC, fetch_isp, show_url, get_path, guess_value
import urllib, urlparse
import xml.parsers.expat
import stat, time
import traceback
from convirt.core.model.Groups import ServerGroup
from convirt.core.model.ImageStore import ImageStore
from convirt.client.htmltextview import HtmlTextView
import webbrowser
from convirt.core.utils.phelper import PHelper, AuthenticationException


utils = convirt.core.utils.utils
constants = convirt.core.utils.constants


class AddServerGroupDialog:
    """ Class that handles adding new Server Pool"""

    initialized = False

    def __init__(self, wtree, left_nav):
        """ Constructor"""
        self.left_nav = left_nav

        self.dialog = wtree.get_widget("AddServerPool")
        self.group_name = wtree.get_widget("server_pool_name")

        self.group_name.set_activates_default(True)
        self.dialog.set_default_response(gtk.RESPONSE_OK)

        if not AddServerGroupDialog.initialized :
            # setup handlers
            wtree.signal_connect("on_add_server_pool_cancelbutton_clicked",
                                 self.on_cancel_button_clicked)
            wtree.signal_connect("on_add_server_pool_okbutton_clicked",
                                 self.on_ok_button_clicked)
            AddServerGroupDialog.initialized = True

        self.init()

    def init(self):
        self.group_name.set_text("")


    def show(self):
        """ Displays add server pool dialog"""

        ret = self.dialog.run()
        if ret == gtk.RESPONSE_DELETE_EVENT:
            self.dialog.hide()


    def on_cancel_button_clicked(self, widget):
       """  Cancel on add server pool dialog """
       self.init()
       self.dialog.hide()

    def on_ok_button_clicked(self, widget):
       """  Ok  button on add server pool """
       # validate parameters
       if self.group_name.get_text() == "":
           showmsg("Please enter valid group name")
           return

       try:
           group = ServerGroup(self.group_name.get_text())
           self.left_nav.add_group(group)
       except Exception , ex:
           showmsg(ex)
           return

       self.init()
       self.dialog.hide()


class CloneImageDialog:
    """ Class clone image """

    initialized = False

    def __init__(self, wtree, left_nav):
        """ Constructor"""
        self.left_nav = left_nav

        self.dialog = wtree.get_widget("CloneImage")
        self.img_name = wtree.get_widget("clone_image_name")
        self.selected_image_label  = wtree.get_widget("clone_selected_image")

        if not CloneImageDialog.initialized :
            # setup handlers
            wtree.signal_connect("on_clone_img_cancelbutton_clicked",
                             self.on_cancel_button_clicked)
            wtree.signal_connect("on_clone_img_okbutton_clicked",
                             self.on_ok_button_clicked)
            self.img_name.set_activates_default(True)
            self.dialog.set_default_response(gtk.RESPONSE_OK)
            CloneImageDialog.initialized = True

        self.init()

    def init(self):
        self.img_name.set_text("")


    def show(self, image_store, group_id, image_id):
        """ Displays clone image dialog"""
        self.image_store = image_store
        self.src_group_id = group_id
        self.src_image_id = image_id
        self.src_image_name = image_store.images[image_id].get_name()
        self.init()

        self.selected_image_label.set_text("Selected Image : " + self.src_image_name)
        ret = self.dialog.run()
        if ret == gtk.RESPONSE_DELETE_EVENT:
            self.dialog.hide()


    def on_cancel_button_clicked(self, widget):
       """  Cancel on clone image dialog """
       self.init()
       self.dialog.hide()

    def on_ok_button_clicked(self, widget):
       """  Ok  button on add server pool """
       # validate parameters
       img_name = self.img_name.get_text()
       if img_name == "":
           showmsg("Please enter valid image name")
           return
       img_name = img_name.strip()
       # may be we should change spaces to underscore ourselves.
# Image name can contain the special characters.       
#       if re.sub(ImageStore.INVALID_CHARS_EXP,"", img_name) != img_name:
#           showmsg("Image name can not contain any special chars %s" % \
#                              ImageStore.INVALID_CHARS)
#           return

       src_group = self.image_store.get_image_group(self.src_group_id)
       
       if src_group.image_exists_by_name(img_name):
           showmsg("Image already exists.")
           return

       self.image_store.clone_image(self.src_group_id, self.src_image_id,  img_name)
       self.left_nav.refresh_nodes()
       self.left_nav.set_selection("Image Store",
                                   self.left_nav.IMAGE_STORE,
                                   op="row-activated")
       self.init()
       self.dialog.hide()


class RenameImageDialog:
    """ Class rename image """

    initialized = False

    def __init__(self, wtree, left_nav):
        """ Constructor"""
        self.left_nav = left_nav

        self.dialog = wtree.get_widget("RenameImage")
        self.img_name = wtree.get_widget("image_name")
        self.selected_image_label  = wtree.get_widget("selected_image")

        if not RenameImageDialog.initialized :
            # setup handlers
            wtree.signal_connect("on_rename_img_cancelbutton_clicked",
                                 self.on_cancel_button_clicked)
            wtree.signal_connect("on_rename_img_okbutton_clicked",
                                 self.on_ok_button_clicked)
            self.img_name.set_activates_default(True)
            self.dialog.set_default_response(gtk.RESPONSE_OK)
            RenameImageDialog.initialized = True

        self.init()

    def init(self):
        self.img_name.set_text("")


    def show(self, image_store, group_id, image_id):
        """ Displays rename image dialog"""
        self.image_store = image_store
        self.src_group_id = group_id
        self.src_image_id = image_id
        self.src_image_name = image_store.images[image_id].get_name()
        self.init()

        self.selected_image_label.set_text("Selected Image : " + self.src_image_name)
        ret = self.dialog.run()
        if ret == gtk.RESPONSE_DELETE_EVENT:
            self.dialog.hide()


    def on_cancel_button_clicked(self, widget):
       """  Cancel on rename image dialog """
       self.init()
       self.dialog.hide()

    def on_ok_button_clicked(self, widget):
       """  Ok  button on rename image """
       # validate parameters
       img_name = self.img_name.get_text()
       if img_name == "":
           showmsg("Please enter valid image name")
           return
       img_name = img_name.strip()
       # may be we should change spaces to underscore ourselves.
# Image name can contain the special characters.       
#       if re.sub(ImageStore.INVALID_CHARS_EXP,"", img_name) != img_name:
#           showmsg("Image name can not contain any special chars %s" % \
#                              ImageStore.INVALID_CHARS)
#           return
       if img_name in self.image_store.images:
           showmsg("Image already exists.")
           return

       self.image_store.rename_image(self.src_group_id, self.src_image_id,  img_name)
       self.left_nav.refresh_nodes()
       self.left_nav.set_selection("Image Store",
                                   self.left_nav.IMAGE_STORE,
                                   op="row-activated")
       self.init()
       self.dialog.hide()


class RenameImageGroupDialog:
    """ Class rename image group"""

    initialized = False

    def __init__(self, wtree, left_nav):
        """ Constructor"""
        self.left_nav = left_nav

        self.dialog = wtree.get_widget("RenameImageGroup")
        self.img_group_name = wtree.get_widget("img_group_name")
        self.selected_image_group_label  = wtree.get_widget("selected_image_group")

        if not RenameImageGroupDialog.initialized :
            # setup handlers
            wtree.signal_connect("on_rename_img_grp_cancelbutton_clicked",
                                 self.on_cancel_button_clicked)
            wtree.signal_connect("on_rename_img_grp_okbutton_clicked",
                                 self.on_ok_button_clicked)
            self.img_group_name.set_activates_default(True)
            self.dialog.set_default_response(gtk.RESPONSE_OK)
            RenameImageGroupDialog.initialized = True

        self.init()

    def init(self):
        self.img_group_name.set_text("")


    def show(self, image_store, group_id):
        """ Displays rename image group dialog"""
        self.image_store = image_store
        self.src_group_id = group_id

        self.src_image_name = image_store.image_groups[group_id].get_name()
        self.init()

        self.selected_image_group_label.set_text("Selected Image Group: " + self.src_image_name)
        ret = self.dialog.run()
        if ret == gtk.RESPONSE_DELETE_EVENT:
            self.dialog.hide()


    def on_cancel_button_clicked(self, widget):
       """  Cancel on rename image group dialog """
       self.init()
       self.dialog.hide()

    def on_ok_button_clicked(self, widget):
       """  Ok  button on rename image group"""
       # validate parameters
       img_name = self.img_group_name.get_text()
       if img_name == "":
           showmsg("Please enter valid image name")
           return
       img_name = img_name.strip()
       # may be we should change spaces to underscore ourselves.
# Image name can contain the special characters.       
#       if re.sub(ImageStore.INVALID_CHARS_EXP,"", img_name) != img_name:
#           showmsg("Image name can not contain any special chars %s" % \
#                              ImageStore.INVALID_CHARS)
#           return
       if img_name in self.image_store.image_groups:
           showmsg("Image already exists.")
           return

       self.image_store.rename_image_group(self.src_group_id,  img_name)
       self.left_nav.refresh_nodes()
       self.left_nav.set_selection("Image Store",
                                   self.left_nav.IMAGE_STORE,
                                   op="row-activated")
       self.init()
       self.dialog.hide()

class AddImageGroupDialog:
    """ Class that handles adding new Image Group"""

    initialized = False

    def __init__(self, wtree, left_nav):
        """ Constructor"""
        self.left_nav = left_nav

        self.dialog = wtree.get_widget("AddImageGroup")
        self.group_name = wtree.get_widget("image_group_name")

        self.group_name.set_activates_default(True)
        self.dialog.set_default_response(gtk.RESPONSE_OK)

        if not AddImageGroupDialog.initialized :
            # setup handlers
            wtree.signal_connect("on_add_image_group_cancelbutton_clicked",
                                 self.on_cancel_button_clicked)
            wtree.signal_connect("on_add_image_group_okbutton_clicked",
                                 self.on_ok_button_clicked)
            AddImageGroupDialog.initialized = True

        self.init()

    def init(self):
        self.group_name.set_text("")


    def show(self, image_store):
        """ Displays add image group dialog"""
        self.image_store = image_store
        ret = self.dialog.run()
        if ret == gtk.RESPONSE_DELETE_EVENT:
            self.dialog.hide()


    def on_cancel_button_clicked(self, widget):
       """  Cancel on add image group dialog """
       self.init()
       self.dialog.hide()

    def on_ok_button_clicked(self, widget):
       """  Ok  button on add image group """
       # validate parameters
       if self.group_name.get_text() == "":
           showmsg("Please enter valid group name") 
           return

       try:
           group = self.image_store.new_group(self.group_name.get_text()) 
           self.image_store.add_group(group)
           self.left_nav.refresh_nodes()
           self.left_nav.set_selection("Image Store",
                                   self.left_nav.IMAGE_STORE,
                                   op="row-activated")
       except Exception , ex:
           showmsg(ex)
           return

       self.init()
       self.dialog.hide()



class Cred:
    def __init__(self, username, password):
        self.username = username
        self.password = password

    def get_username(self):
        return self.username

    def get_password(self):
        return self.password



class CredentialsHelper:

    def __init__(self,wtree):
        self.wtree = wtree


    def get_credentials(self, hostname, username=None):
        dlg = CredentialsDialog(self.wtree)
        dlg.show(hostname, username)
        ret = dlg.dialog.run()
        cred = None
        if ret == gtk.RESPONSE_OK:
            cred = Cred(dlg.username.get_text(), dlg.password.get_text())
        dlg.init()
        return cred

class CredentialsDialog:
    """ Class that handles events from collecting credentials"""
    initialized = False
    def __init__(self, wtree):
        """ Constructor"""
        self.dialog = wtree.get_widget("Credentials")
        self.username = wtree.get_widget("cred_username")
        self.password = wtree.get_widget("cred_password")
        self.cred_label = wtree.get_widget("cred_label")

        self.password.set_activates_default(True)
        self.dialog.set_default_response(gtk.RESPONSE_OK)

        if not CredentialsDialog.initialized:
            # setup handlers
            wtree.signal_connect("on_cred_cancelbutton_clicked",
                                 self.on_cancel_button_clicked)
            wtree.signal_connect("on_cred_okbutton_clicked",
                                 self.on_ok_button_clicked)
            CredentialsDialog.initialized = True
        self.init()

    def init(self):
        self.username.set_text("")
        self.password.set_text("")

    def show(self, hostname, username = None):
        """ Displays initialization params dialog"""
        if username is not None:
            self.username.set_text(username)
            self.password.grab_focus()
        self.cred_label.set_text("Enter Credentials : " + hostname)
        #self.dialog.set_title("Credentials for " + hostname)
        self.dialog.show()

    def on_cancel_button_clicked(self, widget):
       """  Cancel on initialization params """
       self.dialog.hide()

    def on_ok_button_clicked(self, widget):
       """  Cancel creation of dom """
       self.dialog.hide()



class RemoteFileDialog:
    """ Simple dialog box to take file or path from the user """
    initialized = False
    def __init__(self, wtree):
        """ Constructor"""

        self.gladefile = gladefile
        self.wtree = gtk.glade.XML(self.gladefile, "RemoteFileDialog")

        self.dialog = self.wtree.get_widget("RemoteFileDialog")
        self.dirname = self.wtree.get_widget("remote_file_dirname")
        self.filename = self.wtree.get_widget("remote_file_filename")
        self.file_selector = self.wtree.get_widget("remote_file_selector")
        self.file_label = self.wtree.get_widget("remote_file_location_label")
        self.dir_label =  self.wtree.get_widget("remote_file_dir_label")
        self.hostname = self.wtree.get_widget("remote_file_hostname")
        self.frame_label = self.wtree.get_widget("remote_file_frame_title")
        self.dir_tree_view = self.wtree.get_widget("dir_tree_view")


        self.selected_file_dir = None
        self.multi_select=False
        
        # if not RemoteFileDialog.initialized:
        # setup handlers
        self.wtree.signal_connect("on_remote_file_cancel_button_clicked",
                             self.on_cancel_button_clicked)
        self.wtree.signal_connect("on_remote_file_okbutton_clicked",
                             self.on_ok_button_clicked)
        #wtree.signal_connect("on_remote_file_selectorButton_clicked",
        #                     self.on_file_selector_clicked)
        self.wtree.signal_connect("on_remote_file_selectorButton_clicked",
                             self.refresh_clicked)
        self.wtree.signal_connect("on_remote_file_dirname_activate",
                             self.refresh_clicked)
        self.wtree.signal_connect("on_remote_file_filename_activate",
                             self.on_filename_activated)
        self.wtree.signal_connect("on_dir_tree_view_row_activated",self.on_row_activated)
        self.init_view()
        RemoteFileDialog.initialized = True

        self.init()

    def init(self):
        self.dirname.set_text("")
        self.filename.set_text("")
        

    def on_filename_activated(self,widget):
        if self.filename.get_text():
            selection = self.dir_tree_view.get_selection()
            if selection:
                selection.unselect_all()
            self.on_ok_button_clicked(None)
            self.dialog.response(gtk.RESPONSE_OK)
            
        
    def on_row_activated(self,treeview,path,column):
        selection = self.dir_tree_view.get_selection()
        selected_list = []
        if selection:
           selection.selected_foreach(self.gather_selected, selected_list)
           if len(selected_list) > 0:
               selected = selected_list[0]
               if selected[0] and selected[1]: # its a dir
                   self.dirname.set_text(os.path.join(self.dirname.get_text(), selected[0]))
                   self.refresh_contents()
               elif selected[0] and not selected[1]:
                   if self.fstype != "folder_select": # default action
                       self.on_ok_button_clicked(None)
                       self.dialog.response(gtk.RESPONSE_OK)


        

    def get_file_pixbuf(self,column,cell,model,iter):
        is_dir = model.get_value(iter, 3)
        if is_dir:
            id = gtk.STOCK_DIRECTORY
        else:
            id = gtk.STOCK_FILE
        cell.set_property("stock-id", id)

    def init_view(self):
        self.model = gtk.ListStore(
                                   gobject.TYPE_STRING, # File/Dirname
                                   gobject.TYPE_STRING, # size
                                   gobject.TYPE_STRING, # Date Modified
                                   gobject.TYPE_BOOLEAN # is_directory
                                   )
        
        pbrenderer = gtk.CellRendererPixbuf()
        column = gtk.TreeViewColumn("", pbrenderer)
        column.set_cell_data_func(pbrenderer, self.get_file_pixbuf)
        self.dir_tree_view.append_column(column)

        textrenderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn("Name", textrenderer, text=0)
        column.set_expand(True)
        column.set_sort_column_id(0)
        self.dir_tree_view.append_column(column)

        textrenderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn("Date", textrenderer, text=2)
        column.set_sort_column_id(2)
        self.dir_tree_view.append_column(column)

        self.dir_tree_view.set_model(self.model)


    def show(self, managed_node,
             title, fstype, init_folder,
             init_file, parentwin, multi_select=False):

        self.init()
        self.managed_node = managed_node
        self.title = title
        self.fstype = fstype
        self.init_folder = init_folder
        self.init_file = init_file
        self.parentwin = parentwin
        self.multi_select = multi_select

        if self.parentwin:
            self.dialog.set_transient_for(self.parentwin)
            self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)

        uri="ssh://"+self.managed_node.username+"@"+managed_node.hostname
        self.hostname.set_text(uri)

        if self.multi_select:
            self.dir_tree_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
        else:
            self.dir_tree_view.get_selection().set_mode(gtk.SELECTION_SINGLE)

        if self.fstype == "select_folder":
            #self.file_label.set_text("Folder name")
            self.frame_label.set_markup("<b>Specify Folder </b>")
        else:
            #self.file_label.set_text("Filename")
            if multi_select:
                self.frame_label.set_markup("<b>Specify Filename(s) (You can select multiple files.) </b>")
            else:
                self.frame_label.set_markup("<b>Specify Filename </b>")

        self.dialog.set_title(title)

        # choose decent default
        if self.init_folder is not None and self.init_file is not None:
            # remove trailing / from path
            if self.init_folder.rfind("/") == len(self.init_folder) - 1:
                self.init_folder = self.init_folder[0:len(self.init_folder) -1]
            # remove leading / from filename
            if self.init_file.find("/") == 0:
                self.init_file = init_file[1:]

        if not self.init_folder :
            self.init_folder = "/"

        self.dirname.set_text(self.init_folder)

        if self.init_file is not None:
            self.filename.set_text(self.init_file)
        else:
            self.filename.set_text("")

        self.refresh_contents()

        ret = self.dialog.run()
        self.dialog.destroy()
        return ret

    def gather_selected(self, model, path, iter, selected):
        selected.append((model.get_value(iter,0), model.get_value(iter, 3)))

    def on_cancel_button_clicked(self, widget):
       """  Cancel on RemoteFileDialog  """
       return False

    def on_ok_button_clicked(self, widget):
       """  Ok on RemoteFileDialog """
       self.selected_file_dir = None
       sel = self.dir_tree_view.get_selection()
       
       selected_list = []
       selected = None
       if sel:
           sel.selected_foreach(self.gather_selected, selected_list)

       if self.fstype == "select_folder":
           self.selected_file_dir = self.dirname.get_text()
           if selected_list:
               selected=selected_list[0]
               if selected and selected[1]:
                   self.selected_file_dir = os.path.join( self.selected_file_dir, selected[0])
       else:
           # file selection
           if self.multi_select:
               # multi selection here.
               for selected in selected_list:
                   if selected[0] and not selected[1]: # its a file
                       fname = os.path.join(self.dirname.get_text(), selected[0])
                       if not self.selected_file_dir:
                           self.selected_file_dir = fname
                       else:
                           self.selected_file_dir = self.selected_file_dir + "," + fname
           else:
               #print "FILE : Single Select ..."
               if selected_list:
                   selected=selected_list[0]
               #print "selected is ", selected
               if selected and not selected[1]:
                   self.selected_file_dir = os.path.join(self.dirname.get_text(), selected[0])
               else:
                   self.selected_file_dir = os.path.join(self.dirname.get_text(),
                                                         self.filename.get_text())

       print "Finally ", self.selected_file_dir


    def refresh_clicked(self, widget):
        self.refresh_contents()
        

    def refresh_contents(self):
        model=self.dir_tree_view.get_model()
        model.clear()

        dir=self.dirname.get_text()
        try:
            dir_entries=self.managed_node.node_proxy.sftp_client.listdir_attr(dir)
        except Exception, ex:
            showmsg("Error getting directory listing for (%s) : %s " % (dir, str(ex)) , self.parentwin)
            return

        for e in dir_entries:
            mode = e.st_mode
            is_dir=bool(stat.S_ISDIR(mode))
            date_modified = time.strftime("%a %b %d %Y %H:%M",time.localtime(e.st_mtime))
            print e.filename, e.st_size, date_modified, is_dir
            model.append((e.filename, "%15d" % e.st_size, date_modified, is_dir))
    

    def on_file_selector_clicked(self, widget):
       """  file selector clicked on RemoteFileDialog """
       # force the file selection to local/mounted files.
       (res, selection) = file_selection(self.managed_node,
                                         self.title,
                                         self.fstype,
                                         self.init_folder, self.init_file,
                                         self.parentwin,
                                         force_local = True,
                                         multi_select = True)

       if res and selection:
           text = ""
           for file in selection:
               text= text + file + ","

           if len(text) > 0 and text[-1] == ",":
               text = text[0:-1]

           self.dirname.set_text(text)

    #def run(self):
    #    return self.dialog.run()

    def get_filename(self):
        print "RemoteFileDialog : returning ", self.selected_file_dir 
        return self.selected_file_dir


class FileViewEditDialog:
    """ Allow a text file to be viewed/edited """
    initialized = False
    def __init__(self, wtree):
        """ Constructor"""
        self.dialog = wtree.get_widget("FileViewEditDialog")
        self.save_button = wtree.get_widget("file_view_edit_save")
        self.cancel_button = wtree.get_widget("file_view_edit_cancel")
        self.file_content = wtree.get_widget("file_content")
        if not FileViewEditDialog.initialized:
            # setup handlers
            wtree.signal_connect("on_file_view_edit_save_clicked",
                                 self.on_save_button_clicked)
            wtree.signal_connect("on_file_view_edit_cancel_clicked",
                                 self.on_cancel_button_clicked)
            FileViewEditDialog.initialized = True

        self.managed_node = None
        self.filename = None
        self.parentwin = None
        self.editable = True

    #    self.init()

    #def init(self):
    #    self.file_content.set_text("")

    def show(self, widget,  managed_node, filename, content = None,editable=True,
             parentwin = None):

        self.managed_node = managed_node
        self.filename = filename
        self.parentwin = parentwin
        self.editable = editable
        if content is not None:
            self.text = content
            self.editable = False
        else:
            if managed_node is not None and filename is not None:
                self.text = self.get_text_from_file(self.managed_node,
                                                    self.filename)
            else:
                self.text = ""

        self.text_buffer = gtk.TextBuffer()
        self.text_buffer.set_text(self.text)
        self.file_content.set_buffer(self.text_buffer)
        if self.managed_node is not None and self.filename is not None:
            self.dialog.set_title("File : "+  \
                                  self.managed_node.hostname + ":" + self.filename)
        else:
            self.dialog.set_title("Content")

        # adjusts the buttons
        if not self.editable:
            self.save_button.set_label("Ok")
        else:
            self.save_button.set_label("Save")

        self.cancel_button.set_property("visible", self.editable)

        if parentwin:
            self.dialog.set_transient_for(parentwin)
            self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)


        #self.dialog.show()
        ret = self.dialog.run()
        if ret == gtk.RESPONSE_DELETE_EVENT:
            self.dialog.hide()


    def on_save_button_clicked(self, widget):
        """  Save on FileViewEditDialog  """
        if self.editable:
            buf = self.file_content.get_buffer()
            self.text = buf.get_text(buf.get_start_iter(),
                                     buf.get_end_iter())
            print "save to text  " , self.filename
            self.save_text_to_file(self.managed_node,self.filename, self.text)

        self.dialog.hide()

    def on_cancel_button_clicked(self, widget):
        """  Cancel on FileViewEditDialog """
        self.dialog.hide()

    def get_text_from_file(self, managed_node,filename):
        text=""
        file = managed_node.node_proxy.open(filename)
        lines = file.readlines()
        text = "".join(lines)
        file.close()
        return text

    def save_text_to_file(self, managed_node,filename, text):
        file = managed_node.node_proxy.open(filename, "w")
        file.write(text)
        file.close()


class NodeSelection:
    """ Show dialog with list of nodes and return the selection """
    initialized = False
    def __init__(self, wtree):
        """ Constructor"""

        self.dialog = wtree.get_widget("NodeSelection")
        self.node_list_view = wtree.get_widget("select_node_list")
        self.migrate_live_check_button = wtree.get_widget("migrate_live")
        self.select_node_label = wtree.get_widget("select_node_label")
        #self.node_list_view.set_activates_default(True)
        self.dialog.set_default_response(gtk.RESPONSE_OK)
        self.list_model = None
        self.selected_node_name = None
        self.selected_node = None
        self.selected_node_type = None
        self.allow_groups = False
        self.migration_mode = False
        self.migrate_live_selection = False
        self.selected_group_name = None

        pbrenderer = gtk.CellRendererPixbuf()
        column = gtk.TreeViewColumn("       ", pbrenderer)
        column.set_cell_data_func(pbrenderer, get_state_pixbuf)
        self.node_list_view.append_column(column)

        textrenderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn("Name", textrenderer, text=0)

        self.node_list_view.append_column(column)

        self.node_list_model = gtk.TreeStore(gobject.TYPE_STRING,
                                             gobject.TYPE_STRING,
                                             gobject.TYPE_PYOBJECT,
                                             gobject.TYPE_STRING,
                                             gobject.TYPE_STRING,
                                             gobject.TYPE_STRING)

        self.node_list_view.set_model(self.node_list_model)

        if not NodeSelection.initialized:
                        # setup handlers
            wtree.signal_connect("on_node_selection_ok_clicked",
                                 self.on_ok_button_clicked)
            wtree.signal_connect("on_node_selection_cancel_clicked",
                                 self.on_cancel_button_clicked)
            NodeSelection.initialized = True

    def get_selection(self):
        return (self.selected_node_name,
                self.selected_node_type,
                self.selected_node,
                self.selected_group_name,
                self.migrate_live_selection)


    def show(self, widget, manager, migration = False, allow_groups =False,
             parentwin = None, platform = None, image = None):

        self.parentwin = parentwin
        self.selected_node_name = None
        self.selected_node = None
        self.selected_node_type = None
        self.migrate_live_selection = False
        self.migration_mode = migration
        self.allow_groups = allow_groups

        if allow_groups:
            self.select_node_label.set_text("Select a Managed Server or a Server Pool.\nNOTE : Only connected servers would be shown here.")
        else:
            if self.migration_mode:
               	self.select_node_label.set_text("Select a Managed Server for migration.\nNOTE: Only connected servers would be shown here.")
            else:
            	self.select_node_label.set_text("Select a Managed Server.\nNOTE: Only connected servers would be shown here.")

        populate_nodes(manager, self.node_list_view, self.node_list_model,
                       False, platform, image)

        self.migrate_live_check_button.set_property("visible",
                                                    self.migration_mode)
        self.migrate_live_check_button.set_active(self.migration_mode)

        self.dialog.show()
        ret = self.dialog.run()
        if ret == gtk.RESPONSE_DELETE_EVENT:
            self.dialog.hide()


    def on_ok_button_clicked(self, widget):
        """  Ok on Select Node  """
        widget = self.node_list_view.get_selection()
        treemodel, treeiter = widget.get_selected()
        if treeiter:
            (name,type,node,group_name)= \
                                         (treemodel.get_value(treeiter, 0),
                                          treemodel.get_value(treeiter, 1),
                                          treemodel.get_value(treeiter, 2),
                                          treemodel.get_value(treeiter, 3))


            if type is not None and type == MANAGED_NODE or \
               (type is not None and type == SERVER_POOL and
                self.allow_groups == True):
                self.selected_node_name = name
                self.selected_node = node
                self.selected_node_type = type
                self.selected_group_name = group_name
                if self.migration_mode :
                    self.migrate_live_selection = self.migrate_live_check_button.get_active()
            else:
                showmsg("Invalid Selection.")
                return
        self.dialog.hide()

    def on_cancel_button_clicked(self, widget):
        """  Cancel on FileViewEditDialog """
        self.dialog.hide()



# Make this non-modal as now can be displayed from multiple
# provisioning dialogs.

class ProvStatusDlg:
    """Displays the status message and output and logfile"""
    def __init__(self):
        """ Constructor"""
        self.gladefile = gladefile
        self.wtree = gtk.glade.XML(self.gladefile, "ProvStatusDlg")
        self.dialog = self.wtree.get_widget("ProvStatusDlg")
        self.msg_widget = self.wtree.get_widget("msg_text")
        self.output = ""
        self.log_filename = None

        # setup handlers
        self.wtree.signal_connect("on_msg_close_clicked",
                                  self.on_close_button_clicked)
        self.wtree.signal_connect("on_msg_view_output_clicked",
                                  self.on_output_button_clicked)
        self.wtree.signal_connect("on_msg_view_log_clicked",
                                  self.on_log_button_clicked)

    def show(self, widget, msg, managed_node, log_filename, output,
             parentwin = None):

        self.managed_node = managed_node
        self.parentwin = parentwin
        self.msg = msg
        self.output = output
        self.log_filename = log_filename

        self.msg_widget.set_text(msg)

        if parentwin:
            self.dialog.set_transient_for(parentwin)
            self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)


        self.dialog.show()
        # Non-modal op now.
        #ret = self.dialog.run()
        #if ret == gtk.RESPONSE_DELETE_EVENT:
        #    self.dialog.hide()


    def on_output_button_clicked(self, widget):
        """  output button on ProvStatusDlg   """
        dlg = file_editor.show(widget,
                               None,
                               None,
                               content = self.output,
                               editable = False,
                               parentwin = self.dialog)

    def on_log_button_clicked(self, widget):
        """  output button on ProvStatusDlg   """
        dlg = file_editor.show(widget,
                               self.managed_node,
                               self.log_filename,
                               editable=False,
                               parentwin = self.dialog)



    def on_close_button_clicked(self, widget):
        """  Cancel on ProvStatusDlg """
        self.dialog.destroy()


class GetLocalIPDlg:

    def __init__(self):

        """ Constructor"""
        self.gladefile = gladefile
        self.wtree = gtk.glade.XML(self.gladefile, "local_ip_dlg")
        
        self.dialog = self.wtree.get_widget("local_ip_dlg")

        self.local_ip_entry = self.wtree.get_widget("local_ip_entry")

        self.dialog.set_default_response(gtk.RESPONSE_OK)
        # connect the handlers
        self.wtree.signal_connect("on_local_ip_cancel_clicked",
                                 self.on_cancel_clicked)
        self.wtree.signal_connect("on_local_ip_ok_clicked",
                             self.on_ok_clicked)


    def show(self, manager, local_node, parentwin = None):

        self.manager = manager
        self.local_node = local_node

        self.parentwin = parentwin

        if parentwin:
            self.dialog.set_transient_for(parentwin)
            self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)

        adr = local_node.get_address()
        if adr and adr.lower() != "localhost":
            self.local_ip_entry.set_text(adr)
        else:
            self.local_ip_entry.set_text("")

        self.dialog.show()
        ret = self.dialog.run()

        self.dialog.destroy()
        return ret

    def on_cancel_clicked(self, widget):
        return False



    def on_ok_clicked(self, widget):
        local_ip = self.local_ip_entry.get_text()
        local_ip = local_ip.strip()
        if not local_ip:
            showmsg("Please enter a hostname of IP address.")
            return
        self.local_node.set_address(local_ip)
        self.manager._save_node(self.local_node)
        return True




class MigrationChecksResultsDlg:

    (TYPE,CATEGORY,DETAILS) = range(3)

    def __init__(self):

        self.gladefile = gladefile
        self.wtree = gtk.glade.XML(self.gladefile, "MigrationResultDlg")
        self.dialog = self.wtree.get_widget("MigrationResultDlg")

        """ Constructor"""
        # the list view
        self.list_view = self.wtree.get_widget("m_chk_tree_view")

        # set default response
        self.dialog.set_default_response(gtk.RESPONSE_OK)

        # state variables
        self.list_model = None


        # lets populate the colums

        # ENABLE THIS FOR Warning/Error Icon
        pbrenderer = gtk.CellRendererPixbuf()
        column = gtk.TreeViewColumn("Type", pbrenderer)
        column.set_cell_data_func(pbrenderer, self.get_msg_type_pb)
        column.set_sort_column_id(self.TYPE)
        self.list_view.append_column(column)

        lt_textrenderer = gtk.CellRendererText()
        lt_textrenderer.set_property("xalign", 0.0)

        ## column = gtk.TreeViewColumn("Type", lt_textrenderer, text=0)
##         column.set_clickable(True)
##         column.set_sort_column_id(self.TYPE)
##         column.set_resizable(True)
##         self.list_view.append_column(column)


        textrenderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn("Category", textrenderer, text=1)
        column.set_clickable(True)
        column.set_sort_column_id(self.CATEGORY)
        column.set_resizable(True)
        self.list_view.append_column(column)

        textrenderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn("Message", textrenderer, text=2)
        column.set_clickable(True)
        column.set_sort_column_id(self.DETAILS)
        column.set_resizable(True)
        self.list_view.append_column(column)


        self.list_model = gtk.TreeStore(gobject.TYPE_STRING, # Type
                                        gobject.TYPE_STRING, # Category
                                        gobject.TYPE_STRING) # Message



        self.list_view.set_model(self.list_model)

        self.list_model.set_sort_column_id(self.TYPE, gtk.SORT_ASCENDING)


    def populate_list(self, err_list, warn_list):
        for err in err_list:
            (cat, msg) = err
            iter = self.list_model.insert_before(None, None)
            self.list_model.set(iter,
                                self.TYPE,"Error",
                                self.CATEGORY,cat,
                                self.DETAILS,msg)

        for warn in warn_list:
            (cat, msg) = warn
            iter = self.list_model.insert_before(None, None)
            self.list_model.set(iter,
                                self.TYPE,"Warning",
                                self.CATEGORY,cat,
                                self.DETAILS,msg)


    def get_msg_type_pb(self,column,cell,model,iter):
        type = model.get_value(iter, self.TYPE)
        id = None
        if type:
            if type == "Warning":
                id = gtk.STOCK_DIALOG_WARNING
            elif type == "Error":
                id = gtk.STOCK_DIALOG_ERROR

        cell.set_property('stock-id', id)

    def show(self, err_list, warn_list, parentwin=None):

        self.err_list = err_list
        self.warn_list = warn_list
        self.parentwin = parentwin

        if parentwin:
            self.dialog.set_transient_for(parentwin)
            self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)

        self.populate_list(self.err_list, self.warn_list)

        self.dialog.show()
        ret = self.dialog.run()
        self.dialog.destroy()

        if ret == gtk.RESPONSE_OK:
            return True
        else:
            return False

class ApplianceDetailsDlg:

    def __init__(self):

        """ Constructor"""
        self.gladefile = gladefile
        self.wtree = gtk.glade.XML(self.gladefile, "appliance_details_dlg")
        self.dialog = self.wtree.get_widget("appliance_details_dlg")

        self.w_app_protocol = self.wtree.get_widget("app_protocol")
        self.w_app_hostname = self.wtree.get_widget("app_hostname")
        self.w_app_port = self.wtree.get_widget("app_port")
        self.w_app_path = self.wtree.get_widget("app_path")

        self.w_app_mgmt_protocol = self.wtree.get_widget("app_mgmt_protocol")
        self.w_app_mgmt_port = self.wtree.get_widget("app_mgmt_port")

        self.dialog.set_default_response(gtk.RESPONSE_OK)
        # connect the handlers
        self.wtree.signal_connect("on_app_details_cancel_clicked",
                                 self.on_cancel_clicked)
        self.wtree.signal_connect("on_app_details_ok_clicked",
                             self.on_ok_clicked)

        self.mapping = ((self.w_app_protocol, "app_protocol",
                         "default_app_protocol"),
                        (self.w_app_hostname, "host",
                         "default_app_hostname"),
                        (self.w_app_port, "app_port", "default_app_port"),
                        (self.w_app_path, "app_path", "default_app_path"),
                        (self.w_app_mgmt_protocol, "app_mgmt_protocol",
                         "default_app_mgmt_protocol"),
                        (self.w_app_mgmt_port, "app_mgmt_port", "default_app_mgmt_port"))

        self.protocols = ["http", "https", "ssh_tunnel"]

    def show(self, vm_config, defaults={}, parentwin = None):

        self.vm_config = vm_config
        self.defaults = defaults

        self.parentwin = parentwin

        if parentwin:
            self.dialog.set_transient_for(parentwin)
            self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)



        # populate
        for w, vkey, dkey in self.mapping:
            val = self.vm_config.get(vkey)
            if not val:
                val = self.defaults.get(dkey)

            if not val:
                val = ""

            if isinstance(w, gtk.Entry):
                w.set_text(str(val))
            elif isinstance(w, gtk.ComboBox):
                print val
                if val in self.protocols:
                    w.set_active(self.protocols.index(val))
                else:
                    w.set_active(-1)

        self.dialog.show()
        ret = self.dialog.run()

        if ret == gtk.RESPONSE_OK:
            for w, vkey, dkey in self.mapping:
                if isinstance(w, gtk.Entry):
                    val = w.get_text()
                    if val and vkey in ("app_port", "app_mgmt_port"):
                        val = int(val)

                elif isinstance(w, gtk.ComboBox):
                    val = self.protocols[w.get_active()]
                self.vm_config[vkey] = val

            self.vm_config.write()
            self.dialog.destroy()
            return True
        else:
            self.dialog.destroy()
            return False

    def on_cancel_clicked(self, widget):
        return False


    def on_ok_clicked(self, widget):
        return True

class GroupVariablesDlg:
    """ Show dialog with list of group variables and return the selection """
    (COL_ATTR, COL_VAL, COL_EDITABLE) = range(3)
    def __init__(self, group_vars = None):
        """ Constructor"""
        print gladefile
        self.gladefile = gladefile
        self.wtree = gtk.glade.XML(self.gladefile, "GroupVariablesDlg")
        self.dialog = self.wtree.get_widget("GroupVariablesDlg")

        self.groupvar_list_view = self.wtree.get_widget("select_groupvar_list")
        self.dialog.set_default_response(gtk.RESPONSE_OK)
        self.groupvar_list_model  = gtk.ListStore( gobject.TYPE_STRING,
                                                   gobject.TYPE_STRING,
                                                   gobject.TYPE_BOOLEAN)

        self.groupvar_list_view.set_model(self.groupvar_list_model)
        self.groupvar_list_view.set_rules_hint(True)
        self.groupvar_list_view.get_selection().set_mode(gtk.SELECTION_SINGLE)

        self.groupvar_selected = {}


        renderer = gtk.CellRendererText()
        renderer.connect("edited", self.__on_props_cell_edited,
                         self.groupvar_list_model)
        renderer.connect("editing-started",
                         self.__on_props_cell_start_editing,
                         self.groupvar_list_model)


        
        renderer.set_data("column", self.COL_ATTR)

        column = gtk.TreeViewColumn("Variable", renderer, text=self.COL_ATTR,
                                    editable=self.COL_EDITABLE)

        self.groupvar_list_view.append_column(column)

        renderer = gtk.CellRendererText()
        renderer.connect("edited",
                         self.__on_props_cell_edited,
                         self.groupvar_list_model)
        renderer.connect("editing-started",
                         self.__on_props_cell_start_editing,
                         self.groupvar_list_model)


        renderer.set_data("column", self.COL_VAL)

        column = gtk.TreeViewColumn("Value", renderer, text=self.COL_VAL,
                                    editable=self.COL_EDITABLE)
        self.groupvar_list_view.append_column(column)

        self.wtree.signal_autoconnect(
            {
            "on_groupvar_ok_clicked": self.on_ok_button_clicked,
            "on_groupvar_cancel_clicked": self.on_cancel_button_clicked,
            "on_groupvar_add_clicked": ( self.on_add_button_clicked,
                                         self.groupvar_list_model,
                                         self.groupvar_list_view ),
            "on_groupvar_remove_clicked": self.on_remove_button_clicked,
             })

        #If group variables are provided then set them in the model.
        if  group_vars : # is not None:
            self.set_group_vars(group_vars)
        else:
            # put some dummy ones for users to understand
            group_vars = {}
            group_vars["CLASS_A_STORAGE"] = "#/mnt/nfs_share/class_a"
            group_vars["CLASS_B_STORAGE"] = "#/mnt/nfs_share/class_b"
            group_vars["VM_DISKS_DIR"] = "#/mnt/shared/vm_disk"
            group_vars["VM_CONF_DIR"] = "#/mnt/shared/vm_configs"
            group_vars["DEFAULT_BRIDGE"] = "#br0"
            self.set_group_vars(group_vars)

    # hook to catch the context of the cell and set signal handlers for
    # the gtk.Entry.
    def __on_props_cell_start_editing(self,cell,editable, path_string, model):
        self.escape = False
        iter = model.get_iter_from_string(path_string)
        path = model.get_path(iter)[0]
        column = cell.get_data("column")
        editable.connect("focus-out-event", self.__on_focus_out,
                         (path_string,column,model))
        editable.connect("key-press-event", self.__on_key_released)

    # Take care of the ESCAPE key. set the flag and return False for the
    # event system to continue processing.
    def __on_key_released(self, widget, event):
        self.escape =  (event.keyval == 65307) # escape key
        return False


    def __on_focus_out(self,editable, event, context):
        if self.escape:
            return
        (path_string, column, model) = context
        iter = model.get_iter_from_string(path_string)
        new_text = editable.get_text()
        model.set(iter, column, new_text)

    def __on_props_cell_edited(self,cell,path_string,new_text, model):
        iter = model.get_iter_from_string(path_string)
        path = model.get_path(iter)[0]
        column = cell.get_data("column")
        model.set(iter, column, new_text)

    def on_cancel_button_clicked(self, widget):
        self.groupvar_selected = None
        self.dialog.destroy()
        return False

    def get_group_vars(self):
        return (self.groupvar_selected)

    def set_group_vars(self, groupvars):
        model = self.groupvar_list_model
        for (k,v) in groupvars.iteritems():
            iter = model.append()
            model.set(iter,
                  self.COL_ATTR, k,
                  self.COL_VAL, v,
                  self.COL_EDITABLE, True)


    def on_ok_button_clicked(self, widget):
        print "Ok button"
        model = self.groupvar_list_model
        self.groupvar_selected = {}
        iter = model.get_iter_first()
        while iter:
            key = model.get_value(iter, self.COL_ATTR)
            val = model.get_value(iter, self.COL_VAL)
            if val and val[0] == "#":
                iter = model.iter_next(iter)
                continue
            
            self.groupvar_selected[key] = val
            iter = model.iter_next(iter)

        for (k,v) in self.groupvar_selected.iteritems():
            print k, v
        self.dialog.destroy()
        return True

    def on_add_button_clicked(self, widget, model, treeview):
        print "Add button"
        iter = model.append()
        model.set(iter,
                  self.COL_ATTR, "",
                  self.COL_VAL, "",
                  self.COL_EDITABLE, True)

        # set the higlight to newly added row.
        path = model.get_path(iter)
        treeview.set_cursor(path,treeview.get_column(0),True)


    def on_remove_button_clicked(self, widget):
        print "Remove button"
        selection = self.groupvar_list_view.get_selection()
        if selection:
            model, iter = selection.get_selected()
            if iter:
                path = model.get_path(iter)[0]
                model.remove(iter)


    def show(self, widget, pool, parentwin = None):
        """ Displays add group variables dialog"""
        ret = self.dialog.run()


# show the news / updates for the product
class UpdatesDlg:

    def __init__(self):

        """ Constructor"""
        self.gladefile = gladefile
        self.wtree = gtk.glade.XML(self.gladefile, "updates_dlg")
        self.dialog = self.wtree.get_widget("updates_dlg")
        self.view_wnd = self.wtree.get_widget("updates_dlg_view_wnd")

        self.view = self.wtree.get_widget("update_view")
        self.view_wnd.remove(self.view)
        self.view = HtmlTextView()

        self.view.set_property("visible",True)
        self.view.set_wrap_mode(gtk.WRAP_WORD)
        self.view.set_editable(False)

        self.view.connect("url-clicked", self.url_clicked_cb)
        self.view_wnd.add(self.view)

        self.title_span = '<span style="font-size: 125%; font-family: serif; color:#0000FF;text-align: left">'

        # connect the handlers
        self.wtree.signal_connect("on_updates_dlg_close_clicked",
                                 self.on_close_button_clicked)


    def show(self, updates, widget = None,parentwin = None):
        self.updates = updates
        self.parentwin = parentwin

        if parentwin:
            self.dialog.set_transient_for(parentwin)
            self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)

        text = "<body>"

        for update in updates:
            text += self.title_span
            text += '<a href="' + str(update["link"]) + '">'
            text = text + str(update["title"])
            text += "</a>"
            text += "</span>"
            text += "<br/>"
            text += "<br/>"

            text = text + str(update["description"])
            text += "<br/>"
            text += "<br/>"


        text += "</body>"
        try:
            self.view.display_html(text)
        except Exception, ex:
            print "error showing ConVirt updates : HTML -> " + text + "\n" + \
                  "Exception " + str(ex)

        self.dialog.show()

    def on_close_button_clicked(self, widget):
        self.dialog.destroy()

    def url_clicked_cb(htmlview, self, url, type):
        show_url(url)

# show the total number of VM's being managed
class LicenseDlg:
    (SERVER_GROUP,SERVER,VMS, DUMMY) = range(4)
    def __init__(self, store):

        """ Constructor"""
        self.store = store
        self.gladefile = gladefile
        self.wtree = gtk.glade.XML(self.gladefile, "show_license_dlg")
        self.dialog = self.wtree.get_widget("show_license_dlg")
        self.view_wnd = self.wtree.get_widget("license_dlg_view_wnd")

        self.view = self.wtree.get_widget("license_view")


        self.view.set_property("visible",True)

        # connect the handlers
        self.wtree.signal_connect("on_license_dlg_close_clicked",
                                  self.on_close_button_clicked)

        textrenderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn("Server Group", textrenderer, text=0)
        column.set_resizable(True)
        self.view.append_column(column)

        textrenderer = gtk.CellRendererText()
        textrenderer.set_property("xalign", 0.5)
        column = gtk.TreeViewColumn("Servers", textrenderer, text=1)
        column.set_resizable(True)
        self.view.append_column(column)

        textrenderer = gtk.CellRendererText()
        textrenderer.set_property("xalign", 0.5)
        column = gtk.TreeViewColumn("VMs", textrenderer, text=2)
        column.set_resizable(True)
        self.view.append_column(column)

        textrenderer = gtk.CellRendererText()
        #textrenderer.set_property("xalign", 0.5)
        column = gtk.TreeViewColumn("", textrenderer, text=3)
        column.set_resizable(True)
        self.view.append_column(column)


        self.list_model = gtk.TreeStore(gobject.TYPE_STRING,
                                        gobject.TYPE_STRING,
                                        gobject.TYPE_STRING,
                                        gobject.TYPE_STRING)



        self.view.set_model(self.list_model)


    def show(self, manager, widget = None,parentwin = None ):
        self.parentwin = parentwin
        self.manager = manager
        if parentwin:
            self.dialog.set_transient_for(parentwin)
            self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)

        self.populate_list(manager)

        self.dialog.show()
        ret = self.dialog.run()
        self.dialog.destroy()


    def on_close_button_clicked(self, widget):
        self.dialog.destroy()

    def populate_list(self, manager):
        #Iterate through uncategorized nodes and print the vm count
        nodes = manager.getNodeList()
        vmCount = 0
        totalServerCount=0
        totalVmCount = 0
        
        for i in nodes.keys():
          vmCount += nodes[i].get_Managed_VM_count(self.store)
            
        if vmCount > 0:
          iter = self.list_model.insert_before(None, None)
          self.list_model.set(iter,
                              self.SERVER_GROUP,'Uncategorized',
                              self.SERVER,'%4d' % len(nodes),
                              self.VMS,'%4d' % vmCount,
                              self.DUMMY,"")
          totalServerCount += len(nodes)
          totalVmCount +=vmCount

        # Iterate through managed nodes
        groups = manager.getGroupList()
        for i in groups.keys():
          nodes = groups[i].getNodeList()
          vmCount = 0
          for j in nodes.keys():
            vmCount += nodes[j].get_Managed_VM_count(self.store)    
          if vmCount > 0:
            iter = self.list_model.insert_before(None, None)
            self.list_model.set(iter,
                                self.SERVER_GROUP,str(i),
                                self.SERVER, '%4d' % len(nodes),
                                self.VMS,'%4d' % vmCount,
                                self.DUMMY, "")
            totalServerCount += len(nodes)
            totalVmCount += vmCount
            
        iter = self.list_model.insert_before(None, None)
        self.list_model.set(iter,
                            self.SERVER_GROUP,"Total",
                            self.SERVER,'%4d' % totalServerCount,
                            self.VMS,'%4d' % totalVmCount,
                            self.DUMMY,"")



#############
#    Util functions.. may move to util OR Managed Node
#    Also needs to cut this over to remote api
#



def createVBD(managed_node, filename, size=2048, backup=False):
    """Creates a file Virtual Block Device called 'name'
    at 'location'. 'size' is specified in kB.
    RAISES: IOError, OSError """

    if managed_node.node_proxy.file_exists(filename):
        if backup:
            managed_node.node_proxy.rename(filename,filename+'.bak')
        else:
            managed_node.node_proxy.remove(filename)

    # create the new disk block
    fd = managed_node.node_proxy.open(filename,'w')
    off = size * 1024L**2
    fd.seek(off, 0)
    fd.write('\x00')
    fd.close()



class MessageDlg:
    
    def __init__(self):

        """ Constructor"""
        self.wtree = gtk.glade.XML(gladefile, "StatusDialog")
        self.dialog = self.wtree.get_widget("StatusDialog")
        self.status_msg = self.wtree.get_widget("StatusMsg")

    def show(self, parentwin = None,msg = None ):
        self.parentwin = parentwin
        if parentwin:
            self.dialog.set_transient_for(parentwin) 
        self.status_msg.set_text(msg)    
        self.dialog.show()
        ret = self.dialog.run()
        self.dialog.destroy()


########## UI Utils #################

class CBException:
    def __init__(self, context, ex):
        self.context = context
        self.ex = ex

def cb_showmsg(msg):
    try:
        gtk.gdk.threads_enter()
        showmsg(msg)
    finally:
        gtk.gdk.threads_leave()


def showmsg(msg, parent=None):
    """Displays the status message passed as an argument in a popup window"""
    input = msg

    d_msg = ""
    context = ""

    if isinstance(input, CBException):
        (context, input) =  (input.context, input.ex)

    if input and isinstance(input, Exception) and input.__dict__.get("args"):
        args = input.args
        if len(args) == 0:
            d_msg = str(input)
        else:
            for mx in args:
                if isinstance(mx, list):
                    for m in mx:
                        d_msg += str(m) + "\n"
                else:
                    d_msg += str(mx)
    else:
        d_msg = str(input)

    if context is not None and context != "":
        d_msg = context +"\n" + d_msg

    MessageDlg().show(parent, d_msg)


from threading import Thread
import threading
import convirt.core.utils.NodeProxy
class UIWorker(Thread):
    """

    """
    def __init__(self, ui_callback,context=None,
                 success_cb = None,failure_cb = cb_showmsg,
                 lock_ui = False):
                 #ui_cb_args=(), ui_cb_kwargs={}) :

        Thread.__init__(self)
        self.setDaemon(True)
        self.ui_callback = ui_callback
        #self.ui_cb_args = ui_cb_args
        #self.ui_cb_kwargs = ui_cb_kwargs
        self.success_cb = success_cb
        self.failure_cb = failure_cb
        self.context = context
        self.result = None
        self.done = False
        self.lock_ui = lock_ui




    def run(self):
        try:
            try:
                #self.ui_callback(*self.ui_cb_args,**self.ui_cb_kwargs)
                print "calling cb", self.context

                if not self.lock_ui:
                    self.result = self.ui_callback()
                else:
                    # might have to give up livelyness here..
                    # as we throw up login dialog from backend op too :(
                    try:
                        gtk.gdk.threads_enter()
                        self.result = self.ui_callback()
                    finally:
                        gtk.gdk.threads_leave()

                # call the success_cb
                if self.success_cb:
                    print "posting success cb", self.context
                    gobject.idle_add(self.success_cb)
            except Exception ,ex:
                if self.failure_cb:
                    #if self.context is not None :
                    #    msg = self.context + ":" + str(ex)
                    #else:
                    #    msg = str(ex)
                    traceback.print_exc()
                    print "posting exception cb", self.context, ex
                    gobject.idle_add(self.failure_cb, CBException(self.context, ex))

            if self.context is None:
                self.context = ""
            print "thread done. Context ", self.context
            self.done = True
        finally:
            # clean up andy local storage with the thread
            convirt.core.utils.NodeProxy.Node.clean_locals()

def show_wait_cursor(win = None):
    """ Wait cursor displayed / all input disabled """

    if win is None:
        win = main_context["main_window"]
    watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
    gdkwin = win.window
    gdkwin.set_cursor(watch)
    gtk.gdk.flush()

def hide_wait_cursor(win = None):
    if win is None:
        win = main_context["main_window"]
    gdkwin = win.window
    gdkwin.set_cursor(None)




def confirmation(msg):
    """Displays a confirmation dialog message and returns a boolean
    representing the result"""

    wtree.get_widget('ConfirmationDialog').set_title("Confirm")
    wtree.get_widget('ConfirmationMsg').set_text(msg)
    dialog = wtree.get_widget('ConfirmationDialog')
    res = dialog.run() == gtk.RESPONSE_YES
    dialog.hide()
    return res

def file_selection(managed_node,
                   title, fstype,
                   init_folder=None, init_file=None,
                   parentwin=None, force_local = False,
                   multi_select = False):
    """This function will setup a file selection dialogue and return a tuple
    consisting of a boolean which is true if the user selected a filename,
    followed by the filename. fstype is either "open" or "save" or
    "select_folder" and title is whateveryou want displayed as the
    window's title bar. The init_folder and init_file params would be used
    as initial values for the dialog box"""

    gnome_vfs_enabled = True
    if main_context.has_key("client_config"):
        client_config = main_context["client_config"]
        gnome_vfs_prop_val = client_config.get(XMConfig.CLIENT_CONFIG,
                                              constants.prop_gnome_vfs_enabled)
        if gnome_vfs_prop_val is not None:
             gnome_vfs_enabled = eval(gnome_vfs_prop_val)

    if gnome_vfs_enabled:
        back_end = 'gnome-vfs'
    else:
        back_end = None

    if back_end is None and managed_node.is_remote() and not force_local:
        remote_dlg = RemoteFileDialog(wtree)
        ret = remote_dlg.show(managed_node, title, fstype, init_folder, init_file,
                              parentwin, multi_select=multi_select)
        #ret = remote_dlg.run()
        res = ret == gtk.RESPONSE_OK
        filename = remote_dlg.get_filename()
        if multi_select:
            file_list = []
            if filename and filename is not "":
                file_list = filename.split(",")
                return (res, file_list)
            return (False, None)
        else:
            return (res, filename)


    if fstype == "save":
        filesel = gtk.FileChooserDialog(title,
                                        action=gtk.FILE_CHOOSER_ACTION_SAVE,
                                        buttons=(gtk.STOCK_CANCEL,
                                                 gtk.RESPONSE_CANCEL,
                                                 gtk.STOCK_SAVE,
                                                 gtk.RESPONSE_OK),
                                        backend=back_end)
    elif fstype == "open":
        filesel = gtk.FileChooserDialog(title,
                                        action=gtk.FILE_CHOOSER_ACTION_OPEN,
                                        buttons=(gtk.STOCK_CANCEL,
                                                 gtk.RESPONSE_CANCEL,
                                                 gtk.STOCK_OPEN,
                                                 gtk.RESPONSE_OK),
                                        backend = back_end)
        if multi_select:
            filesel.set_select_multiple(True)
    elif fstype == "select_folder":
        filesel = gtk.FileChooserDialog(title,
                                        action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
                                        buttons=(gtk.STOCK_CANCEL,
                                                 gtk.RESPONSE_CANCEL,
                                                 gtk.STOCK_OPEN,
                                                 gtk.RESPONSE_OK),
                                        backend= back_end)

    # enable remote file browsing.
    filesel.set_local_only(False)


    # if remote node, create a url and set it.
    if managed_node.is_remote() and not force_local:
        hostname = managed_node.hostname
        username = managed_node.username
        ssh_port = str(managed_node.ssh_port)
        if username is None:
            username = os.getlogin()
        url = "ssh://"+username+"@"+hostname+ ":" + ssh_port + "/"
        title = filesel.get_title()
        filesel.set_title(title + ":" + username +"@"+ hostname)
        if init_folder is not None and init_folder != "":
            if init_folder[0] == '/':
                url = url + init_folder[1:]
            filesel.set_current_folder_uri(url)
        else:
            filesel.set_current_folder_uri(url)
    else: # local node
        if init_folder is not None and init_folder is not "":
            filesel.set_current_folder(init_folder)

    if init_file is not None:
        filesel.set_current_name(init_file)

    if parentwin:
        filesel.set_transient_for(parentwin)
        filesel.set_position(gtk.WIN_POS_CENTER_ON_PARENT)

    res = filesel.run() == gtk.RESPONSE_OK

    filelist = []
    if res:
        uris = filesel.get_uris()
        if managed_node.is_remote() and not force_local:
            selected_uri = uris[0]
            selected_uri = filesel.get_uri()
            selected_uri = urllib.unquote(selected_uri)
            if selected_uri and selected_uri.find(hostname) == -1:
                msg = "File not selected from the managed node.\n"
                msg += "Please use Open Location and use ssh://"+username+"@" +hostname +"/ to access remote files.\n"
                msg += "Open Location available through right click menu."
                showmsg(msg)
                filelist = []
                filesel.destroy()
                return (None, filelist)

        for u in uris:
            filelist.append(get_filename_from_uri(u))


    filesel.destroy()

    if multi_select:
        return (res, filelist)
    else:
        if len(filelist) > 0:
            return (res, filelist[0])
        else:
            return (res, None)

def get_filename_from_uri(uri):
    if uri == None:
        return None
    # Kludge : as urllib functions require http
    if uri.find("ssh") == 0:
        uri =  uri.replace("ssh", "http", 1)
    (prot, host, path,param,query,fragments ) = urlparse.urlparse(uri)
    if path is not None:
        return path

def get_platform_pb(managed_node):
    pb = None
    if managed_node is not None:
        platform = managed_node.get_platform()
        # TODO : drive this through registry
        if platform == 'xen' and xen_pb:
            pb = xen_pb
        elif platform == 'kvm' and kvm_pb:
            pb = kvm_pb
    return pb

# Cell renderers for the colums in the tree view.
def get_state_pixbuf(column, renderer, model, iter, appliance_store=None):
    """ Call back to display the state column image"""
    dom_name = model.get_value(iter,0)
    node_type = model.get_value(iter,1)
    managed_node =  model.get_value(iter,2)
    g_name = model.get_value(iter, 3)
    provider_id = model.get_value(iter, 4)
    
    if node_type is None :
        return

    pb = unknown_pb

    if node_type == MANAGED_NODE:
        pb = get_platform_pb(managed_node)
        if not pb:
            pb = node_pb
            
    elif node_type == IMAGE_STORE:
        pb = dc_pb
    elif node_type == IMAGE_GROUP:
        pb = image_store_pb
    elif node_type == IMAGE:
        pb = image_pb
        if g_name:
            #provider_id = g_name
            ppb = None
            if provider_id:
                ppb = ApplianceLogos.get_provider_logo(appliance_store,
                                                       provider_id)
            if ppb:
                pb = ppb

    elif managed_node is not None and node_type == DOMAIN: # dom
        dom = managed_node.get_dom(dom_name)

        if dom and dom.is_resident():
            try:
                state = dom.get_state()
            except xmlrpclib.Fault :
                state = None

            if state is not None and state == VM.PAUSED:
                pb = paused_pb
            else:
                pb = resident_pb
        else:
            pb = not_resident_pb
    elif node_type == SERVER_POOL:
        pb = pool_pb
    elif node_type == DATA_CENTER:
        pb = dc_pb


    renderer.set_property('pixbuf', pb)

def get_node_type_pb(type, model, iter):
    if type == SERVER_POOL:
        return pool_pb
    elif type == MANAGED_NODE:
        managed_node = model.get_value(iter,0)
        pb = get_platform_pb(managed_node)
        if pb:
            return pb
        else:
            return node_pb

### create a node list

def populate_node_filter(managed_node, platform, image):

    if managed_node is not None:
        if platform:
            if managed_node.get_platform() != platform:
                return False
        if image:
            if not managed_node.is_authenticated() or \
                   not managed_node.is_image_compatible(image):
                return False

    return True


# NOTE : Platform is used for filtering nodes during migration op.
#        While image is used while provisioning op.
def populate_nodes(manager, view, model, dummy = True, platform = None,
                   image = None):
    """
    refresh the nodes.
    Not expected to be called other than constructor.

    """
    model.clear()

    # Append a Global Server Pool
    d_iter = model.append(None,
                          ["Data Center",
                           DATA_CENTER,
                           None,
                           None,
                           None,
                           None])

    # sort them
    names = manager.getNodeNames()
    name_list = []
    for name in names:
        managed_node = manager.getNode(name)
        if populate_node_filter(managed_node, platform, image):
            name_list.append(name)
    name_list.sort()

    # Kludge, append a blank node so the expanders show up
    nodes = manager.getNodeList()
    for name in name_list:
        node = nodes[name]
        iter = \
             model.append(d_iter,
                          [node.hostname,
                           MANAGED_NODE,
                           node,
                           None,
                           None,
                           None])
        if dummy:
            append_dummy_row(model, iter)

    # add the server pools
    group_names = manager.getGroupNames()
    group_names.sort()

    groups = manager.getGroupList()
    for group_name in group_names:
        group = groups[group_name]
        g_iter = model.append(d_iter,
                              [group.name,
                               SERVER_POOL,
                               group,
                               None,
                               None,
                               None])

        # sort them
        names = group.getNodeNames()
        name_list = []
        for name in names:
            managed_node = group.getNode(name)
            if populate_node_filter(managed_node, platform, image):
                name_list.append(name)
        name_list.sort()

        # Kludge, append a blank node so the expanders show up
        nodes = group.getNodeList()
        for name in name_list:
            node = nodes[name]
            iter = \
                 model.append(g_iter,
                              [node.hostname,
                               MANAGED_NODE,
                               node,
                               group.name,
                               None,
                               None])
            if dummy:
                append_dummy_row(model, iter)


        # NOTE : if this is re-introduced, we need to change
        # UI code for adding and removing groups

        #if len(names) == 0:
        #    if dummy:
        #        append_dummy_row(model, g_iter, "Empty")

    view.expand_row((0,),False)
    view.set_cursor((0,))

def append_dummy_row( model, iter, msg = "VMs not found"):
    model.append(iter, [msg,
                        "DUMMY",None, None, None, None])


# moved to util to prevent cirular dependency.
class ApplianceLogos:
    logos = {}

    @classmethod
    def get_provider_logo(cls, appliance_store, provider_id):
        if not cls.logos.get(provider_id):
            if not provider_id:
                return appliance_pb

            cache_dir = os.path.join(appliance_store.get_cache_dir(),
                                     provider_id)
            if not os.path.exists(cache_dir):
                os.makedirs(cache_dir)
            for ext in (".gif", ".ico", ".png"):
                logo_path =  os.path.join(cache_dir,  provider_id + ext)
                try:
                    pb = gtk.gdk.pixbuf_new_from_file(logo_path)
                    if pb:
                        cls.logos[provider_id] = pb.scale_simple(16,16,
                                                                 gtk.gdk.INTERP_BILINEAR )
                        break
                except Exception, ex:
                    pass
                if not cls.logos.get(provider_id):
                    try:
                        print "provider_id ", provider_id
                        # fetch the logo from the given url
                        logo_url = appliance_store.get_logo_url(provider_id)
                        if logo_url is not None:
                            p = urlparse.urlparse(logo_url)[2]
                            logo_name= os.path.basename(p)
                            frag = logo_name.split(".")
                            if len(frag) > 1:
                                ext = "." + frag[-1]
                            else:
                                ext = ".gif" # can do better with content-type :TBD
                            logo_file = os.path.join(cache_dir,
                                                     provider_id + ext)
                            fetch_isp(logo_url,logo_file, "image")
                            pb = gtk.gdk.pixbuf_new_from_file(logo_file)
                            if pb:
                                cls.logos[provider_id] = pb.scale_simple(16,16,
                                                                         gtk.gdk.INTERP_BILINEAR )
                    except Exception, e:
                        print "Exception processing ", provider_id, e
                        traceback.print_exc()
                        pass

                # set it to none so we do not keep doing scans
                if not cls.logos.get(provider_id):
                    cls.logos[provider_id] = appliance_pb
                    print "setting default for ", provider_id

        return cls.logos[provider_id]

from ui_utils import init_combo, set_value, get_value

class SelectPlatformDlg:

    def __init__(self):

        """ Constructor"""
        self.gladefile = gladefile
        self.wtree = gtk.glade.XML(self.gladefile, "SelectPlatformDlg")
        self.dialog = self.wtree.get_widget("SelectPlatformDlg")

        self.platform_combo = self.wtree.get_widget("platform_combo")
        self.dialog.set_default_response(gtk.RESPONSE_OK)
        # connect the handlers
        self.wtree.signal_connect("on_select_platform_cancel_clicked",
                                  self.on_cancel_clicked)
        self.wtree.signal_connect("on_select_platform_ok_clicked",
                                  self.on_ok_clicked)

        self.registry = None
        self.parentwin = None
        self.selected_platform = None

    def show(self, registry, parentwin = None):

        self.registry = registry
        self.parentwin = parentwin
        self.selected_platform = None
        
        if parentwin:
            self.dialog.set_transient_for(parentwin)
            self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)

            
        map = {}
        for platform, info in registry.get_platforms().iteritems():
            name = info["name"]
            map[name] = platform
            

        k=map.keys()
        k.sort()
        order=["Select Platform..."] + k
        map["Select Platform..."] = ""
        init_combo(self.platform_combo, map, order)
        set_value(self.platform_combo, "")
        self.dialog.show()

        ret = self.dialog.run()
        self.dialog.destroy()
        if ret == gtk.RESPONSE_OK:
            return True
        else:
            return False

    def on_cancel_clicked(self, widget):
        return False


    def on_ok_clicked(self, widget):
        print get_value(self.platform_combo)
        self.selected_platform = get_value(self.platform_combo)
        return True




def update_config_props(config, model, excluded = []):
    # take misc model remove deleted props
    delete_props = []
    if config is None:
        return
    for prop in config:
        if prop not in excluded:
            # check if it exists in the misc model
            found = False
            iter = model.get_iter_first()
            while iter:
                key = model.get_value(iter, 0)
                if key == prop:
                    found = True
                    break
                iter = model.iter_next(iter)

            if not found:
                delete_props.append(prop)

    for prop in delete_props:
        del config.options[prop]

    # now copy update values from model to the config.
    iter = model.get_iter_first()
    while iter:
        key = model.get_value(iter, 0)
        value = model.get_value(iter,1)
        # We got the string representation, guess and make it proper value
        key = key.strip()
        value = value.strip()
        value = guess_value(value)
        if key is not None and key is not '':
            config[key] = value
        iter = model.iter_next(iter)

    #config.dump()


# function to handle callbacks indirectly. takes the first argument that is
# of type method and invokes it with rest of the params.

# shows dialogbox with exception message


# util functions and classes
from convirt.core.utils.utils import dynamic_map
from convirt.client.ui_utils import Container
from convirt.client.ui_utils import *

class StorageDefinitionListDialog (Container):
    """ Class that handles adding new Storage Definitions"""

    (
        COLUMN_NAME,
        COLUMN_TYPE,
        COLUMN_SIZE,
        COLUMN_DEFINITION,
        COLUMN_DESCRIPTION,
        COLUMN_ID
     ) = range(6)
    

    def __init__(self):
        Container.__init__(self)

        
        # Storage Manager
        self.storage_manager = None
        self.context = dynamic_map()
        
        self.context.storage_name = ""
        self.context.shared_storage_id = ""      
        self.group_name = None
        
        self.ui_init(self.context)


    def ui_init(self, context):
        
        wtree = gtk.glade.XML(gladefile, "SharedStorageDefinitionListDialog")
        self.dialog = get_widget(wtree,"SharedStorageDefinitionListDialog")
        self.init_widgets(wtree, ["shared_storage_view",
                                  "storage_definition_add",
                                  "storage_definition_remove",
                                  "storage_definition_rename",
                                  "storage_definition_edit",
                                  "storage_definition_test",
                                  "storage_definition_close",
                                 
                                  ])
        self.init_storage_view()
                
        # event handlers
        wtree.signal_autoconnect({"on_shared_storage_add_clicked":(cb_wrapper,self.on_shared_storage_add_clicked),
                                  "on_shared_storage_remove_clicked":(cb_wrapper,self.on_shared_storage_remove_clicked),
                                  "on_shared_storage_rename_clicked":(cb_wrapper,self.on_shared_storage_rename_clicked),
                                  "on_shared_storage_edit_clicked":(cb_wrapper,self.on_shared_storage_edit_clicked),
                                  "on_shared_storage_test_clicked":(cb_wrapper,self.on_shared_storage_test_clicked),
                                  "on_shared_storage_close_clicked":(cb_wrapper,self.on_shared_storage_close_clicked),
                                  "on_shared_storage_view_row_activated":(cb_wrapper,self.handle_row_activated),
                                  }
                                 )

    def handle_row_activated(self,treeview,path,column):
        self.on_shared_storage_edit_clicked(self.widgets.storage_definition_edit)
        
    def get_defn(self, sd):
        if not sd:
            return ""
        desc = None
        if sd.type == NFS:
            desc = sd.connection_props["server"] + ", " + \
                   sd.connection_props["share"]
        elif sd.type == iSCSI:
            desc = sd.connection_props["server"] + ", " + \
                   sd.connection_props["target"]
        elif sd.type == AOE:
            desc =  sd.connection_props["interface"]

        print sd.type
        if not desc:
            return ""
        else:
            return desc
        
        
    def init(self):
        self.scatter(self.context)

        sds = self.storage_manager.get_sd_ids(self.group.name)
        view = self.widgets.shared_storage_view
                        
        model = view.get_model()
        model.clear()
        for item in sds:
            s_def = self.storage_manager.get_sd(item)
            iter = model.append()
            
            total_str = "  N/A"
            if s_def.get_stats():
                total = s_def.get_stats().get("TOTAL")
                if total:
                    total_str = "%6.2f" % total
                
            model.set(iter,
                      self.COLUMN_NAME, s_def.name,
                      self.COLUMN_TYPE, s_def.type,
                      self.COLUMN_SIZE, total_str,
                      self.COLUMN_DEFINITION, self.get_defn(s_def),
                      self.COLUMN_DESCRIPTION, s_def.description,
                      self.COLUMN_ID, s_def.id
                )
        
        view.set_model(model)     
        
    
        
    def init_storage_view(self):
        textrenderer = gtk.CellRendererText()
        view = self.widgets.shared_storage_view
        columns = ["Name", "Type", "Size GB", "Definition", "Description"]
        for c in columns:
            tree_column = gtk.TreeViewColumn(c, textrenderer,
                                            text=columns.index(c))
            tree_column.set_resizable(True)
            view.append_column(tree_column)        

        model = gtk.ListStore(gobject.TYPE_STRING, # Storage Name
                              gobject.TYPE_STRING, # Type
                              gobject.TYPE_STRING, # Size in GB
                              gobject.TYPE_STRING, # Definition
                              gobject.TYPE_STRING, # Description
                              gobject.TYPE_STRING, # ID                              
                              ) 
        
        
        view.set_model(model)     
        
        
    def on_shared_storage_add_clicked(self, widget):

        shared_storage_details = StorageDefinitionDetailsDialog()
        
        ret = shared_storage_details.show(widget, self.storage_manager,
                                          None,
                                          self.context.managed_server,
                                          self.group,
                                          "NEW",
                                          parent=self.dialog)
        
        # Add the Storage def if OK button clicked.
        if ret == True:
            new_sd = shared_storage_details.get_valid_sd()
                
            self.update_storage_def(None, None, new_sd,
                                    None, True)

    def on_shared_storage_remove_clicked(self, widget):
        print "Storage definition Remove button clicked" 
        view = self.widgets.shared_storage_view
        selection = view.get_selection()
        result = selection.get_selected()
        if result is not None: #result could be None
            model, iter = result
            storage_id = model.get_value(iter, self.COLUMN_ID )
            sd_to_remove = self.storage_manager.get_sd(storage_id)
            self.storage_manager.remove_sd(sd_to_remove, self.group)
                        
            model.remove(iter)
            
            

    def on_shared_storage_rename_clicked(self, widget):
        print "Storage definition Rename button clicked" 
        selection = self.widgets.shared_storage_view.get_selection()
        result = selection.get_selected()
        if result is not None:
            model, iter = result
            storage_name = model.get_value(iter, self.COLUMN_NAME )
            renamedlg = RenameSharedStorageDialog()
            ret = renamedlg.show(storage_name, parent = self.dialog)
            if ret != gtk.RESPONSE_OK:
                return
            new_name = renamedlg.get_renamed_storage_name()

            storage_id = model.get_value(iter, self.COLUMN_ID )
            sd_to_rename = self.storage_manager.get_sd(storage_id)
            sd_to_rename.name = new_name
            self.storage_manager.update_sd(sd_to_rename, self.group)
            
            model.set(iter, self.COLUMN_NAME, new_name)            

    def on_shared_storage_edit_clicked(self, widget):
        print "Storage definition Edit button clicked" 
        selection = self.widgets.shared_storage_view.get_selection()
        result = selection.get_selected()
        dlg = StorageDefinitionDetailsDialog()
        model = None
        iter = None
        if result is not None:
            model, iter = result
            storage_id = model.get_value(iter, self.COLUMN_ID )
            ret = dlg.show(None,
                           self.storage_manager,
                           storage_id,
                           self.context.managed_server,
                           self.group, "EDIT", parent = self.dialog)
            if ret == True:
                # get updated sd
                new_sd = dlg.get_valid_sd()
                
                self.update_storage_def(iter, model, new_sd,
                                        storage_id, False)

    # This will update the storage definition. 
    # If new = True, a new storage definition will be created.
    # If new = False, selected storage definition will be updated.
    def update_storage_def(self, iter, model, new_sd, storage_id, new = True):
                
            group = ServerGroup(self.group.name)

            if new == True:
                model = self.widgets.shared_storage_view.get_model()
                self.storage_manager.add_sd(new_sd, group)
                iter = model.append()
            else:
                old_sd = self.storage_manager.get_sd(storage_id)
                old_sd.connection_props = new_sd.get_connection_props()
                old_sd.name = new_sd.name
                old_sd.type = new_sd.type
                old_sd.description = new_sd.description
                
                if old_sd.creds_required == True:
                    old_sd.set_creds(new_sd.get_creds())

                old_sd.set_stats(new_sd.get_stats())
                self.storage_manager.update_sd(old_sd, group)

            model.set(iter,
                self.COLUMN_NAME, new_sd.name,
                self.COLUMN_TYPE, new_sd.type,
                self.COLUMN_DEFINITION, str(new_sd.connection_props), 
                self.COLUMN_DESCRIPTION,new_sd.description,
                self.COLUMN_ID, new_sd.id
            )
        
            self.init()

    def on_shared_storage_test_clicked(self, widget):
        print "Storage definition Test button clicked" 
        selection = self.widgets.shared_storage_view.get_selection()
        result = selection.get_selected()
        storage_name = ""
        if result is not None:
            model, iter = result
            storage_name = model.get_value(iter, self.COLUMN_NAME )
            storage_id = model.get_value(iter, self.COLUMN_ID )

        dlg = StorageDefinitionDetailsDialog()
        ret = dlg.show(None, self.storage_manager,
                       storage_id,
                       self.context.managed_server,
                       self.group,
                       "TEST", parent = self.dialog)        
        
        #disk_info = dlg.get_selected_volume()

    def on_shared_storage_close_clicked(self, widget):
        print "Storage definition Test button clicked" 
        self.dialog.destroy()


    def scatter(self, context):
        #set the data.
        i= 0


    def gather(self, context):
 # Get the selected value from the table.
        i = 0

    def show(self, widget,
             storage_manager,
             managed_server = None,
             group = None,
             parent = None):


        """ Displays storage definition dialog"""
        if parent:
            self.dialog.set_transient_for(parent)
        self.context.managed_server = managed_server
        self.group = group 
        self.storage_manager = storage_manager
        
        self.scatter(self.context)
        ret = None
        self.init()

        self.dialog.show()
        

        ret = self.dialog.run()
        self.dialog.destroy()
        if ret == gtk.RESPONSE_OK:
            return True
        else:
            return False



class StorageDefinitionDetailsDialog (Container):
    """ Class that handles adding new Storage Definitions"""


    (
        COLUMN_NAME,
        COLUMN_SIZE,
        COLUMN_ATTR,      # attr for nfs, disk for others.
        COLUMN_STATUS,        
        COLUMN_INTERFACE, # interface for AOE, uuid for iscsi
     ) = range(5)
     
######
     
#===============================================================================
# Edit (x = disabled, 0 = hidden)
# ------------------------------------------------------------------------------
#    Control                                    iSCSI        NFS          AOE
# "storage_definition_target_type_label",
# "storage_target_type",                         
# "storage_share_name_label",                    0            0            0
# "storage_share_name_combo",                    0            0            0
# "storage_definition_host_label",            Portal        Host    Network Interface
# "storage_definition_host_entry",
# "sd_iscsi_target_label",                    Target          0            0
# "sd_iscsi_target_entry",
# "storage_definition_user_label",            Username     Mount Point     0
# "storage_userid",
# "storage_definition_pwd_label",
# "storage_pwd",
# "storage_definition_options_label",        Options       Mount Options   0    
# "storage_options",
# "storage_volumes_view",
# "storage_share_name_entry_label",
# "storage_share_name_entry",
# "storage_share_managed_server_combo"                
# "storage_nfs_mount_point_checkbox",          0                0            0
# "storage_authenticate_btn",
#===============================================================================
# Test (x = disabled, 0 = hidden)
# ------------------------------------------------------------------------------
#    Control                                    iSCSI        NFS          AOE
# "storage_definition_target_type_label",        0            0            0
# "storage_target_type",                         0            0            0
# "storage_share_name_label",                    0            0            0
# "storage_share_name_combo",                    0            0            0
# "storage_definition_host_label",               x            x            x
# "storage_definition_host_entry",               x            x            x
# "sd_iscsi_target_label",                       x            x            x
# "sd_iscsi_target_entry",                       x            x            x
# "storage_definition_user_label",               x            x            x
# "storage_userid",                              x            x            x
# "storage_definition_pwd_label",              
# "storage_pwd",
# "storage_definition_options_label",            0            0            0
# "storage_options",                             0            0            0
# "storage_volumes_view",
# "storage_share_name_entry_label",              x            x            x
# "storage_share_name_entry",                    x            x            x
# "storage_share_managed_server_combo"                
# "storage_nfs_mount_point_checkbox",            0                0            0
# "storage_get_vol_btn",
#===============================================================================
     
    def __init__(self):
        Container.__init__(self)

        self.test_mode = False # just for testing UI, make it True
        self.storage_manager = None

        # To determine whether to show edit controls or display controls
        self.mode = "NEW"

        self.context = dynamic_map()
        self.disk_context = dynamic_map()
        self.share_map = {}
        
        
        self.context.storage_name = ""
        self.context.target_type = ""
        self.context.target = ""
        self.context.iscsi_target = ""
        self.context.username = ""
        self.context.password = ""
        self.context.managed_server = ""

        self.disk_context.name = ""
        self.disk_context.size = ""
        self.disk_context.attr = ""
        self.disk_context.interface = ""
        self.disk_context.status = ""


        self.share_name_combo_hack = False
        
        self.ui_init(self.context)

        self.aoe_model = None
        self.nfs_model = None
        self.iscsi_model = None
        
        self.valid = False

        self.init()

    def ui_init(self, context):
        
        wtree = gtk.glade.XML(gladefile, "SharedStorageDefinitionDetailsDialog")
        self.dialog = get_widget(wtree,"SharedStorageDefinitionDetailsDialog")
        self.init_widgets(wtree, ["storage_target_type",
                                  "storage_definition_host_entry",
                                  "storage_share_name_combo",
                                  "storage_share_name_label",
                                  "storage_share_desc_label",
                                  "storage_share_desc_entry",
                                  "storage_userid",
                                  "storage_pwd",
                                  "storage_options",                                  
                                  "storage_definition_host_label",
                                  "sd_iscsi_target_label",
                                  "sd_iscsi_target_entry",
                                  "storage_definition_user_label",
                                  "storage_definition_pwd_label",
                                  "storage_definition_options_label",
                                  "storage_definition_target_type_label",
                                  "storage_volumes_view",
                                  "storage_share_name_entry_label",
                                  "storage_share_name_entry",
                                  "storage_nfs_mount_point_checkbox",
                                  "server_selection_label",
                                  "storage_get_vol_btn",
                                  "storage_share_managed_server_combo_label",      
                                  "storage_share_managed_server_combo",
                                  "storage_table_frame",  
                                  "test_results_table",
                                  "select_disk_label",
                                  "select_disk_pre_label",
                                  "storage_test_result_label",
                                  "storage_test_total_size_label",
                                  "storage_test_total_size_value_label",
                                  "storage_test_available_size_label",
                                  "storage_test_available_size_value_label",  
                                  "storage_test_image",              
                                  ])
                       
        #self.dialog.set_default_response(gtk.RESPONSE_OK)
                            
        self.host_label = self.widgets["storage_definition_host_label"]
        self.user_label = self.widgets["storage_definition_user_label"]
        self.options_label = self.widgets["storage_definition_options_label"]

        self.nfs_share_label = self.widgets["sd_iscsi_target_label"]
        self.nfs_share_entry = self.widgets["sd_iscsi_target_entry"]
                            
        wtree.signal_autoconnect({"on_storage_definition_cancel_clicked":(cb_wrapper,self.on_cancel_button_clicked),
                                  "on_storage_definition_ok_clicked":(cb_wrapper,self.on_ok_button_clicked),
                                  "on_storage_definition_target_type_changed": (cb_wrapper,self.on_target_type_changed),
                                  "on_storage_share_name_combo_changed": (cb_wrapper,self.on_share_name_combo_changed),
                                  "on_storage_definition_get_vol_clicked": (cb_wrapper,self.on_get_vol_button_clicked),
                                  "on_storage_nfs_mount_point_checkbox_clicked":(cb_wrapper,self.on_nfs_mount_checkbox_clicked),     
                                                               
                                  }
                                 )


        self.managed_server  = None
        self.group = None
        self.init_target_type_combo()
        self.init_volumes_view(NFS)
        self.init_managed_server_combo()

    def init(self):
      print "StorageDefinitionDetailsDialog::init callied"       



    # Container::update_widgets() 
    def update_widgets(self, mode):
        Container.update_widgets(self, mode)
        # complete HACK as get_widgets to hide is again showing up the
        # hidden credentials by on_share_name_combo changed handler!
        # May be somehow weave it in to get_widgets_hide if we are not
        # going to have real case where share_name_combo is going to change!
        if mode == "TEST":
            self.on_share_name_combo_changed(self.widgets.storage_share_name_combo)
        if mode not in ["SELECT",]:
            self.widgets.storage_get_vol_btn.set_label("Go")
            self.widgets.server_selection_label.set_label("Select a server to validate the storage connectivity.")
        else:
            self.widgets.server_selection_label.set_label("")
            self.widgets.storage_get_vol_btn.set_label("Select Storage")


    # Disable the widgets based on mode
    def get_widgets_to_disable(self, mode):
        disable_widgets = []
        disable_widgets_for_type = []
        target_type = self.context.target_type
        if mode not in  ["NEW", "EDIT"] :
            disable_widgets =  [ self.widgets[w] for w in [
                                "storage_definition_host_entry",    # Name
                                "storage_share_desc_entry",         # Description
                                "storage_target_type"               # Type
                                ]
                            ]
            
            if mode == "SELECT": # in context of a server.. so disable it.
                disable_widgets.append(self.widgets.storage_share_managed_server_combo)
            
            if target_type == iSCSI:
                disable_widgets_for_type = [
                          self.widgets[w] for w in [
                            "sd_iscsi_target_entry"                 # Target
                            ]                            
                        ]
            if target_type == NFS:
                disable_widgets_for_type = [
                          self.widgets[w] for w in [
                            "sd_iscsi_target_entry",                # Share
                            "storage_options",                      # Mount options
                            "storage_userid",                       # Mount point
                            ]                            
                        ]

        if mode == "EDIT": # in context of a server.. so disable it.
            disable_widgets.append(self.widgets.storage_target_type)


            
        disable_widgets = disable_widgets + disable_widgets_for_type
        return disable_widgets
        
        
    # Hide the widgets when launched from VM Settings
    def get_widgets_to_hide(self, mode):

        hide_widgets = []
        hide_widgets_any_time = [ self.widgets[w] for w in [
                                  "test_results_table",
                                  "storage_table_frame"
                                  ]              
                            ]
        type_hide = []
        target_type = get_value(self.widgets.storage_target_type)

        if mode == "NEW" and \
               get_value(self.widgets.storage_target_type) == None:
            
            hide_widgets =  [ self.widgets[w] for w in [
                "storage_definition_pwd_label", 
                "storage_pwd",
                "storage_definition_user_label",
                "storage_userid",
                "storage_definition_options_label",
                "storage_options",      
                "storage_nfs_mount_point_checkbox",
                "storage_share_name_label",
                "storage_share_name_combo",
                "storage_definition_host_label",
                "storage_definition_host_entry",
                "storage_nfs_mount_point_checkbox",
                "test_results_table",
                "storage_table_frame",
                ]              
                              ]
            return hide_widgets + hide_widgets_any_time

        if mode == "SELECT":
            hide_widgets =  [ self.widgets[w] for w in [
                                    "storage_target_type",
                                    "storage_share_managed_server_combo_label",
                                    "storage_share_managed_server_combo",
                                    "test_results_table",
                                    "storage_table_frame",
                                    "storage_share_name_entry_label",
                                    "storage_share_name_entry",
                                    "storage_nfs_mount_point_checkbox",
                                  ]              
                            ]
            
        
        
        if mode not in  ["NEW", "EDIT"] :
            hide_widgets =  [ self.widgets[w] for w in ["storage_target_type",
                                  "storage_definition_target_type_label",
                                  "storage_share_name_entry_label",
                                  "storage_share_name_entry",
                                  "storage_nfs_mount_point_checkbox",
                                  "test_results_table",
                                  "storage_table_frame"
                                  ]              
                            ]

            
        else:
            hide_widgets =  [ self.widgets[w] for w in ["storage_share_name_label",
                                                        "storage_share_name_combo",
                                                        "storage_nfs_mount_point_checkbox",
                                              ]
                            ]

        # make adjustments
        if mode != "SELECT":
            hide_widgets.append(self.widgets.select_disk_label)
            hide_widgets.append(self.widgets.select_disk_pre_label)



        if target_type == NFS:
            type_hide = [
                          self.widgets[w] for w in[
                            "storage_definition_pwd_label", 
                            "storage_pwd",
                            "storage_table_frame"
                            "storage_nfs_mount_point_checkbox",
                            # For now
                            "storage_definition_options_label",
                            "storage_options",      
                            
                            ]
                        ]
        if target_type == AOE :
            type_hide = [
                          self.widgets[w] for w in [
                            "storage_definition_pwd_label", 
                            "storage_pwd",
                            "storage_definition_user_label",
                            "storage_userid",
                            "storage_definition_options_label",
                            "storage_options",      
                            "storage_nfs_mount_point_checkbox",
                            "sd_iscsi_target_label",
                            "sd_iscsi_target_entry",
                            ]                            
                        ]

        if target_type == iSCSI :
            type_hide = [
                          self.widgets[w] for w in [
                            "storage_nfs_mount_point_checkbox",
                            # hide them for this release
                            "storage_definition_pwd_label", 
                            "storage_pwd",
                            "storage_definition_user_label",
                            "storage_userid",
                            "storage_definition_options_label",
                            "storage_options",      
                            ]                            
                        ]
        
        hide_widgets = hide_widgets + type_hide + hide_widgets_any_time
        return hide_widgets
    
    def init_target_type_combo(self):
        if( self.mode == "NEW"):
            init_combo(self.widgets.storage_target_type,
                   self.get_storage_type_map() )


    def init_managed_server_combo(self):
        server_map = {}
        
        if self.managed_server is not None:
            server_map[self.managed_server.hostname] = self.managed_server.hostname
        else:
            if self.group is not None:
                servers = self.group.getNodeNames()
                for s in servers:
                    server_map[s] = s
            else:
                return
            
                    
        init_combo(self.widgets.storage_share_managed_server_combo,
                   server_map )

        self.widgets.storage_share_managed_server_combo.set_active(0)


    def init_storage_share_combo(self):
       
        sdlist = self.storage_manager.get_sds(self.group.name)
        for sd in sdlist:
            self.share_map[sd.name] = sd.id
        # No need to inialize share combo when edit mode is launched.
        if self.mode == "NEW":
           return


        view = self.widgets.shared_storage_view
                        
        self.share_name_combo_hack = True
        init_combo(self.widgets.storage_share_name_combo, self.share_map)
        self.share_name_combo_hack = False
        if self.context.shared_storage_id is not None:
            sd = self.storage_manager.get_sd(self.context.shared_storage_id)
            set_value(self.widgets.storage_share_name_combo,
                          sd.id)
            self.widgets.storage_share_name_combo.set_property("sensitive", False)
            self.widgets.storage_share_name_combo.set_sensitive(0)
        else:
            self.widgets.storage_share_name_combo.set_active(0)
            
    def init_volumes_view(self, target_type):
        textrenderer = gtk.CellRendererText()

        if(target_type is None):
            return
        
        if(target_type == NFS) :
            self.nfs_model = gtk.ListStore(gobject.TYPE_STRING, # volume
                                           gobject.TYPE_STRING, #size
                                           gobject.TYPE_STRING, # attribute
                                           ) 
            columns = ["Name", "Size (GB)", "Attributes"]
            model = self.nfs_model
        elif(target_type == iSCSI) :
            self.iscsi_model = gtk.ListStore(gobject.TYPE_STRING, # volume
                                             gobject.TYPE_STRING, # size
                                             gobject.TYPE_STRING, # disk
                                             gobject.TYPE_STRING, # state 
                                             gobject.TYPE_STRING, # unique id
                                             ) 
            columns = ["Name", "Size (GB)", "Disk", "State", "Unique path"]
            model = self.iscsi_model
        elif(target_type == AOE) :
            self.aoe_model = gtk.ListStore(gobject.TYPE_STRING, # volume
                                           gobject.TYPE_STRING, # size
                                           gobject.TYPE_STRING, # disk
                                           gobject.TYPE_STRING, # status
                                           gobject.TYPE_STRING, # Interface
                                           
                                           )
            columns = ["Name", "Size (GB)", "Disk", "State", "Interface"]
            model = self.aoe_model
        else:
            return

        view = self.widgets.storage_volumes_view
        view.set_model(model)        
        
        # Remove the columns from the widget.            
        old_columns = view.get_columns()        
        for c in old_columns:
            view.remove_column(c)
        
        # And add new columns
        for c in columns:
            tree_column = gtk.TreeViewColumn(c, textrenderer,
                                            text=columns.index(c))
            tree_column.set_resizable(True)
            view.append_column(tree_column)
        

    def get_storage_type_map(self):
        return { "Network File Storage (NFS)":NFS,
                 "Internet SCSI (iSCSI)": iSCSI,
                 "ATA Over Ethernet (AOE)": AOE,
                 }

           
    def get_selected_volume(self):
        return self.disk_context


    def show(self, widget,
             storage_manager = None,
             shared_storage_id = None,
             managed_server = None,
             group = None,
             mode = "NEW",
             parent = None):

        """ Displays storage definition dialog"""
        if parent:
            self.dialog.set_transient_for(parent)
        self.managed_server = managed_server
        self.group = group
        self.storage_manager = storage_manager
        self.mode = mode
        self.context.shared_storage_id = shared_storage_id
        

        # Need to initialize 
        self.init_storage_share_combo( )
        self.init_managed_server_combo()

        self.init()
        self.scatter(self.context)

        
        self.update_widgets(self.mode)
        
        # storage_list to be filled up from storage manager
        ret = None

        self.dialog.show()
        self.valid = False
        while self.valid == False:
            ret = self.dialog.run()
            if ret == gtk.RESPONSE_DELETE_EVENT:
                break
            
        self.dialog.destroy()
        
        if ret == gtk.RESPONSE_OK:
            return True
        else:
            return False
        
#        return ret

    
    def scatter(self, context):
        if context.shared_storage_id is not None:
            sd = self.storage_manager.get_sd(context.shared_storage_id)
            connection_props = sd.connection_props
            context.target_type =  sd.type
            
            if sd.type == iSCSI:     # conn_props = target, options                
                set_value(self.widgets.storage_options,
                          connection_props.get("options"))
                set_value(self.widgets.storage_definition_host_entry,
                          connection_props.get("server"))
                set_value(self.widgets.sd_iscsi_target_entry,
                          connection_props.get("target"))
                if sd.creds_required == True:
                    creds = sd.creds
                    set_value(self.widgets.storage_userid, creds.get("username"))
             
            if sd.type == NFS:       # conn_props = server, share, mount_point, mount_options
                set_value(self.widgets.storage_options,
                          connection_props.get("mount_options"))
                set_value(self.widgets.storage_definition_host_entry,
                          connection_props.get("server"))
                set_value(self.widgets.storage_userid,
                          connection_props.get("mount_point"))
                set_value(self.nfs_share_entry,
                          connection_props.get("share"))
                
            if sd.type == AOE:       # conn_props = interface
                set_value(self.widgets.storage_definition_host_entry,
                          connection_props.get("interface"))

            context.storage_name = sd.name
            context.description = sd.description
        
        set_combo_value(self.widgets.storage_target_type, context.target_type)         
        set_value(self.widgets.storage_share_name_entry,context.storage_name)
        set_value(self.widgets.storage_share_desc_entry,context.description)
        

    def gather(self, context):
        if self.mode in ["NEW", "EDIT"] :
            context.storage_name = self.widgets.storage_share_name_entry.get_text()
        else:
            context.storage_name = get_combo_value(self.widgets.storage_share_name_combo)
            
        context.target_type = get_value(self.widgets.storage_target_type)
        context.target = get_value(self.widgets.storage_definition_host_entry)
        context.iscsi_target = get_value(self.widgets.sd_iscsi_target_entry)
        
        if context.target is None:
            context.target = ""

        if context.iscsi_target is None:
            context.iscsi_target = ""

        context.username = get_value(self.widgets.storage_userid)
        context.password = get_value(self.widgets.storage_pwd)
        context.options = get_value(self.widgets.storage_options)
        context.description = get_value(self.widgets.storage_share_desc_entry)
        if context.options is None:
            context.options = ""
        

    def on_cancel_button_clicked(self, widget):
       """  Cancel on shared storage details dialog """
       print "Shared Storage Details Cancel button clicked"
       self.valid = True
       self.init()

    def on_ok_button_clicked(self, widget):
       """  Ok  button on shared storage details """
       print "Shared Storage Details OK button clicked"
       # validate parameters
       self.gather(self.context)
       self.valid = True
       
       if self.mode in [ "NEW", "EDIT"]:
           
           #  Need validation for - 
           # 1. Storage name not empty
           # 2. Storage name already exists
           # iscsi
           # 3. Empty portal
           # 4. Empty target
           # 5. Empty username
           # 6. Empty password ... allowed. do not check.
           # nfs
           # 7. Empty mount point
           # 8. Empty share point
           # aoe
           # 9. Empty network interface
            
           
           # Collect the data to create a new storage definiton
           if self.context.storage_name is None or self.context.storage_name is "":
               showmsg("Please provide a name for the Storage")
               self.valid = False
               return False
       
           if self.mode == "NEW" and \
                  self.share_map.has_key(self.context.storage_name) :
               showmsg("Storage share name already exists")
               self.valid = False
               return False
                   
           target_type = get_value(self.widgets.storage_target_type)
           if target_type == NFS:
               error_msg = ""
               sharename = get_value(self.widgets.storage_definition_host_entry)
               if sharename is None or sharename is "":
                   error_msg = "Please provide a share name for the NFS Storage"
                    
               mountpoint = get_value(self.widgets.storage_userid)
               if mountpoint is None or mountpoint is "":
                   error_msg = error_msg + "\n Please provide a mount point for the NFS Storage"
            
               if error_msg != "":
                   showmsg(error_msg)
                   self.valid = False
                   return False
                   

           if target_type == iSCSI:
               error_msg = ""
               portal = get_value(self.widgets.storage_definition_host_entry)
               if portal is None or portal is "":
                   error_msg = "Please provide a portal name for the iSCSI Storage"
                                
               target = get_value(self.widgets.sd_iscsi_target_entry)
               if target is None or target is "":
                   error_msg = error_msg + "\n Please provide a target name for the iSCSI Storage"
                                
               if error_msg != "":
                   showmsg(error_msg)
                   self.valid = False
                   return False
           
                   
                
       else:
           # Collect the data to pass on to the VM settinggs
           if self.context.target_type == NFS:
               # special processing for NFS
               sd = self.storage_manager.get_sd(self.context.shared_storage_id)

               self.disk_context.type = sd.type
               self.disk_context.name = sd.connection_props.get("mount_point")
               self.disk_context.disk = sd.connection_props.get("mount_point")
               self.disk_context.size = ""
               self.disk_context.interface = ""
               self.disk_context.status = ""
           else:
               selection = self.widgets.storage_volumes_view.get_selection()
               result = selection.get_selected()
               if result is not None:
                   model, iter = result
                   sd = self.storage_manager.get_sd(self.context.shared_storage_id)
                   self.disk_context.type = sd.type
                   if iter is not None:
                       self.disk_context.name = \
                                              model.get_value(iter,
                                                              self.COLUMN_NAME )
                       self.disk_context.size = \
                                              model.get_value(iter,
                                                              self.COLUMN_SIZE )
                       self.disk_context.disk = \
                                              model.get_value(iter,
                                                              self.COLUMN_ATTR )
                       if self.context.target_type != NFS :
                           self.disk_context.interface = model.get_value(iter,
                                                                         self.COLUMN_INTERFACE )
                           self.disk_context.status = model.get_value(iter,
                                                                      self.COLUMN_STATUS )


       return True


    def on_nfs_mount_checkbox_clicked(self, widget):
        if self.widgets.storage_nfs_mount_point_checkbox.get_active() :
            self.widgets.storage_get_vol_btn.set_sensitive(0)
        else:
            self.widgets.storage_get_vol_btn.set_sensitive(1)

    def process_iscsi_output(self, output):
        # Sample iscsi Output :
        test_data =  \
                  {'DETAILS': [{'CurrentPortal': ' 192.168.12.104:3260,1',
                                'Lun': 'Test 1',
                                'State': 'running',
                                'Target': 'shared_104:store',
                                'mount_point': '/dev/sde',
                                'SIZE': ' 3142 MB',
                                'uuid': 'df150e55-3e28-4e93-8d9a-e6acfa7fe52c'},
                               {'CurrentPortal': ' 192.168.12.104:3260,1',
                                'Lun': 'Test 2',
                                'State': 'running',
                                'Target': 'shared_104:store',
                                'mount_point': '/dev/sdf',
                                'SIZE': ' 3142 MB',
                                'uuid': '/dev/disk/by-uuid/b472fcb4-f4fe-44f8-837f-333ad9244171'}],
                   'id': '5b76f1d1-fb55-683b-e0e2-dd04b8d13212',
                   'name': 't',
                   'op': 'GET_DISKS',
                   'type': 'iscsi'}
        if self.test_mode and output is None:
            output = test_data
        

        # TODO : change units to GB, header etc, add sorting of column
        self.widgets.storage_volumes_view.set_model(self.iscsi_model)
        if output and output.get("DETAILS"):
            for item in output.get("DETAILS"):
                iter = self.iscsi_model.append()
                if item.get("Lun") == None:
                    continue # ignore summary row for now.
                self.iscsi_model.set(iter,
                                     self.COLUMN_NAME, "Lun " + item['Lun'],
                                     self.COLUMN_SIZE, item["SIZE"],
                                     self.COLUMN_ATTR, item["mount_point"],
                                     self.COLUMN_STATUS, item["State"],
                                     self.COLUMN_INTERFACE, item['uuid'],
                                     )

        return output
            
    def process_nfs_output(self, output):
        # Test data
        test_data = \
        {'DETAILS': [{'AVAILABLE': '8.7G',
              'FILESYSTEM': '192.168.12.104:/mnt/Test',
              'MOUNT': '/mnt/vm_data',
              'USED': '38G'}] 
        }
        
        if self.test_mode and output is None:
            output = test_data

        pprint.pprint(output)
        self.widgets.storage_volumes_view.set_model(self.nfs_model)
        
        if output and output.get("DETAILS"):
            for item in output.get("DETAILS"):
                if len(item) == 0:
                    continue
                iter = self.nfs_model.append()
                self.nfs_model.set(iter,
                               self.COLUMN_NAME, item['MOUNT'],
                               self.COLUMN_SIZE, item['USED'],
                               self.COLUMN_ATTR, item['FILESYSTEM'],
                               )
        return output

            
    def process_aoe_output(self, output):
        test_data = {'DETAILS': [{'DEVICENAME': 'test5.0',
                                  'INTERFACENAME': 'eth0',
                                  'SIZE': '4.405GB',
                                  'STATUS': 'up'},
                                 {'DEVICENAME': 'test5.0',
                                  'INTERFACENAME': 'eth0',
                                  'SIZE': '9.405GB',
                                  'STATUS': 'up'}],
                     'id': 'e5631f9d-47f3-f597-2f39-38d3ba605d84',
                     'name': 'AOE Test',
                     'op': 'GET_DISKS',
                     'type': 'aoe'}

        if self.test_mode and output is None:
            output = test_data

        self.widgets.storage_volumes_view.set_model(self.aoe_model)
        if output and output.get("DETAILS"):
            for item in output.get("DETAILS"):
                iter = self.aoe_model.append()
                self.aoe_model.set(iter,
                                   self.COLUMN_NAME, item["DEVICENAME"],
                                   self.COLUMN_SIZE, item["SIZE"],
                                   self.COLUMN_ATTR, "/dev/etherd/"+ item["DEVICENAME"],
                                   self.COLUMN_STATUS, item["STATUS"],
                                   self.COLUMN_INTERFACE, item["INTERFACENAME"],
                                   )

        return output

    
    
    # may be make this just get_sd()
    def get_valid_sd(self):
        # validate from UI and create a temp SD
        (name, desc, type, target,
         iscsi_target,user,
         pwd, options) = (self.context.storage_name,
                          self.context.description,
                          self.context.target_type,
                          self.context.target,
                          self.context.iscsi_target,
                          self.context.username,
                          self.context.password,
                          self.context.options,
                          )
    
        creds_req = False
        creds = {}
        conn_options = {}
        if type == iSCSI:     # conn_props = target, options
            creds_req = True
            creds["username"] = user
            creds["password"] = pwd

            conn_options["server"] = target
            conn_options["target"] = iscsi_target
            conn_options["options"] = options

        if type == NFS:       # conn_props = share, mount_point, mount_options
            conn_options["server"] = target
            conn_options["share"] = iscsi_target
            conn_options["mount_point"] = user
            conn_options["mount_options"] = options

        if type == AOE:       # conn_props = interfaces
            conn_options["interface"] = target

        new_sd = StorageDef(None, name, type, desc,
                            conn_options,
                            creds_req)
        if creds_req == True:
            new_sd.set_creds(creds)

        if self.context.stats != None:
            new_sd.set_stats(self.context.stats)

        return new_sd


        

    def on_get_vol_button_clicked(self, widget):
       """  Get Volumes  button on shared storage details """
       print "Shared Storage Details Test button clicked"
       # 1. Log on to the storage.
       # 2. Query for the disks
       # 3. Display the disks.

       managed_server = get_value(self.widgets.storage_share_managed_server_combo)
       managed_node = self.group.getNode(managed_server)

       # Authenticate the node if not already :

       while not managed_node.is_authenticated():
           try:
               managed_node.connect()
           except AuthenticationException ,ex:
               creds = None
               creds_helper = main_context.get("creds_helper")
               if creds_helper:
                   creds = creds_helper.get_credentials(managed_node.hostname,
                                                        managed_node.username)
               else:
                   raise ex

               if creds is None:
                   raise Exception("%s Server not Authenticated" %
                                   managed_node.hostname)
               else:
                   managed_node.set_credentials(creds.username, creds.password)
       

       target_type = get_value(self.widgets.storage_target_type)

       # Let call the backend.
       # TODO : There are several mode from where we can get here.
       # need to change mode from boolean to multi-value var and do
       # appropriate thing here.
       # e.g. build sd from user input and call backend
       #      use exisitng one from the id and call the backend.

       details = None
       testmsg = None
       try:
           if not self.test_mode :
               if self.mode in ["NEW", "EDIT"] :
                   self.gather(self.context)
                   sd = self.get_valid_sd()
               else:
                   sd = self.storage_manager.get_sd(self.context.shared_storage_id)
           
               details = self.storage_manager.get_sd_details(sd, managed_node,
                                                         self.group)

               pprint.pprint(details)

       except Exception , ex:
           traceback.print_exc()
           testmsg = ex
           
       # Write processor for each: Take output and put it in to
       # data provider

       model = self.widgets.storage_volumes_view.get_model()
       model.clear()
       

       if target_type == NFS:
           details = self.process_nfs_output(details)
               
       elif target_type == iSCSI:
           details = self.process_iscsi_output(details)

       elif target_type == AOE:
           details = self.process_aoe_output(details)
       
       available_cap = 0
       total_cap = 0
       size = "SIZE"
       self.widgets.test_results_table.set_property("visible", True)
       self.widgets.storage_table_frame.set_property("visible", True)
       if target_type == NFS:
           self.widgets.storage_table_frame.set_property("visible", False)
       else:
           self.widgets.test_results_table.set_property("visible", True)
           #self.widgets.storage_test_available_size_label.set_property("visible", False)
           #self.widgets.storage_test_available_size_value_label.set_property("visible", False)

       if details and details.get("DETAILS"):
           for item in details.get("DETAILS"):
               if len(item) == 0:
                   continue
               if not item.get(size):
                   continue
               if target_type == NFS:
                   available_cap =item['AVAILABLE']

       if details and details.get("SUMMARY"):
           summary = details.get("SUMMARY")
           if summary.get("TOTAL"):
               total_cap = summary.get("TOTAL")

       
       # If we could not get details, this means get volumes failed.
       # Show status with red.
       if details == None or len(details) == 0 or testmsg != None:
           self.widgets.storage_test_result_label.set_markup("<b>Failure </b>")
           # self.widgets.storage_test_total_size_label.set_markup("<span foreground='red'>"+ str(testmsg) +" </span>")
           if testmsg:
               testmsg = str(testmsg).strip()
           else:
               testmsg = ""
           self.widgets.storage_test_total_size_label.set_markup(testmsg)
           self.widgets.storage_test_total_size_value_label.set_markup("  ")

           
           self.widgets.storage_test_available_size_label.set_property("visible", False)
           self.widgets.storage_test_available_size_value_label.set_property("visible", False)
           self.widgets.storage_test_image.set_from_pixbuf(small_kill_pb)
       else:
           self.widgets.storage_test_result_label.set_markup("<b>Success </b>")
           self.widgets.storage_test_total_size_label.set_markup("Total Size: ")
           self.widgets.storage_test_total_size_value_label.set_markup(str(total_cap) + " GB")
           if target_type == NFS:
               available = True
           else:
               available = False

           self.widgets.storage_test_available_size_label.set_property("visible", available)
           self.widgets.storage_test_available_size_value_label.set_property("visible", available)
           
           self.widgets.storage_test_available_size_label.set_markup("Available Size: ")
           self.widgets.storage_test_available_size_value_label.set_markup(str(available_cap) + " GB")
           self.widgets.storage_test_image.set_from_pixbuf(success_pb)
       
           # update the total value in to the storage definition
           # kludge :currently the only way to learn about total storage
           # size
           self.context.stats = {"TOTAL" : float(total_cap)}


    def on_target_type_changed(self, widget):
       """  Target type combobox """
       target_type = get_value(self.widgets.storage_target_type)
       if target_type == NFS:
           self.host_label.set_markup("Server:")
           self.user_label.set_markup("Mount Point:")
           self.options_label.set_markup("Mount Options:")
           self.nfs_share_label.set_markup("Share:")

       if target_type == iSCSI:
           self.host_label.set_markup("Portal:")
           self.user_label.set_markup("Username:")
           self.options_label.set_markup("Options:")
           
       if target_type == AOE:
           self.host_label.set_markup("Network Interfaces:")
           

       self.init_volumes_view(target_type)
       self.update_widgets(self.mode)

       
    def on_share_name_combo_changed(self, widget):
       print "Shared Storage Details shared storage combobox changed"
       # Need to get the values for selected shared storage and fill in the relevant values.
       if self.share_name_combo_hack:
           return 
       #If self.context.shared_storage_id is not None then set this id.
       # Else this has come from VM Settings. Let user select a shared storage id.
       sd_id = None
       if self.mode in ["NEW", "EDIT", "SELECT"] :
           sd_id = get_value(self.widgets.storage_share_name_combo)
           self.context.shared_storage_id = sd_id
       elif self.mode in [ "TEST"]:
           sd_id = self.context.shared_storage_id
           set_value(self.widgets.storage_share_name_combo,
                          sd_id)
           self.widgets.storage_share_name_combo.set_property("sensitive",
                                                              False)
               
       else:
           sd_id = self.context.shared_storage_id
           
       sd = self.storage_manager.get_sd(sd_id)
       if not sd:
           return
       else:
           self.scatter(self.context)
#       set_value(self.widgets.storage_target_type, sd.type)
       
       # If any of the following is true then do not need credentials.
       # Credentials are valid only for SCSI
       
       #if sd.type == iSCSI:
       if False: # for this release no username passwords
           if sd.creds_required == False or \
               sd.creds is not None and \
               (sd.creds.get("username") is None or sd.creds.get("username") == "") :
               self.widgets.storage_definition_user_label.set_property("visible", False)
               self.widgets.storage_userid.set_property("visible", False)
               self.widgets.storage_definition_pwd_label.set_property("visible", False)
               self.widgets.storage_pwd.set_property("visible", False)
           else:
               self.widgets.storage_definition_user_label.set_property("visible", True)
               self.widgets.storage_userid.set_property("visible", True)
               self.widgets.storage_userid.set_property("sensitive", False)
               self.widgets.storage_definition_pwd_label.set_property("visible", True)
               self.widgets.storage_pwd.set_property("visible", True)
               set_value(self.widgets.storage_userid, sd.creds.get("username"))

            
            

class RenameSharedStorageDialog(Container):
    """ Class rename shared storage """

    def __init__(self):
        """ Constructor"""
        wtree = gtk.glade.XML(gladefile, "SharedStorageRenameDialog")
        self.dialog = wtree.get_widget("SharedStorageRenameDialog")
        self.storage_name = wtree.get_widget("shared_storage_rename_text")
        self.selected_storage_label  = wtree.get_widget("selected_shared_storage_label")
        self.target_storage_name = ""
            # setup handlers
        wtree.signal_connect("on_rename_shared_storage_cancelbutton_clicked",
                                 self.on_cancel_button_clicked)
        wtree.signal_connect("on_rename_shared_storage_okbutton_clicked",
                                 self.on_ok_button_clicked)
        self.storage_name.set_activates_default(True)
        self.dialog.set_default_response(gtk.RESPONSE_OK)

        self.init()

    def init(self):
        self.storage_name.set_text("")

    def get_renamed_storage_name(self):
        return self.target_storage_name

    def show(self, src_shared_storage_name, parent = None):
        if parent:
            self.dialog.set_transient_for(parent)
        """ Displays rename image dialog"""
        self.src_storage_name = src_shared_storage_name
        self.init()

        self.selected_storage_label.set_text("Selected Shared Storage : " +
                                             self.src_storage_name)
        ret = self.dialog.run()
        if ret == gtk.RESPONSE_DELETE_EVENT:
            self.dialog.destroy()

        return ret


    def on_cancel_button_clicked(self, widget):
       """  Cancel on rename image dialog """
       self.init()
       self.dialog.destroy()

    def on_ok_button_clicked(self, widget):
       """  Ok  button on rename shared storage """
       # validate parameters
       self.target_storage_name = self.storage_name.get_text()
       if self.target_storage_name == "":
           showmsg("Please enter valid shared storage name")
           return
       self.target_storage_name = self.target_storage_name.strip()
       # If storage name is already in the store, then return.

       self.init()
       self.dialog.destroy()



class CloneSharedStorageDialog(Container):
    """ Class rename shared storage """

    def __init__(self):
        """ Constructor"""

        self.dialog = wtree.get_widget("SharedStorageCreateLikeDialog")
        self.storage_name = wtree.get_widget("shared_storage_clone_text")
        self.selected_storage_label  = wtree.get_widget("selected_clone_shared_storage_label")
        self.target_storage_name = ""
            # setup handlers
        wtree.signal_connect("on_clone_shared_storage_cancelbutton_clicked",
                                 self.on_cancel_button_clicked)
        wtree.signal_connect("on_clone_shared_storage_okbutton_clicked",
                                 self.on_ok_button_clicked)
        self.storage_name.set_activates_default(True)
        self.dialog.set_default_response(gtk.RESPONSE_OK)

        self.init()

    def init(self):
        self.storage_name.set_text("")

    def get_cloned_storage_name(self):
        return self.target_storage_name

    def show(self, src_shared_storage_name):
        """ Displays clone image dialog"""
        self.src_storage_name = src_shared_storage_name
        self.init()

        self.selected_storage_label.set_text("Selected Shared Storage : " + self.src_storage_name)
        ret = self.dialog.run()
        if ret == gtk.RESPONSE_DELETE_EVENT:
            self.dialog.destroy()


    def on_cancel_button_clicked(self, widget):
       """  Cancel on clone image dialog """
       self.init()
       self.dialog.destroy()

    def on_ok_button_clicked(self, widget):
       """  Ok  button on rename shared storage """
       # validate parameters
       self.target_storage_name = self.storage_name.get_text()
       if self.target_storage_name == "":
           showmsg("Please enter valid shared storage name")
           return
       self.target_storage_name = self.target_storage_name.strip()
       # If storage name is already in the store, then return.

       self.init()
       self.dialog.destroy()

# Dialogbox to set boot image location
class SelectBootImageDialog(Container):
    """ Class Set boo image location dialog """

    def __init__(self):
        """ Constructor"""
        Container.__init__(self)

        wtree = gtk.glade.XML(gladefile, "SelectBootImageDialog")

        self.dialog = wtree.get_widget("SelectBootImageDialog")
        self.init_widgets(wtree, ["boot_image_label",
                                  "boot_image_combobox",
                                  ])
        self.boot_image = ""
        # setup handlers
        wtree.signal_connect("on_select_boot_image_cancel_clicked",
                                 self.on_cancel_button_clicked)
        wtree.signal_connect("on_select_boot_image_ok_clicked",
                                 self.on_ok_button_clicked)
        self.dialog.set_default_response(gtk.RESPONSE_OK)

        init_combo(self.widgets.boot_image_combobox,
                   self.get_boot_map() )


    def get_boot_map(self):
        return { "CD ROM":"d",
                 "Disk": "c",
                 }

    def get_boot_image(self):
        return self.boot_image
    
    def show(self, vm_name, vm_boot_image):
        """ Displays Select boot image dialog"""
        self.vm_name = vm_name
        self.boot_image = vm_boot_image
        
        self.widgets.boot_image_label.set_text("Select Boot Device for : " + self.vm_name)
        set_combo_value(self.widgets.boot_image_combobox, self.boot_image)
        
        ret = self.dialog.run()
        if ret == gtk.RESPONSE_DELETE_EVENT:
            self.dialog.destroy()
        return ret


    def on_cancel_button_clicked(self, widget):
       """  Cancel on clone image dialog """
       self.dialog.destroy()

    def on_ok_button_clicked(self, widget):
       """  Ok  button on rename shared storage """
       # validate parameters
       self.boot_image = get_combo_value(self.widgets.boot_image_combobox)
       self.dialog.destroy()

### Module initialization
# Types of nodes in the tree
SERVER_POOL = "SERVER_POOL"
MANAGED_NODE = "MANAGED_NODE"
DOMAIN  = "DOMAIN"
DATA_CENTER= "DATA_CENTER"

IMAGE_STORE = "IMAGE_STORE"
IMAGE = "IMAGE"
IMAGE_GROUP = "IMAGE_GROUP"

STORAGE_DEFINITION = "STORAGE_DEFINITION"


(path, gladefile) = get_path("convirt.glade")
if not path:
    print "ERROR: Couldn't find glade interface definition file!"
    sys.exit(1)   # bad, but ok for now.


paused_pb   = gtk.gdk.pixbuf_new_from_file(path +\
                                           "/pixmaps/small_pause.png")
resident_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                           "/pixmaps/small_started_state.png")
not_resident_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                               "/pixmaps/small_shutdown.png")

small_kill_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                             "/pixmaps/small_kill.png")

node_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                       "/pixmaps/small_node.png")

dc_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                     "/pixmaps/small_pool.png")
pool_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                       "/pixmaps/group.png")

unknown_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                          "/pixmaps/small_unknown_state.png")

image_store_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                          "/pixmaps/small_image_store.png")

image_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                        "/pixmaps/small_image.png")

connected_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                        "/pixmaps/small_connect_blue.png")
disconnected_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                        "/pixmaps/small_disconnect_yellow.png")

appliance_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                        "/pixmaps/small_appliance.png")

convirt_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                         "/pixmaps/convirt.png")

success_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                         "/pixmaps/small_started_state.png")

failure_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                         "/pixmaps/kill.png")

kvm_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                      "/pixmaps/kvm.png")

xen_pb = gtk.gdk.pixbuf_new_from_file(path + \
                                      "/pixmaps/xen.png")

## error_img = gtk.Image()
## error_img.set_from_stock(gtk.STOCK_DIALOG_ERROR,
##                          gtk.ICON_SIZE_MENU)
## error_pb = error_img.get_pixbuf()

## warn_img = gtk.Image()
## warn_img.set_from_stock(gtk.STOCK_DIALOG_WARNING,
##                         gtk.ICON_SIZE_MENU)

## warn_pb = warn_img.get_pixbuf()

warn_pb = connected_pb
error_pb = disconnected_pb

gtk.window_set_default_icon(convirt_pb)

wtree = gtk.glade.XML(gladefile)

# KLUDGE : way to share global context
main_context = {}

file_editor =  FileViewEditDialog(wtree)
####
if __name__ == '__main__':
##     helper = CredentialsHelperDialog(wtree)
##     cred = helper.get_credentials("foobar", "root")
##     if cred:
##         print cred.get_username(), cred.get_password()
    dlg = MigrationChecksResultsDlg()
    err_list = (("Mem", "Test"), ("CPU", "TEST"))
    warn_list = (("HVM", "Warn Test"), ("Platform", "Warn TEST 1 sdslfjsdlfjsdjfs sdsdfsd sdfvdsfsdfs \n Second Line"))
    ret = dlg.show(err_list, warn_list)
    print ret
