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

# adjust the python paths for platforms
import sys
sys.path.append('/usr/lib/python')
sys.path.append('/usr/lib64/python')
sys.path.append('/usr/lib/xen-default/lib/python') # for debian


### signal handler to get stack trace.
import signal
import traceback
import inspect

def d_trace(num, frame):
    print "SIGNAL HANDLER "
    frames = sys._current_frames()
    i = 0
    for f in frames.values():
        print "Thread ", i
        i = i +1
        #print inspect.getframeinfo(f,20)
        traceback.print_stack(f)

    #print "STACK"
    #print inspect.stack(20)

signal.signal(signal.SIGQUIT, d_trace)

import string
import threading
import subprocess
import types
import socket
import time, datetime 
import traceback



# check for gtk intialization and display problems
try:
    import gtk
except Exception, ex:
    print ex
    print "ERROR : Please make sure DISPLAY environment variable is set (usually to :0.0) and you have permission to use it. You may need to execute 'xhost +local:' as desktop/display owner."
    exit(0)


from convirt.client.TreeViewTooltips import TreeViewTooltips
import gtk.glade, gobject

import webbrowser

import xmlrpclib
import xml.parsers.expat

import vte, re, os,signal,platform, glob

import convirt.core.utils.constants
from convirt.core.utils.constants import *
from convirt.core.utils import utils
from convirt.core.utils.utils import is_host_remote, Worker, read_python_conf
from convirt.core.utils.utils import dynamic_map, get_path,cleanupQCDomain

from convirt.core.utils.phelper import PHelper, AuthenticationException
from convirt.core.utils.NodeProxy import Node
from convirt.core.model.ImageStore import ImageStore, ImageUtils

import convirt.client.dialogs
from convirt.client.dialogs import NodeSelection, GroupVariablesDlg
from convirt.client.dialogs import AddServerGroupDialog, CloneImageDialog, GetLocalIPDlg
from convirt.client.dialogs import RenameImageDialog, RenameImageGroupDialog, AddImageGroupDialog
from convirt.client.dialogs import CredentialsHelper, FileViewEditDialog
from convirt.client.dialogs import MigrationChecksResultsDlg
from convirt.client.dialogs import wtree
from convirt.client.dialogs import file_selection 
from convirt.client.dialogs import main_context, show_wait_cursor, hide_wait_cursor, file_editor
from convirt.client.dialogs import UpdatesDlg
from convirt.client.dialogs import LicenseDlg
from convirt.client.dialogs import UIWorker
from convirt.client.dialogs import populate_nodes, append_dummy_row, showmsg, cb_wrapper
from convirt.client.dialogs import StorageDefinitionListDialog, SelectBootImageDialog
from convirt.client.htmltextview import HtmlTextView
from convirt.client.ApplianceList import ApplianceList, ImportApplianceDlg
from convirt.core.model.ApplianceStore import ApplianceStore
from convirt.core.model.PlatformRegistry import PlatformRegistry

from convirt.client.NWUI import NWListDlg

from convirt.core.model.GridManager import GridManager
from convirt.core.model.storage import StorageManager
from convirt.core.model.network import NwManager

from convirt.core.model.Groups import ServerGroup
from convirt.core.model.VM import VM, VMConfig
from convirt.client.VMInfoHelper import VMInfoHelper

from convirt.client.ui_utils import populateTreeWithDictInfo, populateTreeWithListInfo

from convirt.core.model.PlatformUIHelper import PlatformUIHelper
import pprint

dialogs = convirt.client.dialogs


#
# class definitions
#

from convirt.core.model.ManagedNode import ManagedNode,NodeException

#
# debug or not.
#

debug = True

def print_stack():
    if debug:
        traceback.print_exc()
        

## use threads to do heavy weight background op or not.

enable_background_ops = True

def threads_enter():
    if enable_background_ops:
        #print "### Enter ", threading.currentThread()
        gtk.gdk.threads_enter()
        #print "### Entered ", threading.currentThread()

def threads_leave():
    if enable_background_ops:
        #print "### Leave", threading.currentThread()
        gtk.gdk.threads_leave()
        #print "### Left", threading.currentThread()


class LeftNav:
    """
    Keeps track of the left side navigation
    List of Managed Nodes as well as virtual machines running on them.
    """
    # Types of nodes in the tree
    SERVER_POOL = dialogs.SERVER_POOL
    MANAGED_NODE = dialogs.MANAGED_NODE
    DOMAIN  = dialogs.DOMAIN
    DATA_CENTER = dialogs.DATA_CENTER

    IMAGE_STORE = dialogs.IMAGE_STORE
    IMAGE = dialogs.IMAGE
    IMAGE_GROUP = dialogs.IMAGE_GROUP
    
    STORAGE_DEFINITION = dialogs.STORAGE_DEFINITION
    STORAGE_DEF_NODE = "Storage Definition"
    # NodeList Constructor
    def __init__(self, wtree):
        """
        constructor, initialize the widgets
        Tree populated with nodes from grid manager
        Assumes manager as global variable.
        """
        self.wtree = wtree
        self.left_nav_view = wtree.get_widget("DomView")
        self.left_nav_view.get_selection().connect("changed",
                                               cb_wrapper,self.handle_selection)
        self.left_nav_view.connect("row-activated",
                                   cb_wrapper,self.handle_row_activated)

        self.left_nav_view.connect("row-expanded",
                                cb_wrapper,self.handle_row_expanded)

        # multiselct
        #self.left_nav_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE)


        # initialize columns
        pbrenderer = gtk.CellRendererPixbuf()
        column = gtk.TreeViewColumn("State", pbrenderer)
        column.set_cell_data_func(pbrenderer, dialogs.get_state_pixbuf,
                                  appliance_store)
        self.left_nav_view.append_column(column)

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

        self.left_nav_view.append_column(column)

        # dnd
        self.TARGETS = [("LEFT_NAV", gtk.TARGET_SAME_WIDGET, 0)]
        self.left_nav_view.enable_model_drag_source( gtk.gdk.BUTTON1_MASK,
                                                     self.TARGETS,
                                                     gtk.gdk.ACTION_DEFAULT|
                                                     gtk.gdk.ACTION_MOVE|
                                                     gtk.gdk.ACTION_PRIVATE)
        
        self.left_nav_view.enable_model_drag_dest(self.TARGETS,
                                                  gtk.gdk.ACTION_DEFAULT |
                                                  gtk.gdk.ACTION_PRIVATE)
        
        self.left_nav_view.connect("drag_data_get", self.drag_data_get_data)
        self.left_nav_view.connect("drag_data_received",
                                   self.drag_data_received_data)

        #self.left_nav_view.set_rubber_banding(True)
        # dnd end

        # make the tree searchable using ctrl-f
        self.left_nav_view.set_search_column(0)
        
        # object id represents id for the object being represented.
        self.left_nav_tree_model = \
               gtk.TreeStore(gobject.TYPE_STRING,   # name / display name
                             gobject.TYPE_STRING,   # type 
                             gobject.TYPE_PYOBJECT, # managed_node, group
                             gobject.TYPE_STRING,   # group name/image_group_id
                             gobject.TYPE_STRING,   # provider_id
                             gobject.TYPE_STRING    # object_id
                             )

        # Add a sorter inbetween
        #sorted_model = gtk.TreeModelSort(self.left_nav_tree_model)
        #sorted_model.set_sort_column_id(0, gtk.SORT_ASCENDING)

        sorted_model = self.left_nav_tree_model

        # This is also behaving strange, when timer is enabled.
        # some multi-threaded problem!!
        #sorted_model.set_sort_column_id(0, gtk.SORT_ASCENDING)
        self.left_nav_view.set_model(sorted_model)
        
        
        ## Does not work..! property not available.!
        #self.left_nav_view.set_property("show-expanders", True)
        #self.left_nav_view.set_show_expanders(True)

        self.refresh_nodes()


    # signal handlers

    # callback for gathering selections
    def gather_selected_iters(self, model, path, iter, selected):
        selected.append((model,iter))
    
    # return selection only if one of the node is selected.
    def get_selected(self):
        selected=[]
        selection = self.left_nav_view.get_selection()
        if selection:
            selection.selected_foreach(self.gather_selected_iters, selected)
            if len(selected) > 0:
                return selected[0]
            
        return None, None

    def gather_selected(self, model, path, iter, selected):

        node = model.get_value(iter, 2)
        type = model.get_value(iter, 1)
        name = None
        if node is not None:
            if isinstance(node, ManagedNode):
                name = node.hostname
            else:
                name = node.name
        objid = None 
        if( type == self.IMAGE): 
            objid = model.get_value(iter, 5)
        else:
            objid = model.get_value(iter, 3)
        
        data = (model.get_value(iter, 0),
                model.get_value(iter, 1),
                name,
                objid)
        
        selected.append((path,data))
    
        
    # return an array of model, iter selections
    # Collect the data for the selected object and its parent
    def get_multi_selected(self):
        selected=[]
        parent_data = None
        parent_iter = None

        selection = self.left_nav_view.get_selection()
        if selection:
            selection.selected_foreach(self.gather_selected, selected)
            if len(selected) > 0:
                first_path, data = selected[0]
                parent_path = first_path[0:-1]
                for p, d in selected:
                    if p[0:-1] != parent_path:
                        raise Exception("All selected nodes must be peers.")

                # gather information about parent node
                if parent_path :
                    model = self.left_nav_view.get_model()
                    parent_iter = model.get_iter(parent_path)
                
                if parent_iter:
                    # Get the type of the object we are trying to drag and drop.
                    type = model.get_value(parent_iter, 1)                    
                    objid = model.get_value(parent_iter, 5) 
                    
                    # If object type is image group, we need image group_id. 
                    if( type == self.IMAGE_GROUP): 
                        objid = model.get_value(parent_iter, 5)
                        parent_data = (model.get_value(parent_iter, 0), 
                                       model.get_value(parent_iter, 1),
                                       None,
                                       objid)
                    else: 
                        parent_data = (model.get_value(parent_iter, 0), 
                                       model.get_value(parent_iter, 1),
                                       None,
                                       model.get_value(parent_iter, 3)
                                       )
        
        return selected, parent_data
            
        


    ## dnd handlers
    def drag_data_get_data(self, treeview, context, selection, target_id,
                                 etime):
        treeselection = treeview.get_selection()
        model, iter = self.get_selected()

        try:
            selected, parent_data = self.get_multi_selected()
        except Exception ,ex:
            showmsg(ex)
            return

        if selected and len(selected) > 0:
            first = selected[0]
        else:
            return
        
        #(source_name,source_type, managed_node, group_name)  = self.get_selection()
        #if managed_node is None:
        #    return
        #if source_type == self.DATA_CENTER or \
        #       source_type == self.SERVER_POOL:
        #    showmsg("Bad source selection.")
        #    return False

        #(parent_name, parent_type, parent_node, parent_group_name) = self.get_parent_selection()

        ## GridManage API specific
        ## if parent_type == self.DATA_CENTER:
        ##    parent_name = None

        ## GridManage API specific
        if parent_data is not None:
            (p_name, p_type, p_node, p_grpname) = parent_data
            if p_type == self.DATA_CENTER:
                parent_data = (None, p_type, None, p_grpname)

            if p_type == self.IMAGE_GROUP:
                parent_data = (p_name, p_type, None, p_grpname)

        data = str((selected, parent_data))
        
        selection.set(selection.target, 8, data)
   
    def drag_data_received_data(self, treeview, context, x, y, selection,
                                info, etime):
        model = treeview.get_model()
        data = selection.data
        if data is None:
            return
        print "SOURCE = ", eval(data)
        src = eval(data)
        #(src_name, src_type, src_node_name, \
        # parent_name, parent_type, parent_grp_name)  = src

        (selected, parent_data) = src
        (parent_name, parent_type, parent_node, parent_grp_name) = parent_data

        if selected is None or len(selected) < 1:
            return

        # validate that all the selections are of the same type
        first_path, first_data = selected[0]
        src_type = first_data[1]
        for path, data in selected:
            type = data[1]
            if type != src_type:
                raise Exception("All selection must be of same type.")

        ## Get information about the destination node
        drop_info = treeview.get_dest_row_at_pos(x, y)
        if drop_info:
            path, position = drop_info
            #print path
            iter = model.get_iter(path)
                                    
            (dest_name, dest_type,dest_node) = \
                             (model.get_value(iter,0),
                              model.get_value(iter,1),
                              model.get_value(iter,2)
                              )
            
            if src_type == self.IMAGE and \
               dest_type == self.IMAGE_GROUP:
                dest_node_group = model.get_value(iter,5)
            else:
                dest_node_group = model.get_value(iter,3)
                
#            print "DEST ", dest_name, dest_type,  dest_node, dest_node_group
            if dest_type == self.DOMAIN:
                showmsg("Bad destination selection")
                return

            if (dest_name, dest_type) == (parent_name, parent_type) :
                showmsg("Nothing to do.")
                return

            # drag and drop managed node
            if src_type == self.MANAGED_NODE and \
               (dest_type == self.SERVER_POOL or \
                dest_type == self.DATA_CENTER):

                if len(selected) == 1:
                    src_name = selected[0][1][0]
                else:
                    src_name = "selected servers"

                
                
                if confirmation("Do you want to move " +  src_name + " to " +
                                dest_name + "?"):
                    # GridManager API specific
                    if dest_type == self.DATA_CENTER:
                        dest_name = None
                    for path, data in selected:
                        src_node_name = data[0]
                        m_node = manager.getNode(src_node_name, parent_name)
                        manager.addNode(m_node, dest_name)
                        manager.removeNode(m_node.hostname,parent_name)

                    self.refresh_nodes()
                    return
                else:
                    return
            # drag and drop VM
            if src_type == self.DOMAIN and dest_type == self.MANAGED_NODE:
                if len(selected) == 1:
                    src_name = selected[0][1][0]
                else:
                    src_name = "selected VMs"

                src_node_name = selected[0][1][2]
                if confirmation("Do you want to live migrate " +  src_name +
                                " on " + src_node_name + " to " + dest_name + "?"):
                    src_node = manager.getNode(src_node_name, parent_grp_name)
                    vm_list = []
                    for path, data in selected:
                        src_node_name = data[0]
                        vm_list.append(src_node.get_dom(src_name))
                        

                    migrate_doms(src_node, vm_list, dest_node, True)
                    return
                
                else:
                    return

            # drag and drop images
            if src_type == self.IMAGE and \
               dest_type == self.IMAGE_GROUP:

                if len(selected) == 1:
                    src_name = selected[0][1][0]
                    src_image_id = selected[0][1][3] 
                else:
                    src_name = "selected images"

                if confirmation("Do you want to move " +  src_name + " to " +
                                dest_name + "?"):
                    # Move image from src image group to dest image goup
                    for path, data in selected:
                        
                        image_group_dest = image_store.image_groups[dest_node_group]
                        image_group_src = image_store.image_groups[parent_grp_name]
                        image_src = image_store.images[src_image_id]
                        
                        image_store.add_image_to_group(image_group_dest, image_src)
                        image_store.remove_image_from_group(image_group_src, image_src)

                    self.refresh_nodes()
                    return
                else:
                    return

            showmsg("Bad drag and drop operation.")
        return


    ## dnd handlers end


    def handle_row_activated(self, treeview, path, column):
        """
        handle double-click on the managed node.
        """
        model = treeview.get_model()
        iter = model.get_iter(path)
        if iter:
            node_type = model.get_value(iter,1)
            tree_node = model.get_value(iter,2)
            if node_type == self.MANAGED_NODE:
                if self._refresh_doms(model, tree_node, path, path):
                    path = model.get_path(iter)
                    # JDX
                    #treeview.expand_row(path, True)
            elif node_type == self.DOMAIN:
                Coordinator.handle_row_activated()
            else:
                treeview.expand_row(path, True)

        return True


    # A node in the tree is expanded/collapsed
    def handle_row_expanded(self, treeview, iter, path, userdata=None):
        def cb_suc_handle_row_expanded(treeview):
            try:
                threads_enter()
                Coordinator.handle_nav_selection(treeview)
            finally:
                threads_leave()
            
        model = treeview.get_model()
        iter = model.get_iter(path)
        if iter:
            node_type = model.get_value(iter,1)
            tree_node = model.get_value(iter,2)
            
            if node_type == self.MANAGED_NODE:
                do_work(lambda : (cb_connect(tree_node, creds_helper),
                                            self._refresh_doms(model,
                                                    tree_node,
                                                    path, path)),
                        "Expand node " + tree_node.hostname,
                        lambda : cb_suc_handle_row_expanded(treeview))
                        
                
        return True

        
    def handle_selection(self, widget=None):
        """Handles the selection of a domain in the domain tree view"""

        Coordinator.handle_nav_selection(widget)


    def get_parent_selection(self):

        tree_selection = self.left_nav_view.get_selection()
        model, iter = self.get_selected()

        if iter is not None:
            parent_iter = model.iter_parent(iter)
            return (model.get_value(parent_iter,0),
                    model.get_value(parent_iter,1),
                    model.get_value(parent_iter,2),
                    model.get_value(parent_iter,3),
                    model.get_value(parent_iter,4),
                    model.get_value(parent_iter,5)
                    )
        
        return (None, None, None, None, None, None)
    

    def refresh_doms(self, auto=False, dom_name = None):
        """ take current selection and refresh dom list."""
        tree_selection = self.left_nav_view.get_selection()
        model, iter = self.get_selected()
        if not iter :
            # no selection
            return True

        node_type = model.get_value(iter,1)
        selected_node = model.get_value(iter,2)

        if node_type == self.DOMAIN:
            # current selection on dom, get the managed node
            parent_iter = model.iter_parent(iter)
            managed_node = model.get_value(parent_iter,2)
            path = model.get_path(parent_iter)
            current_path = model.get_path(iter)
            return self._refresh_doms(model, managed_node, path,
                                      current_path, auto)
        elif node_type == self.MANAGED_NODE:
            # current selection is managed node itself
            managed_node = selected_node
            path = model.get_path(iter)
            return self._refresh_doms(model, managed_node, path, path, auto)



    # utility methods
    
    def _refresh_doms(self, model, managed_node,
                      path, current_path,
                      auto = False):
        """
        refresh dom list for the managed node, refered by iter
        """
        
        # This is done in the reverse way, as the normal way
        # does not work. We add the new nodes and remove the old
        # ones later.Need to be careful, at some point there
        # would be more than one instance of the same dom here!!
        # Also, the order matters. (careful, when we add sorting!)
        
        #print managed_node.hostname, managed_node.is_authenticated()
        iter = model.get_iter(path)
        if isinstance(managed_node, ManagedNode) and iter:
            if auto and (not managed_node.is_authenticated() or \
                                            managed_node.is_in_error()):
                return True

            num_old_doms = model.iter_n_children(iter)            
            # get new ones and insert them
            # catch the expact error. Intermittently we get this because
            # server returns an empty string. (dont know why, yet)
            try:
                managed_node.refresh()
                doms = managed_node.get_dom_names()
            except xml.parsers.expat.ExpatError, e:
                #print "_refresh_doms() :", e
                return                
            except Exception, e:
                #print_stack()
                #showmsg('Exception '+str(e))
                #if debug:
                #    print e
                raise
            

            doms.sort()
            # add the dummy row back if no current doms
            if len(doms) == 0:
                append_dummy_row(model, iter)

            for dom_name in doms:
                #if not dom.is_resident():
                #    Coordinator.handle_kill_dom(dom)
                node = model.iter_children(iter)
                exists = False
                while node:
                    d_name = model.get_value(node,0)
                    node_type = model.get_value(node,1)
                    m_node = model.get_value(node,2)

                    #update the managed node instance if required.
                    if m_node is not None and m_node is not managed_node:
                        model.set_value(node,2, managed_node)
                        
                    if node_type == self.DOMAIN and d_name == dom_name:
                        exists = True
                        #model.set_value(node,0,dom_name)
                        #path = model.get_path(node)
                        #model.row_changed(path,node)
                        #print "path, iter ", path, iter
                        break

                    if d_name > dom_name:  # keep things in sorted order
                        break

                    node= model.iter_next(node)
                    
                if not exists and dom_name != "Domain-0": #Hard coding ..bad
                    #print "adding new node", dom_name
                    model.insert_before(iter,node,
                                       [dom_name,self.DOMAIN,
                                        managed_node,
                                        None, None, None])

            # clear old nodes that do not exist
            next_node = model.iter_children(iter)
            while next_node: 
                this_node = next_node
            
                dom_name = model.get_value(this_node,0)
                node_type = model.get_value(this_node,1)

                if dom_name is not None and dom_name != "" and \
                       node_type == self.DOMAIN:

                    if dom_name in doms:
                        d = managed_node.get_dom(dom_name)
                        if not managed_node.is_resident(dom_name):
                            Coordinator.handle_kill_dom(d)
                        else:
                            Coordinator.handle_existing_dom(d)

                        next_node = model.iter_next(this_node)
                            
                    else:
                        #print "removing " , dom_name
                        Coordinator.handle_missing_dom(managed_node,
                                                       dom_name)
                        next_node = model.iter_next(this_node)
                        model.remove(this_node)
                        
                else:
                    #print "removing ", dom_name
                    next_node = model.iter_next(this_node)
                    model.remove(this_node)



            # set  selection to current selection
            try:
                selection = self.left_nav_view.get_selection()
                if auto: # suppress callbacks
                    Coordinator.fromUserAction = False
                ## JDX selection.select_path(current_path)
            finally:
                Coordinator.fromUserAction = True
        else :
            print "refresh_dom called without Server"
            print managed_node.__class__, iter

        self.left_nav_view.queue_draw()
        return True

    def populate_storage(self):        

        i_iter = self.left_nav_tree_model.append(None,
                                                 [self.STORAGE_DEF_NODE,
                                                  self.STORAGE_DEFINITION,
                                                  None, None, None, None])

    def populate_images(self):        

        i_iter = self.left_nav_tree_model.append(None,
                                                 ["Image Store",
                                                  self.IMAGE_STORE,
                                                  None, None, None, None])

        # get the groups
        image_groups = image_store.get_image_groups()

        for group in image_groups.itervalues():
            g_iter = \
                   self.left_nav_tree_model.append(i_iter,
                                                   [group.name,
                                                    self.IMAGE_GROUP,
                                                    local_node,
                                                    None, 
                                                    None,
                                                    group.id])
            
            images = group.get_images()

            # Sort the images
            if images:
                image_list = [ x for x in images.itervalues() ]
                image_list.sort(key=lambda(x) : x.get_name())
            else:
                image_list = []
            

            for image in image_list:
                # get the provider id and put it in the model
                # use the group_name slot for now.
                provider_id = ""
                try:
                    cfg, i_cfg  = image.get_configs()
                    if cfg:
                        provider_id = cfg.get("provider_id")
                        
                except Exception,ex:
                    print "Error getting provider id for ", image
                    print ex

                print "setting provider id to ", image.name, provider_id
                iter = \
                     self.left_nav_tree_model.append(g_iter,
                                                     [image.name,
                                                      self.IMAGE,
                                                      local_node,
                                                      group.id,
                                                      provider_id,
                                                      image.id])

    def refresh_nodes(self):
        populate_nodes(manager,
                       self.left_nav_view, self.left_nav_tree_model)
        self.populate_images()

#        self.populate_storage()
        
    def add_group(self, group):
        if group is None:
            return
        
        manager.addGroup(group)

        # update the UI
        model = self.left_nav_tree_model
        root = model.get_iter_root()
        node_added = False
        next = root
        last = None
        
        data =  [group.name,
                 self.SERVER_POOL,
                 group,
                 None,
                 None,
                 None]
        
        if root:
            next = model.iter_children(root)  #skip the root group
            if not next :
                # root node is empty
                model.append(root,data)
                return
            
            while next :
                name = model.get_value(next, 0)
                type = model.get_value(next, 1)
                if type == self.SERVER_POOL:
                    if name > group.name:
                        model.insert_before(root, next, data)
                        node_added = True
                        break
                    last = next
                next = model.iter_next(next)

        else:
            # Should never happen
            pass

        if not node_added:
            if last:
                # group name higher than all known groups
                model.insert_after(root, last, data)  
            else:
                # root node contains no groups
                model.append(root, data)
                                     
    def remove_group(self, group_name, deep=False):
        if group_name is None:
            return
        
        manager.removeGroup(group_name, deep)
        grp_iter = self.get_group_iter(group_name)
        if grp_iter:
            self.left_nav_tree_model.remove(grp_iter)
            

    def add_node(self, node, group_name = None):
        manager.addNode(node, group_name)
        node_added = False
        # update UI
        model = self.left_nav_tree_model
        data = [ node.hostname, self.MANAGED_NODE, node, group_name, None, None ]

        last = None
        if group_name is None:
            grp_iter = self.left_nav_tree_model.get_iter_root()
        else:
            grp_iter = self.get_group_iter(group_name)
            
        if grp_iter :
            node_iter = model.iter_children(grp_iter)
            if not node_iter:
                # no nodes under the group
                iter = model.append(grp_iter, data)
                append_dummy_row(model, iter)
                node_added = True
            else:
                while node_iter:
                    name = model.get_value(node_iter, 0)
                    type = model.get_value(node_iter, 1)
                    if type == self.MANAGED_NODE:
                        if name > node.hostname:
                            iter = model.insert_before(grp_iter, node_iter,
                                                       data)
                            append_dummy_row(model, iter)
                            node_added = True
                            break
                        last = node_iter
                    # special case : we want nodes to be before
                    # the groups 
                    if group_name is None:
                        if type == self.SERVER_POOL: # we reached the groups
                            iter = model.insert_before(grp_iter, node_iter,
                                                       data)
                            append_dummy_row(model, iter)
                            node_added = True
                            break
                    node_iter = model.iter_next(node_iter)
        else:
            # should never happen
            pass
                    
        if not node_added:
            if last:
                # node name higher than all known nodes
                iter = model.insert_after(grp_iter,last, data)
                append_dummy_row(model, iter)
            else:
                # group node contains no nodes
                iter = model.append(grp_iter, data)
                append_dummy_row(model, iter)
                

    def remove_node(self, node, group_name):
        manager.removeNode(node.hostname, group_name)
        node_iter = self.get_node_iter(group_name, node.hostname)
        if node_iter:
            self.left_nav_tree_model.remove(node_iter)
        #else:
        #    print "node not found %s:%s" % ( group_name, node.hostname)


    def get_node_iter(self, group_name, node_name):
        model = self.left_nav_tree_model
        if group_name is None:
            grp_iter = self.left_nav_tree_model.get_iter_root()
        else:
            grp_iter = self.get_group_iter(group_name)

        
        if grp_iter :
            node_iter = model.iter_children(grp_iter)
            while node_iter:
                name = model.get_value(node_iter, 0)
                type = model.get_value(node_iter, 1)
                if type == self.MANAGED_NODE:
                    if name == node_name:
                        return node_iter
                node_iter = model.iter_next(node_iter)
        return None
                

    # return iter for the group name in the tree
    def get_group_iter(self,group_name):
        model = self.left_nav_tree_model
        root = model.get_iter_root()
        
        if group_name is None:
            return None
        
        if root:
            grp_iter = model.iter_children(root)  #skip the root group
            while grp_iter :
                name = model.get_value(grp_iter, 0)
                type = model.get_value(grp_iter, 1)
                if type == self.SERVER_POOL:
                    if name == group_name:
                        return grp_iter
                grp_iter= model.iter_next(grp_iter)
        return None
        

    # returns tuple with name, node_type and managed node, group
    def get_selection(self, path=None):
        """
        return current selection 
        returns either ManagedNode,  Dom or None
        """

        if path is None:
            widget = self.left_nav_view.get_selection()
            treemodel, treeiter = self.get_selected()
        else:
            treemodel = self.left_nav_view.get_model()
            treeiter = treemodel.get_iter(path)

        if treeiter:
            # try to give group context to the domain.
            type = treemodel.get_value(treeiter, 1)
            group_name = treemodel.get_value(treeiter, 3)
            if type == LeftNav.DOMAIN and group_name is None:
                (name,node_type,m, g,ignore,id) = self.get_parent_selection()
                if node_type == LeftNav.MANAGED_NODE:
                    group_name = g
            


            return (treemodel.get_value(treeiter, 0),
                    treemodel.get_value(treeiter, 1),
                    treemodel.get_value(treeiter, 2),
                    group_name, # treemodel.get_value(treeiter, 3),
                    treemodel.get_value(treeiter, 4),
                    treemodel.get_value(treeiter, 5)
                    )

        return (None,None,None,None,None,None)

    def get_selection_type(self, path = None):
        (name, node_type, managed_node, group_name, ignore, obj_id) = self.get_selection(path)
        return node_type

    def get_managed_node(self, path = None):
        """
        return managed node for the currently selected dom
        """
        (name, node_type, managed_node, group_name, ignore, obj_id) = self.get_selection(path)
        return managed_node

    def set_context(self, group_name=None,
                    server_name=None,
                    vm_name=None,
                    select = True):
        
        if group_name is not None:
           if select and server_name is None and vm_name is None:
               select_group = True
           else:
               select_group = False
           print "requesting to expand ", group_name
           self.set_selection(group_name,self.SERVER_POOL,
                              select = select_group,
                              op="row-activated")
           
        if server_name is not None:
            if select and vm_name is None:
                select_server = True
            else:
                select_server = False
            print "requesting to expand ", server_name
            self.set_selection(server_name,
                               self.MANAGED_NODE,
                               select = select_server,
                               op="row-activated")
        if vm_name is not None:
            print "requesting to select ", vm_name
            self.set_selection(vm_name, self.DOMAIN, select = select)

    def set_selection(self, node_name, node_type, select=True,
                      op = None, op_args = None):
        """
        set the current selection to either a Dom or a ManagedNode
        """
        # this may be tricky
        ret = self.left_nav_tree_model.foreach(self.select_node,
                                               (node_name,
                                                node_type,
                                                select,op,
                                                ()))

    def select_node(self, model, path, iter, context):
        (node_name, node_type, select, op, op_args) = context
        if iter:
            (name, type, managed_node) = (model.get_value(iter, 0),
                                          model.get_value(iter, 1),
                                          model.get_value(iter, 2))

            if name == node_name and type == node_type:
                if select:
                    self.left_nav_view.set_cursor(path)
                if op == "row-activated":
                    # we know that last param is not used. so pass None.
                    self.handle_row_activated(self.left_nav_view, path, None)
                elif op == "expand-node":
                    self.left_nav_view.expand_row(path, True)
                return True

    def addDomFile(self, managed_node, filename):
        """Adds a dom specified by it's file name to the index"""
        try:
            dom = managed_node.add_dom_config(filename)
            self.refresh_doms()
        except (Exception, StandardError), e:
            showmsg('FAILED. Invalid File: '+str(e))


    def remDomFile(self, managed_node, filename):
        """Remove a dom specified by it's file name to the index"""
        if managed_node.remove_dom_config(filename):
            self.refresh_doms()
        else:
            return False
        


class Coordinator:
    """ Class that takes care of cordination """
    # currently the toolbar, menu and popup are assumed to be part of
    # cordinator, later can be moved out in to a separate class



    # going with static methods (can make it singleton later)
    # Also, this is not a pure cordinator (yet) but central place
    # for all interactiona.

    nav = None
    notebook = None
    fromUserAction = True

    # timer vars
    skipcount = 0
    stat_refresh_rate = 5
    stat_refresh_count = stat_refresh_rate


    last_focus_in = None
    last_focus_out = None

    popup_path = None
    
##  Singleton bit later.
##     @classmethod
##     def instance():
##         return self._instance

##     @classmethod
##     def initialize(nav, notebook):
##         self._instance = Coordinator(nav, notebook)

##     def __init__(self,nav, notebook):
##         self.nav = nav
##         self.notebook = notebook
    
    @classmethod
    def set_popup_path(cls, path):
        cls.popup_path = path

    @classmethod
    def get_popup_path(cls):
        # invoked from popup
        return cls.popup_path

    @classmethod
    def is_menu_from_popup(cls, widget):
        popup_list = (vm_popup, node_popup, pool_popup, dc_popup,
                      image_popup, image_group_popup, image_store)
        if widget is not None:
            if widget in popup_list or widget.parent in popup_list:
                return True
    
    @classmethod
    def set_nav(cls,nav):
        cls.nav = nav

    @classmethod
    def set_notebook(cls, notebook):
        cls.notebook =  notebook
    

    @classmethod
    def handle_row_activated(cls):
        if cls.nav == None:
            return
        
        (name, node_type, managed_node, group, provider_id, obj_id) = cls.nav.get_selection()
        if managed_node is None:
            return

        if node_type == LeftNav.DOMAIN:
            if managed_node.isDomU(name):
                if managed_node.is_resident(name):
                    dom = managed_node.get_dom(name)
                    cls.notebook.showTab(dom)

       
    @classmethod
    def handle_nav_selection(cls, widget):
        cls.stateRefresh()
        if cls.nav == None or cls.fromUserAction == False:
            return
        (name, node_type, managed_node, group, provider_id, obj_id) = cls.nav.get_selection()
        
        cls.notebook.summary_tab.enable_tab()
        cls.notebook.info_tab.enable_tab()
        
        if node_type == LeftNav.IMAGE or \
               node_type == LeftNav.IMAGE_STORE or \
               node_type == LeftNav.IMAGE_GROUP:
            cls.notebook.summary_tab.disable_tab()
            cls.notebook.showDomTab(None, None) #uggh
            return

        
        if node_type == LeftNav.SERVER_POOL or \
               node_type == LeftNav.DATA_CENTER:
            cls.notebook.info_tab.disable_tab()
            cls.notebook.showSummaryTab()
                
        #if managed_node is None:
        #    return
        
        #Handle if the selection was a Dom on a Node
        if node_type == LeftNav.DOMAIN:
            cls.notebook.showDomTab(managed_node,name)

        # handle node selection
        elif node_type==LeftNav.MANAGED_NODE:
            #managed_node.is_authenticated() and \
            #if not managed_node.is_in_error():
            cls.notebook.showSummaryTab()
            



    @classmethod
    def handle_timer_callback(cls):
        if cls.nav is None : return
        try:
            try:
                sys.stdout.flush() # periodically flush stuff in to log
                sys.stderr.flush()
                cls.fromUserAction = False
                cls.nav.refresh_doms(True)

                cls.stat_refresh_count -= 1
                if cls.stat_refresh_count <= 0:
                   cls.stat_refresh_count = cls.stat_refresh_rate
                   # fetch stats only if home tab is shown
                   if (cls.notebook.getTabPos() == 0):
                       cls.notebook.showSummaryTab()

                if cls.skipcount:
                    cls.skipcount -= 1
                    return True

                #Coordinator.stateRefresh()
            except Exception ,e:
                #print "Exception in callback...ignoring ", e
                #print_stack()
                pass
        finally:
            cls.fromUserAction = True
            cls.stateRefresh()
        return True


    @classmethod
    def handle_save_dom(cls, dom):
        cls.notebook.removeTab(dom)
        
    @classmethod
    def handle_missing_dom(cls, managed_node, dom_name):
        cls.notebook.removeTabUsingName(managed_node,dom_name)

    @classmethod
    def handle_remove_dom(cls, dom):
        cls.notebook.removeTab(dom)

    @classmethod
    def handle_shutdown_dom(cls, dom):
        cls.notebook.removeTab(dom)
        
    @classmethod
    def handle_existing_dom(cls, dom):
        """ Handle refresh of existing dom"""
        # allow notebook to potentially clean up
        cls.notebook.refresh_tab(dom)

    @classmethod
    def handle_kill_dom(cls, dom):
        cls.notebook.removeTab(dom)
        

    # TBD : make this better. currently quite intermingled.
    @classmethod
    def translate_mode(cls, mode, node):
        node_type = None
        if mode == SummaryTab.NODE_SUMMARY:
            node_type = LeftNav.DOMAIN
        elif isinstance(node, ManagedNode):
            node_type = LeftNav.MANAGED_NODE
        elif isinstance(node, ServerGroup):
            node_type =  LeftNav.SERVER_POOL
        elif isinstance(node, VM):
            node_type = LeftNav.DOMAIN
            
##         if mode == SummaryTab.POOL_SUMMARY:
##             node_type = LeftNav.MANAGED_NODE
##         elif mode == SummaryTab.NODE_SUMMARY:
##             node_type = LeftNav.DOMAIN
        return node_type

    # only affect the popup 
    @classmethod
    def popup_stateRefresh(cls, path=None, selection_widget=None):
        if cls.nav == None : return

        if path:
            (name, node_type, managed_node, group, provider_id, obj_id) = cls.get_selection(path)
        else:
            (name, node_type, managed_node, group, provider_id, obj_id) = cls.get_selection()

        if node_type == LeftNav.IMAGE :
            provision_menu_item = wtree.get_widget("image_popup_provision")
            if provision_menu_item :
                if name and name[0] == "_":
                    provision_menu_item.set_sensitive(False)
                else:
                    provision_menu_item.set_sensitive(True)
                
        
        pausepopup = wtree.get_widget("Popup_pause")
        remove = ("PopupRemove", "delete")
        if node_type == LeftNav.MANAGED_NODE or node_type == LeftNav.DOMAIN:
            edit_cfg  = True
        else:
            edit_cfg = False

        for widget in ("PopupSettings",
                       "Popup_edit_config_file"):
            if wtree.get_widget(widget) is not None:
                wtree.get_widget(widget).set_sensitive(edit_cfg)


        restore = node_type == LeftNav.MANAGED_NODE

        for action in ("restore",):
            wtree.get_widget("Popup_" + action).set_sensitive(restore)

        if node_type != LeftNav.DOMAIN or \
           (node_type == LeftNav.DOMAIN and  managed_node.isDom0(name)):

            for action in ("start", "pause", "reboot", "shutdown", "kill",
                           "snapshot", "show_console", "migrate"):
                wtree.get_widget("Popup_" + action).set_sensitive(False)

            pausepopup.set_sensitive(False)
            
            for widget in remove:
                wtree.get_widget(widget).set_sensitive(False)

            return
        
        elif node_type == LeftNav.DOMAIN :
            dom_is_resident = managed_node.is_resident(name)

            for widget in ("Popup_start",):
                wtree.get_widget(widget)\
                                          .set_sensitive(not dom_is_resident)

            for action in ("pause", "reboot", "shutdown", "kill", "snapshot",
                           "show_console", "migrate"):
                wtree.get_widget("Popup_" + action)\
                                          .set_sensitive(dom_is_resident)
            isauto = False
            dom = managed_node.get_dom(name)

            for widget in remove:
                if isauto or dom_is_resident:
                    wtree.get_widget(widget).set_sensitive(False)
                else:
                    wtree.get_widget(widget).set_sensitive(True)
            

            if dom_is_resident:
                state = dom.get_state()
            else:
                state = None

            cls.fromUserAction = False
            if state:
                pausepopup.set_sensitive(True)

                if (state == VM.PAUSED):
                    for widget in (pausepopup.child, ):
                        widget.set_label("Resume")
                else:
                    for widget in (pausepopup.child,):
                        widget.set_label("Pause")
            else:
                for widget in (pausepopup.child,):
                    widget.set_sensitive(False)
            cls.fromUserAction = True


    @classmethod
    def stateRefresh(cls, path=None,selection_widget=None):
        """Refreshes UI elements based on current dom selection"""
        if cls.nav == None: return

        (name, node_type, managed_node, group, provider_id, obj_id) = cls.get_selection()

        if node_type is None:
            return

        if node_type == LeftNav.IMAGE :
            provision_menu_item = wtree.get_widget("image_popup_provision")
            if provision_menu_item :
                if name and name[0] == "_":
                    provision_menu_item.set_sensitive(False)
                else:
                    provision_menu_item.set_sensitive(True)
            else:
                print "Menu not found"


        pausebutton = wtree.get_widget("pausebutton")
        pausemenu  = wtree.get_widget("menu_pause")

        remove = ("MenuRemove", "delete_domain")

        if node_type == LeftNav.DOMAIN:
            edit_cfg  = True
        else:
            edit_cfg = False
            
        for widget in ("MenuSettings",
                       "Menu_edit_config_file"
                       ):
            if wtree.get_widget(widget) is not None:
                wtree.get_widget(widget).set_sensitive(edit_cfg)


        
        restore = node_type == LeftNav.MANAGED_NODE
        for action in ("restore",):
            wtree.get_widget(action + "button").set_sensitive(restore)
            wtree.get_widget("menu_" + action).set_sensitive(restore)
            #wtree.get_widget("Popup_" + action).set_sensitive(restore)

        if node_type != LeftNav.DOMAIN or \
           (node_type == LeftNav.DOMAIN and  managed_node.isDom0(name)):

            for action in ("start", "pause", "reboot", "shutdown", "kill",
                           "snapshot", "show_console", "migrate"):
                wtree.get_widget(action + "button").set_sensitive(False)
                wtree.get_widget("menu_" + action).set_sensitive(False)
             #   wtree.get_widget("Popup_" + action).set_sensitive(False)

            appliance_menu_item.hide()
            cls.fromUserAction = False
            pausebutton.set_active(False)
            cls.fromUserAction = True

            pausemenu.set_sensitive(False)
            #pausepopup.set_sensitive(False)

            for widget in remove:
                wtree.get_widget(widget).set_sensitive(False)

            return
        elif node_type == LeftNav.DOMAIN :
            dom_is_resident = managed_node.is_resident(name)


            for widget in ("startbutton", "menu_start"):
                wtree.get_widget(widget)\
                                          .set_sensitive(not dom_is_resident)

            for action in ("pause", "reboot", "shutdown", "kill", "snapshot",
                           "show_console", "migrate"):
                wtree.get_widget(action + "button")\
                                        .set_sensitive(dom_is_resident)
                wtree.get_widget("menu_" + action)\
                                         .set_sensitive(dom_is_resident)
               # wtree.get_widget("Popup_" + action)\
               #                           .set_sensitive(dom_is_resident)

            isauto = False

            dom = managed_node.get_dom(name)

            # appliance menu item adjustments
            vm_name = name
            provider_id = None
            submenu = None
            if managed_node is not None and vm_name:
                vm = managed_node.get_dom(vm_name)
                if vm and vm.is_resident() and vm.get_config():
                    config = vm.get_config()
                    provider_id = config["provider_id"]

            if provider_id:
                submenu = appliance_menu_map.get(provider_id)

            if submenu:
                #parent = submenu.get_attach_widget()
                #if parent:
                #    submenu.detach()
                #if appliance_menu_item.get_submenu():
                #    appliance_menu_item.remove_submenu()
                appliance_menu_item.set_submenu(submenu)
                appliance_menu_item.show()
            else:
                appliance_menu_item.hide()


            for widget in remove:
                if isauto or dom_is_resident:
                    wtree.get_widget(widget).set_sensitive(False)
                else:
                    wtree.get_widget(widget).set_sensitive(True)
            

            if dom_is_resident:
                state = dom.get_state()
            else:
                state = None

            cls.fromUserAction = False
            if state:
                pausemenu.set_sensitive(True)
                #pausepopup.set_sensitive(True)

                if (state == VM.PAUSED):
                    pausebutton.set_active(True)
                    cls.notebook.pausedTab(dom, True)
                    
                    for widget in (pausebutton, pausemenu.child,
                                   ):
                        widget.set_label("Resume")
                else:
                    pausebutton.set_active(False)
                    cls.notebook.pausedTab(dom, False)
                    
                    for widget in (pausebutton, pausemenu.child,
                                   ):
                        widget.set_label("Pause")
            else:
                pausebutton.set_active(False)
                for widget in (pausemenu.child,):
                    widget.set_sensitive(False)
            cls.fromUserAction = True
        

    # Track focus between summary table and left nav table
    @classmethod
    def focus_in(cls,widget, event):
        cls.last_focus_in = widget
        #cls.stateRefresh()

        
    @classmethod
    def focus_out(cls,widget, event):
        cls.last_focus_out = widget


    @classmethod
    def get_selection_type(cls, widget = None):
        path = None
        if cls.is_menu_from_popup(widget):
            path = Coordinator.get_popup_path()
            
        if cls.last_focus_in == cls.nav.left_nav_view:
            return cls.nav.get_selection_type(path)
        else:
            (name, mode,node, grp_name)=cls.notebook.summary_tab.get_selection(path)
            node_type = cls.translate_mode(mode, node)
            return node_type
        
    @classmethod
    def get_selection(cls, widget=None):
        path = None
        if cls.is_menu_from_popup(widget):
            path = Coordinator.get_popup_path()

        if cls.last_focus_in == cls.nav.left_nav_view:
            return cls.nav.get_selection(path)
        else:
            (name, mode,node, grp_name)=cls.notebook.summary_tab.get_selection(path)
            node_type = cls.translate_mode(mode, node)
            return (name, node_type, node, grp_name, None, None)
        
    @classmethod
    def get_managed_node(cls, widget = None):
        path = None
        if cls.is_menu_from_popup(widget):
            path = Coordinator.get_popup_path()

        if cls.last_focus_in == cls.nav.left_nav_view:
            return cls.nav.get_managed_node(path)
        else:
            (name, mode,managed_node, grp_name)=cls.notebook.summary_tab.get_selection(path)
            return managed_node


class NoteBook:
    """This class manages the gtk.NoteBook"""

    
    def __init__(self, left_nav):
        self.notebook = left_nav.wtree.get_widget("MainNotebook")
        self.left_nav = left_nav
        self.summary_tab = SummaryTab(wtree, left_nav)
        self.info_tab = InfoTab(wtree, left_nav)
        
        self.nbooklist = [0,0]
        self.terms = {}
        
        # add handlers : connecting through glade not working.
        self.notebook.connect("switch_page", 
                              cb_wrapper,self.on_notebook_switch_page)

    def _getDomToken(self, managed_node,dom_name):
        if managed_node is None or dom_name is None:
            return None
        else:
            return managed_node.hostname + ","  + dom_name


    def __getDomToken(self, dom):
        """ std way of generating unique id for a given dom"""
        if dom is None:
            #print "ERROR : getDomToken :dom is None"
            return None
        if dom.node is None :
            #print "ERROR : getDomToken :dom.node is None"
            return None
        return self._getDomToken(dom.node,dom.name)


    def showDomTab(self,managed_node, dom_name):
        #if self.getTabPos()== 1: 
        self.showInfoTab()


    def showInfoTab(self,widget=None,dom=None):
        if self.notebook.get_current_page() == 1:
            self.info_tab.refresh()
        else:
            self.notebook.set_current_page(1)
        

    def showSummaryTab(self, widget=None, managed_node=None):
        if self.notebook.get_current_page() == 0:
            self.summary_tab.refresh()
        else:
            self.notebook.set_current_page(0)
            
    def showTab(self, dom):
        """Displays the tab for the requested Dom or Dom ID"""
        dom_token = self.__getDomToken(dom)
        
        if dom_token in self.terms.keys():
            term_tab = self.terms.get(dom_token)
            if term_tab is not None and term_tab.child_died():
                self.__removeTab(dom_token)
                self.__addTab(dom)
                self.pausedTab(dom, False)
            else:
                self.notebook.set_current_page(self.nbooklist.index(dom_token))
            
        else:
            self.__addTab(dom)
            self.pausedTab(dom, False)

    def removeTabUsingName(self, managed_node, dom_name):
        dom_token = self._getDomToken(managed_node,dom_name)
        if dom_token:
            self.__removeTab(dom_token)

    def removeTab(self, dom):
        dom_token = self.__getDomToken(dom)
        if dom_token is not None:
            self.__removeTab(dom_token)

    def __removeTab(self, dom_token):
        """Removes the tab for the requested Dom ID"""
        
        if dom_token in self.terms.keys():
            del self.terms[dom_token]
            self.notebook.remove_page(self.nbooklist.index(dom_token))
            self.nbooklist.remove(dom_token)


    def getTabPos(self):
        return self.notebook.get_current_page()

    def pausedTab(self, dom, state):
        """Set the sensitive state of the contents of a tab specified by
        the requested Dom or Dom ID"""

        dom_token = self.__getDomToken(dom)
        
        if dom_token in self.terms.keys():
            term_tab = self.terms[dom_token]
            term_tab.showPaused(state)

    def __addTab(self, dom):
        """Adds a console tab to the notebook for the specified Dom"""

        # assume that dom is only passed.
        #if not isinstance(dom, Dom):
        #    return

        dom_token = self.__getDomToken(dom)
        if dom_token:
            term_tab = TerminalTab(self, dom, dom_token)
            self.terms[dom_token] = term_tab
            self.nbooklist.append(dom_token)

        
    def closeTab(self, widget, dom_token):
        """Handles the request to close a notebook tab"""
        self.__removeTab(dom_token)


    # TODO : add the tab at the same position as itwas.
    def refresh_tab(self, dom):
        """ If a tab for the same dom with old id exists, clean it up"""
        
        if dom:
            dom_token = self.__getDomToken(dom)
            if dom_token in self.terms.keys():
                tab = self.terms[dom_token]
                if tab.dom_id != dom.id:
                    self.__removeTab(dom_token)
                    self.__addTab(dom)
                

    #### NOTE THIS IS NOT CALLED FROM ANYWHERE.
    #### MAY BE RETIRED (NOT CUTOVER FOR MULTINODE)
    def cleanup(self):
        """Goes through the list of notebook tabs and checks if there is a
        corresponding Dom and what it's state is, in order to cleanup tabs
        that no longer should be displayed"""

        changes = 0

        
        for dom_token in self.terms.keys():
            try:
                dom = self.terms[dom_token]
                dom.refresh()
            except NodeException:
                self.__removeTab(dom_token)
                changes += 1
                continue
            #except Exception, e:
            #    print 'domid: ',domid
            #    continue

        if changes:
            # create new tab if required (after reboot)
            self.left_nav.domselected()

            
    def on_notebook_switch_page(self, widget, page, page_no):
        """if the user switched to info tab, populate with the
        dom information """
        #print page_no, page_no.__class__
        if page_no == 1:
            self.info_tab.refresh()
        else:
            self.info_tab.set_default_title()
        if page_no == 0:
            self.summary_tab.refresh()
        else:
            self.summary_tab.set_default_title()

        return True



class TerminalTab:
    """ Class represents terminal tab for a dom """

    def __init__(self, notebook, dom, dom_token):

        self.notebook = notebook
        
        
        self.term = vte.Terminal()
        self.term.set_scrollback_lines(1000)
        
        self.savedTerm = None

        #self.dom = dom
        managed_node = dom.node
        self.host_name = managed_node.hostname
        self.child_pid = None
        self.dom_name = dom.name
        self.dom_token = dom_token
        self.dom_id = dom.id
        if dom.is_graphical_console():
            vnc_port = dom.get_vnc_port()
            vnc_display = str(vnc_port)

            
            vncviewer = client_config.get(utils.XMConfig.CLIENT_CONFIG,
                                          prop_vncviewer)
            local_vncviewer = client_config.get(utils.XMConfig.CLIENT_CONFIG,
                                                prop_local_vncviewer)

            vncviewer_opt_str = client_config.get(utils.XMConfig.CLIENT_CONFIG,
                                                  prop_vncviewer_options)

            vncviewer_via_tunnel = client_config.get(utils.XMConfig.CLIENT_CONFIG,
                                                     prop_vncviewer_via_tunnel)

            # get options from config file so that they can be overidden on 
            # per vm bases.
            d_config=dom.get_config()
            if d_config:
                if d_config.get(prop_local_vncviewer) is not None:
                    local_vncviewer=d_config.get(prop_local_vncviewer)
                    print "local_vncviewer from vm config ", local_vncviewer
                if d_config.get(prop_vncviewer_options) is not None:
                    vncviewer_opt_str=d_config.get(prop_vncviewer_options)
                    print "vncviewer opt_str from vm config ", vncviewer_opt_str
                if d_config.get(prop_vncviewer_via_tunnel) is not None:
                    vncviewer_via_tunnel = d_config.get(prop_vncviewer_via_tunnel)
                    print "vncviewer via_tunnel from vm config ", vncviewer_via_tunnel
            else:
                print "No vm config associated with VM, will use default settings"

            
            # To use local vncviewer or use it via ssh
            if local_vncviewer is None:
                local_vncviewer = True
            else:
                local_vncviewer=eval(str(local_vncviewer))

            
            if vncviewer_via_tunnel is None:
                vncviewer_via_tunnel = True
            else:
                vncviewer_via_tunnel=eval(str(vncviewer_via_tunnel))
                
            if vncviewer is None:
                vncviewer = "vncviewer"
            
            #if vncviewer_opt:
            #    vncviewer = vncviewer + " " + vncviewer_opt
            if vncviewer_opt_str :
               vncviewer_opt = vncviewer_opt_str.strip().split()
            else:
               vncviewer_opt = []

            print "vncviewer is ", vncviewer, vncviewer_opt

            if not managed_node.is_remote():
                # localhost management, use vncviewer directly
                params = [vncviewer] + vncviewer_opt + [ ":"+vnc_display]
                pprint.pprint(params)
                self.child_pid =self.term.fork_command(vncviewer,
                                                       params)

            else:
                # use local vncviewer 
                if local_vncviewer:
                    env_array = []
                    if vncviewer_via_tunnel: # use it via tunnel
                        gw=managed_node.username+ "@" + managed_node.hostname 
                        env_array = ["""VNC_VIA_CMD=/usr/bin/ssh -p """ + \
                                         str(managed_node.ssh_port) + \
                                     """ -f -L "%L":"%H":"%R" "%G" sleep 20""" ]
                        #env_array = ["""VNC_VIA_CMD=/usr/bin/ssh -p %s -f -L "$L":"$H":"$R" "$G" sleep 20""" %  str(managed_node.ssh_port) ] 
                        params = [vncviewer] + vncviewer_opt + \
                            [ "-via", gw, "127.0.0.1" + ":"+vnc_display]
                    else:
                        params = [vncviewer] + vncviewer_opt + \
                            [managed_node.hostname+ ":"+vnc_display]

                    pprint.pprint(params)
                    pprint.pprint(env_array)
                    self.child_pid =self.term.fork_command("vncviewer",
                                                           params,
                                                           env_array)
                else: # use ssh and use vncviewer on the managed host
                    params = ["ssh",
                              "-X",
                              "-p",
                              str(managed_node.ssh_port),
                              managed_node.username+ "@" +
                              managed_node.hostname,
                              vncviewer ] + \
                              vncviewer_opt + \
                              [ ":"+ vnc_display]

                    pprint.pprint(params)
                    self.child_pid = self.term.fork_command("ssh",
                                                            params)


        else:
            console_cmd,console_args = dom.get_console_cmd()
            if console_cmd:
                if not managed_node.is_remote():
                    pprint.pprint(console_args)
                    self.child_pid = self.term.fork_command(console_cmd,
                                                            console_args)
                else:
                    hostname = managed_node.hostname
                    if managed_node.username is not None:
                        hostname = managed_node.username + "@" + hostname
                        base_args = ["ssh", "-p", str(managed_node.ssh_port),
                                     "-t",
                                     managed_node.username+ "@" +
                                     managed_node.hostname]
                        # skip the first arg
                        if console_args and len(console_args) > 1:
                            base_args.append(console_cmd)
                            for arg in console_args[1:]:
                                base_args.append(arg)
                                
                        pprint.pprint(base_args)
                        self.child_pid = self.term.fork_command("ssh", 
                                                                base_args)


        # Add scrollbar
        self.v_scrollbar = gtk.VScrollbar()
        self.v_scrollbar.set_adjustment(self.term.get_adjustment())
        
        #self.h_scrollbar = gtk.HScrollbar()
        #self.h_scrollbar.set_adjustment(self.term.get_adjustment())

        # try adding event handlers
        #self.term.connect("commit", self.commit_callback)
        self.term.connect("child-exited", self.child_exited_callback)

        
        self.tbox = gtk.HBox()
        #self.vbox = gtk.VBox()
        #self.vbox.add(self.tbox)
        #self.vbox.add(self.h_scrollbar)
        
        self.tbox.add(self.term)
        self.tbox.add(self.v_scrollbar)
        
        self.tbox.show_all()



        self.nbox = gtk.HBox()
        self.event_box = gtk.EventBox()
        self.tab_name = gtk.Label(self.dom_name)
        self.event_box.add(self.tab_name)
        self.nbox.pack_start(self.event_box)
        self.closebutton = gtk.Button()
        self.closebutton.set_relief(gtk.RELIEF_NONE)
        self.closebutton.set_size_request(20, 17)
        self.closeimage = gtk.Image()
        self.closeimage.set_from_stock(gtk.STOCK_CLOSE,
                                       gtk.ICON_SIZE_MENU)
        self.closebutton.add(self.closeimage)
        self.closebutton.connect("clicked", self.__closeTab, self.dom_token)

        """ Some other time...
        infobutton = gtk.Button()
        infobutton.set_relief(gtk.RELIEF_NONE)
        infobutton.set_size_request(28, 28)
        info_image = gtk.Image()
        info_image.set_from_stock(gtk.STOCK_INFO,
                                  gtk.ICON_SIZE_MENU)
        infobutton.add(info_image)
        infobutton.connect("clicked", self.notebook.showInfoTab, dom)
        nbox.pack_start(infobutton)
        """
        self.nbox.pack_start(self.closebutton)
        self.tool_tip = gtk.Tooltips()

        self.tool_tip.set_tip(self.event_box, managed_node.hostname)
        self.nbox.show_all()
        
        
        # add the tab to the notebook
        # Kludge : done like this because append page requires
        # tab content (tbox etc)
        page_id = self.notebook.notebook.append_page(self.tbox, self.nbox)
        self.notebook.notebook.set_current_page(page_id)


    def child_died(self):
        return self.child_pid is None

    def child_exited_callback(self, term):
        #print "child process for term exited", threading.currentThread(), \
        #       self.host_name, self.dom_name
        self.child_pid = None
    

    # from sample
    def commit_callback(self,object, *args):
        (text, length) = args
        #Echo the text input by the user to stdout.  Note that the string's
	# length isn't always going to be right.
	if (0):
            sys.stdout.write(text)
            sys.stdout.flush()
	else:
            # Test the get_text() function.
            for line in (string.splitfields(object.get_text(False),"\n")):
                if (line.__len__() > 0):
                    print line
        # Also display it.
	object.feed(text, length)

    def __closeTab(self, widget, dom_token):
        if self.child_pid is not None:
            if self.child_pid > 0:
                os.kill(self.child_pid, signal.SIGKILL) # should we be softer ?
            self.child_pid = None
        self.notebook.closeTab(widget, dom_token)

    def showPaused(self,paused):
        """
        show paused or normal console for a running dom
        """
        
        if paused:
            if not self.savedTerm:
                self.savedTerm = self.term
                self.tbox.remove(self.term)
                self.tbox.remove(self.v_scrollbar)
                
                label = gtk.Label()
                label.set_markup('<span size="xx-large">Paused</span>')
                self.tbox.add(label)
                self.tbox.show_all()
                
        elif self.savedTerm:
            self.savedTerm = None
            self.tbox.remove(self.tbox.get_children()[0])
            self.tbox.add(self.term)
            self.tbox.add(self.v_scrollbar)

class InfoTab:
    """ Class representing information tab for current selection """
    
    def __init__(self, wtree, left_nav):
        self.left_nav = left_nav
        self.info_tree_model = gtk.TreeStore(gobject.TYPE_STRING,
                                             gobject.TYPE_STRING,
                                             gobject.TYPE_STRING,
                                             gobject.TYPE_BOOLEAN
                                             )
        self.info_text = wtree.get_widget("info_text_view")
        self.info_text_window=wtree.get_widget("info_text_view_window")

        # replace the text view the htmlviewer
        self.info_text_window.remove(self.info_text)
        self.info_text = HtmlTextView()
        self.info_text.connect("url-clicked", self.url_clicked_cb)
        self.info_text_window.add(self.info_text)
        
        self.info_tree_view = wtree.get_widget("info_tree")
        self.info_tree_view.set_model(self.info_tree_model)


        self.tab_name = wtree.get_widget("info_tree_tab_label")
        
        textrenderer = gtk.CellRendererText()
        textrenderer.set_property("weight",700)
        textrenderer.set_property("weight-set",True)
        column = gtk.TreeViewColumn("Configuration", textrenderer, text=0,
                                    weight_set=3)
        column.set_cell_data_func(textrenderer, self.display_bold)
        self.info_tree_view.append_column(column)
        
        textrenderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn("", textrenderer, text=1)
        column.set_cell_data_func(textrenderer, self.display_bold)
        self.info_tree_view.append_column(column)


        column = gtk.TreeViewColumn("", textrenderer, text=2)
        column.set_cell_data_func(textrenderer, self.display_bold)
        self.info_tree_view.append_column(column)

        self.info_tree_view.show()

    def display_bold(self, column, renderer, model, iter, extra_data=None):
        value = model.get_value(iter, 3)
        renderer.set_property("weight", 700)
        renderer.set_property("weight-set", value)
        


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

    def disable_tab(self):
        # just disable label. actual disabling does not work
        self.tab_name.set_sensitive(False)

    def enable_tab(self):
        # just disable label. actual disabling does not work
        self.tab_name.set_sensitive(True)

    def show_text_view(self):
        self.info_text.set_property("visible",True)
        self.info_text.set_wrap_mode(gtk.WRAP_WORD)
        self.info_text.set_editable(False)
        self.info_text_window.set_property("visible",True)
        self.info_tree_view.set_property("visible", False)

    def show_tree_view(self):
        self.info_text.set_property("visible",False)
        self.info_text_window.set_property("visible",False)
        self.info_tree_view.set_property("visible", True)

    def show_text(self, text):
        if text is not None:
            if text.find("<body>") == -1:
                text_buffer = gtk.TextBuffer()
                text_buffer.set_text(text)
                self.info_text.set_buffer(text_buffer)
            else:
                self.info_text.display_html(text)
                


    def display_image_info(self, image_id):
        self.show_text_view()
        text = ""
        # populate image description
        image_name=image_store.images[image_id].get_name()
        filename = image_store.images[image_id].get_image_desc() 
        text = "No description file (%s) for %s " % (filename,image_name)
        if os.path.exists(filename):
            file = local_node.node_proxy.open(filename)
            file = local_node.node_proxy.open(filename)
            lines = file.readlines()
            text = "".join(lines)
            file.close()
        self.show_text(text)

    def display_image_store_info(self):
        self.show_text_view()
        text = """<body>
            <span style=\"font-size: 200%; font-family: serif; color:blue;text-align: 
            center;background-color:lightgray\">
            The Image Store
            </span>
            <br/>
            <span style=\"font-size: 125%; font-family: serif; 
            color:#0000FF;text-align: left\">
            Store Location:
            </span>"""
        text = text + image_store.get_store_location()
        text = text + """<br/>
            <span style=\"font-size: 125%; font-family: serif;color:#0000FF;text-align: left\">
            Available Image Groups:
            </span>
            <ol >
            """
        groups = image_store.get_image_groups()
        for k,img in groups.iteritems():  
            text = text + "<li>" + img.get_name() + "</li>" + "\n"
        footer = '</ol></body>'
        text = text + footer
        self.show_text(text)

    def display_image_group_info(self, image_group_id):
        self.show_text_view()

        text = """<body>
        <span style=\"font-size: 200%; font-family: serif; color:blue;text-align: 
        center;background-color:lightgray\">""" +\
        image_store.get_image_group(image_group_id).get_name() + \
        """
        </span>
        <br/>
        <span style=\"font-size: 125%; font-family: serif; 
        color:#0000FF;text-align: left\">
        Store Location:
        </span>"""
        text = text + image_store.get_store_location()
        text = text + """<br/>
        <span style=\"font-size: 125%; font-family: serif;color:#0000FF;text-align: left\">
        Available Images:
        </span>
        <ol >
        """
        images = image_store.get_image_group(image_group_id).get_images()
        for k,img in images.iteritems():  
            text = text + "<li>" + img.get_name() + "</li>" + "\n"
        footer = '</ol></body>'
        text = text + footer
        self.show_text(text)        


    # TODO : Take this out in to VNodeUIHelper so integrators can add
    # their own categories and information.
    # For now use the Platform category to add platform specific information.
    def display_node_info(self, managed_node):
        self.show_tree_view()
        self.info_tree_model.clear()
        model = self.info_tree_model
        if managed_node is None:
            return

        env_iter  = model.append(None,[display_tab_platform_info,"", "",True])
        populateTreeWithDictInfo(model, env_iter, managed_node.get_platform_info(),managed_node.get_platform_info_display_names())

        env_iter  = self.info_tree_model.append(None,[display_tab_os_info,"", "",True])
        populateTreeWithDictInfo(model,env_iter,managed_node.get_os_info(), managed_node.get_os_info_display_names())


        env_iter  = model.append(None,[display_tab_cpu_info,"", "",True])
        populateTreeWithDictInfo(model, env_iter,managed_node.get_cpu_info(), managed_node.get_cpu_info_display_names())

        env_iter  = model.append(None,[display_tab_memory_info,"", "",True])
        populateTreeWithDictInfo(model, env_iter,managed_node.get_memory_info(), managed_node.get_memory_info_display_names())

        env_iter  = model.append(None,[display_tab_disk_info, "", "", True])
        populateTreeWithListInfo(model, env_iter,managed_node.get_disk_info(),managed_node.get_disk_info_display_names())

        env_iter  = model.append(None,[display_tab_network_info,"", "",True])
        populateTreeWithListInfo(model, env_iter, managed_node.get_network_info(),managed_node.get_network_info_display_names())

        
        self.info_tree_view.expand_all()
        return

    def display_vm_info(self, vm):
        self.show_tree_view()
        self.info_tree_model.clear()
        # self.tab_name.set_text("Information " + "\n" + name)
        if not vm:
            return 
        platform = vm.get_platform()
        ui_helper = registry.get_ui_helper(platform)
        vm_info_helper = ui_helper.get_vm_info_helper()
        if vm_info_helper == None:
            vm_info_helper = VMInfoHelper()

        vm_info_helper.display_vm_info(self.info_tree_view, vm)
        self.info_tree_view.expand_all()
            
    def refresh(self):
        (name, node_type, managed_node, group_name, provider_id, obj_id) = self.left_nav.get_selection()

        if node_type == LeftNav.IMAGE:
            self.display_image_info(obj_id)
        elif node_type == LeftNav.IMAGE_STORE:
            self.display_image_store_info()
        elif node_type == LeftNav.IMAGE_GROUP:
            self.display_image_group_info(obj_id)
        elif  node_type == LeftNav.MANAGED_NODE:
            self.display_node_info(managed_node)
        elif node_type == LeftNav.DOMAIN:
            if managed_node is not None:
                vm = managed_node.get_dom(name)
                self.display_vm_info(vm)

    def set_default_title(self):
        pass
        # self.tab_name.set_text("Information")


class CustomTreeViewColumn(gtk.TreeViewColumn):
    def __init__(self,title=None,
                 renderer=None,
                 display_modes = [],
                 data_source = None,
                 data_key=None,format=None, hide_if_snapshot=False):

        if isinstance(renderer,list):
            gtk.TreeViewColumn.__init__(self, title)
            for r in renderer:
                self.pack_start(r,False)
        else:
            gtk.TreeViewColumn.__init__(self,title, renderer)
            
        self.data_source=data_source
        self.data_key = data_key
        self.format = format
        self.display_modes = display_modes
        self.hide_if_snapshot = hide_if_snapshot # this is lame
        self.set_visible(False)
        self.set_resizable(True)
        self.x_props = {}

    def set_x_porp(self, key, value):
        self.x_props[key] = value

    def get_x_prop(self,key):
        if self.x_props.has_key(key):
            return self.x_props[key]
        else:
            return None

    def get_x_props(self):
        return self.x_props

class ColumnToolTip(TreeViewTooltips):
    
    def __init__(self, tip_column):
        self.tip_col = tip_column
        # call base class init
        TreeViewTooltips.__init__(self)
        
    def get_tooltip(self, view, column, path):
        if column is self.tip_col:
            if self.tip_col and self.tip_col.data_key :
                k = self.tip_col.data_key
                if k in ("VM_SUMMARY",):
                    return '<i>Total/Running/Paused/Crashed</i>'
                elif k in ("NET_SUMMARY", "TOTAL_NET_SUMMARY"):
                    return '<i>Total/Rx/Tx</i>'
                elif k in ("VBD_SUMMARY", "TOTAL_VBD_SUMMARY"):
                    return '<i>Total/OO/RD/WR</i>'
                if k in ("VM_STORAGE",):
                    return '<i>Local/Pool Used/Pool Total</i>'
                if k in ("POOL_STORAGE",):
                    return '<i>Pool Used/Pool Total</i>'
    def XX_location(self, x, y, w, h):
        # rename me to "location" so I override the base class
        # method.  This will demonstrate being able to change
        # where the tooltip window popups, relative to the
        # pointer.

        # this will place the tooltip above and to the right
        return x + 10, y - (h + 10)

class SummaryTab:
    """ Summary information of all running doms"""
    (M_NODE,DOM_INFO,SNAPSHOT, MODE, GROUP_NAME) = range(5)
    (POOL_SUMMARY, NODE_SUMMARY, ALL) = range(3)
    (COL_ID_MEM_PCT, COL_ID_CPU_PCT,COL_ID_VM_MEM_PCT, COL_ID_VM_CPU_PCT,
     COL_ID_SERVER_NAME, COL_ID_DOM_NAME, COL_ID_CONN_STATUS,
     COL_ID_SERVER_MEM,COL_ID_VM_STORAGE, COL_ID_POOL_STORAGE) = range(10)


    # Virtual column for storage : display local/shared/(total shared @ group)
    VM_STORAGE = "VM_STORAGE"
    POOL_STORAGE = "POOL_STORAGE"


    # Can add some more information about the node.
    def __init__(self, wtree, left_nav):
        self.left_nav = left_nav

        self.statmodel = gtk.ListStore(gobject.TYPE_PYOBJECT,#managed_node
                                       gobject.TYPE_PYOBJECT,#dom
                                       gobject.TYPE_PYOBJECT,#snapshot
                                       gobject.TYPE_INT, 
                                       gobject.TYPE_STRING #group name
                                       )
        
        self.statview = wtree.get_widget("statTable")
        self.tab_name = wtree.get_widget("summaryTabLabel")

        self.statview.connect("row-activated",
                              cb_wrapper,self.handle_row_activated)

        self.statview.get_selection().connect("changed",
                                              cb_wrapper,self.handle_selection)


        # did not work. gtk 2.10 and later.
        #self.statview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH)
                                     
        # Renderers
        textrenderer = gtk.CellRendererText()
        bold_textrenderer = gtk.CellRendererText()
                
        bold_textrenderer.set_property("weight",700)
        bold_textrenderer.set_property("weight-set",True)
        #bold_textrenderer.set_property("scale",pango.SCALE_LARGE)
        

        ct_textrenderer = gtk.CellRendererText()
        ct_textrenderer.set_property("xalign", 0.5)

        rt_textrenderer = gtk.CellRendererText()
        rt_textrenderer.set_property("xalign", 1.0)

        bar_renderer = gtk.CellRendererProgress()

        pix_renderer = gtk.CellRendererPixbuf()

        column = CustomTreeViewColumn("   ", # Type
                                      [pix_renderer],
                                      [self.POOL_SUMMARY],
                                      self.SNAPSHOT, 'NODE_TYPE')
        column.set_cell_data_func(pix_renderer,
                                  self.summary_cell_data)
        self.statview.append_column(column)

        column = CustomTreeViewColumn("Name", bold_textrenderer,
                                      [self.POOL_SUMMARY],
                                      self.SNAPSHOT, 'NODE_NAME')
        column.set_cell_data_func(bold_textrenderer,
                                  self.summary_cell_data)
        self.statmodel.set_sort_func(self.COL_ID_SERVER_NAME,
                                     self.summary_cmp, column)
        #self.statmodel.set_sort_column_id(self.COL_ID_SERVER_NAME,
        #                                  gtk.SORT_ASCENDING)
        column.set_sort_column_id(self.COL_ID_SERVER_NAME)
        self.statview.append_column(column)

        column = CustomTreeViewColumn("",
                                      [pix_renderer,rt_textrenderer],
                                      [self.POOL_SUMMARY],
                                      self.SNAPSHOT, 'NODE_STATUS')
        column.set_cell_data_func(pix_renderer,
                                  self.summary_cell_data)
        self.statmodel.set_sort_func(self.COL_ID_CONN_STATUS,
                                     self.summary_cmp, column)
        column.set_sort_column_id(self.COL_ID_CONN_STATUS)
        self.statview.append_column(column)

        column = CustomTreeViewColumn("VM Summary", ct_textrenderer,
                                      [self.POOL_SUMMARY],
                                      self.SNAPSHOT,
                                      'VM_SUMMARY'
                                      )
        column.set_cell_data_func(ct_textrenderer,
                                  self.summary_cell_data)

        
        self.stat_view_tt = ColumnToolTip(column)
        self.stat_view_tt.add_view(self.statview)
        self.statview.append_column(column)

        
        column = CustomTreeViewColumn("VM CPU(%)", bar_renderer,
                                      [self.POOL_SUMMARY],
                                      self.SNAPSHOT, 'VM_TOTAL_CPU(%)',
                                      'float%')
        column.set_cell_data_func(bar_renderer,
                                  self.summary_cell_data)
        column.set_clickable(True)
        self.statmodel.set_sort_func(self.COL_ID_VM_CPU_PCT,
                                     self.summary_cmp, column)
        #self.statmodel.set_sort_column_id(self.COL_ID_VM_CPU_PCT,
        #                                  gtk.SORT_DESCENDING)
        column.set_sort_column_id(self.COL_ID_VM_CPU_PCT)

        self.statview.append_column(column)

        column = CustomTreeViewColumn("VM Mem(%)", bar_renderer,
                                      [self.POOL_SUMMARY],
                                      self.SNAPSHOT, 'VM_TOTAL_MEM(%)',
                                      'float%')
        column.set_cell_data_func(bar_renderer,
                                  self.summary_cell_data)
        column.set_clickable(True)
        self.statmodel.set_sort_func(self.COL_ID_VM_MEM_PCT,
                                     self.summary_cmp, column)
        #self.statmodel.set_sort_column_id(self.COL_ID_VM_MEM_PCT,
        #                                  gtk.SORT_ASCENDING)
        column.set_sort_column_id(self.COL_ID_VM_MEM_PCT)

        self.statview.append_column(column)


        # Shared Storage Total 
        column = CustomTreeViewColumn("Storage(GB)", ct_textrenderer,
                                      [self.POOL_SUMMARY],
                                      self.SNAPSHOT,
                                      self.POOL_STORAGE,
                                      )
        column.set_cell_data_func(ct_textrenderer,
                                  self.summary_cell_data)

        column.set_clickable(True)
        self.statmodel.set_sort_func(self.COL_ID_POOL_STORAGE,
                                     self.pool_storage_cmp, column)
        column.set_sort_column_id(self.COL_ID_POOL_STORAGE)

        self.stat_view_tt = ColumnToolTip(column)
        self.stat_view_tt.add_view(self.statview)
        
        self.statview.append_column(column)



        # Total Net summary
        column = CustomTreeViewColumn("Network ", ct_textrenderer,
                                      [self.POOL_SUMMARY],
                                      self.SNAPSHOT,
                                      'TOTAL_NET_SUMMARY'
                                      )
        column.set_cell_data_func(ct_textrenderer,
                                  self.summary_cell_data)

        
        self.stat_view_tt = ColumnToolTip(column)
        self.stat_view_tt.add_view(self.statview)
        self.statview.append_column(column)


        # Total VBD summary
        column = CustomTreeViewColumn("I/O", ct_textrenderer,
                                      [self.POOL_SUMMARY],
                                      self.SNAPSHOT,
                                      'TOTAL_VBD_SUMMARY'
                                      )
        column.set_cell_data_func(ct_textrenderer,
                                  self.summary_cell_data)

        
        self.stat_view_tt = ColumnToolTip(column)
        self.stat_view_tt.add_view(self.statview)
        self.statview.append_column(column)




        

##         column = CustomTreeViewColumn("Total VMs", textrenderer,
##                                       [self.POOL_SUMMARY],
##                                       self.SNAPSHOT, 'TOTAL_VMS')
##         column.set_cell_data_func(textrenderer,
##                                   self.summary_cell_data)
##         self.statview.append_column(column)

##         column = CustomTreeViewColumn("Running VMs", textrenderer,
##                                       [self.POOL_SUMMARY],
##                                       self.SNAPSHOT, 'RUNNING_VMs')
##         column.set_cell_data_func(textrenderer,
##                                   self.summary_cell_data)
##         self.statview.append_column(column)

##         column = CustomTreeViewColumn("Paused VMs", textrenderer,
##                                       [self.POOL_SUMMARY],
##                                       self.SNAPSHOT, 'PAUSED_VMs')
##         column.set_cell_data_func(textrenderer,
##                                   self.summary_cell_data)
##         self.statview.append_column(column)


##         column = CustomTreeViewColumn("Crashed VMs", textrenderer,
##                                       [self.POOL_SUMMARY],
##                                       self.SNAPSHOT, 'CRASHED_VMs')
##         column.set_cell_data_func(textrenderer,
##                                   self.summary_cell_data)
##         self.statview.append_column(column)


        column = CustomTreeViewColumn("Server CPU(s)", textrenderer,
                                      [self.POOL_SUMMARY],
                                      self.SNAPSHOT, 'SERVER_CPUs')
        column.set_cell_data_func(textrenderer,
                                  self.summary_cell_data)
        self.statview.append_column(column)


        
        column = CustomTreeViewColumn("Server Mem", rt_textrenderer,
                                      [self.POOL_SUMMARY],
                                      self.SNAPSHOT, 'SERVER_MEM')
        column.set_cell_data_func(rt_textrenderer,
                                  self.summary_cell_data)

        column.set_clickable(True)
        self.statmodel.set_sort_func(self.COL_ID_SERVER_MEM,
                                     self.summary_cmp, column)
        #self.statmodel.set_sort_column_id(self.COL_ID_SERVER_MEM,
        #                                  gtk.SORT_ASCENDING)
        column.set_sort_column_id(self.COL_ID_SERVER_MEM)



        self.statview.append_column(column)

        column = CustomTreeViewColumn("Version", textrenderer,
                                      [self.POOL_SUMMARY],
                                      self.SNAPSHOT, 'VER')
        column.set_cell_data_func(textrenderer,
                                  self.summary_cell_data)
        self.statview.append_column(column)


        column = CustomTreeViewColumn("Id", textrenderer,
                                      [self.NODE_SUMMARY],
                                      self.DOM_INFO, 'domid')
        column.set_cell_data_func(textrenderer,
                                  self.summary_cell_data)
        self.statview.append_column(column)

        column = CustomTreeViewColumn("Name", bold_textrenderer,
                                      [self.NODE_SUMMARY],
                                      self.DOM_INFO, 'name')
        column.set_cell_data_func(bold_textrenderer,
                                  self.summary_cell_data)
        self.statmodel.set_sort_func(self.COL_ID_DOM_NAME,
                                     self.summary_cmp, column)
        #self.statmodel.set_sort_column_id(self.COL_ID_DOM_NAME,
        #                                  gtk.SORT_ASCENDING)
        column.set_sort_column_id(self.COL_ID_DOM_NAME)
        self.statview.append_column(column)

        column = CustomTreeViewColumn("State", textrenderer,
                                      [self.NODE_SUMMARY],
                                      self.DOM_INFO, 'state')
        column.set_cell_data_func(textrenderer,
                                  self.summary_cell_data)
        self.statview.append_column(column)


        column = CustomTreeViewColumn("CPU Time(sec)", rt_textrenderer,
                                      [self.NODE_SUMMARY],
                                      self.DOM_INFO, 'cpu_time','float', True)
        column.set_cell_data_func(rt_textrenderer,
                                  self.summary_cell_data)
        self.statview.append_column(column)

        column = CustomTreeViewColumn("Memory", rt_textrenderer,
                                      [self.NODE_SUMMARY],
                                      self.DOM_INFO, 'memory', 'float',True)
        column.set_cell_data_func(rt_textrenderer,
                                  self.summary_cell_data)
        self.statview.append_column(column)



        column = CustomTreeViewColumn("CPU (%)", bar_renderer,
                                      [self.NODE_SUMMARY],
                                      self.SNAPSHOT, 'CPU(%)','float%')
        column.set_cell_data_func(bar_renderer,
                                  self.summary_cell_data)
        column.set_clickable(True)
        #column.connect("clicked",self.col_clicked)
        self.statmodel.set_sort_func(self.COL_ID_CPU_PCT,
                                     self.summary_cmp, column)
        #self.statmodel.set_sort_column_id(self.COL_ID_CPU_PCT,
        #                                  gtk.SORT_ASCENDING)
        column.set_sort_column_id(self.COL_ID_CPU_PCT)
        self.statview.append_column(column)


        column = CustomTreeViewColumn("MEM (%)", bar_renderer,
                                      [self.NODE_SUMMARY],
                                      self.SNAPSHOT, 'MEM(%)','float%')
        column.set_clickable(True)
        self.statmodel.set_sort_func(self.COL_ID_MEM_PCT,
                                     self.summary_cmp, column)
        #self.statmodel.set_sort_column_id(self.COL_ID_MEM_PCT,
        #                                  gtk.SORT_ASCENDING)
        column.set_sort_column_id(self.COL_ID_MEM_PCT)
        #column.connect("clicked",self.col_clicked)
        column.set_cell_data_func(bar_renderer,
                                  self.summary_cell_data)
        self.statview.append_column(column)


        column = CustomTreeViewColumn("Storage(GB)", ct_textrenderer,
                                      [self.NODE_SUMMARY],
                                      self.SNAPSHOT,
                                      self.VM_STORAGE
                                      )
        column.set_cell_data_func(ct_textrenderer,
                                  self.summary_cell_data)

        column.set_clickable(True)
        self.statmodel.set_sort_func(self.COL_ID_VM_STORAGE,
                                     self.storage_cmp, column)
        column.set_sort_column_id(self.COL_ID_VM_STORAGE)
        
        self.stat_view_tt = ColumnToolTip(column)
        self.stat_view_tt.add_view(self.statview)
        self.statview.append_column(column)




        # Net summary
        column = CustomTreeViewColumn("Network", ct_textrenderer,
                                      [self.NODE_SUMMARY],
                                      self.SNAPSHOT,
                                      'NET_SUMMARY'
                                      )
        column.set_cell_data_func(ct_textrenderer,
                                  self.summary_cell_data)

        
        self.stat_view_tt = ColumnToolTip(column)
        self.stat_view_tt.add_view(self.statview)
        self.statview.append_column(column)


        # VBD summary
        column = CustomTreeViewColumn("I/O", ct_textrenderer,
                                      [self.NODE_SUMMARY],
                                      self.SNAPSHOT,
                                      'VBD_SUMMARY'
                                      )
        column.set_cell_data_func(ct_textrenderer,
                                  self.summary_cell_data)

        
        self.stat_view_tt = ColumnToolTip(column)
        self.stat_view_tt.add_view(self.statview)
        self.statview.append_column(column)




        #dummy column for alignment.. may not be required.
        column = CustomTreeViewColumn("", textrenderer,
                                      [self.ALL],
                                      self.DOM_INFO, 'Empty')
        column.set_cell_data_func(textrenderer,
                                  self.summary_cell_data)
        self.statview.append_column(column)

        self.statview.set_model(self.statmodel)
        self.statview.show()


    def get_selection(self, path = None):
        if path is None:
            selection = self.statview.get_selection()
            (model, iter) = selection.get_selected()
        else:
            model = self.statview.get_model()
            iter = model.get_iter(path)

        if iter:
            mode = model.get_value(iter, self.MODE)
            if mode == self.POOL_SUMMARY:
                m_node = model.get_value(iter, self.M_NODE)
                if isinstance(m_node, ManagedNode):
                    name = m_node.hostname
                elif isinstance(m_node, ServerGroup):
                    name = m_node.name
            elif mode == SummaryTab.NODE_SUMMARY:
                dom_info = model.get_value(iter, self.DOM_INFO)
                name = dom_info.name
                
            node = model.get_value(iter, self.M_NODE)
            group_name = model.get_value(iter, self.GROUP_NAME)

            return (name, mode, node, group_name)
        return (None, None, None, None)

    def handle_selection(self, widget = None):
        Coordinator.stateRefresh(widget)

    def handle_row_activated(self,treeview,path,column):
        # need to fig out if we are in server pool or at a managed node.
        selection = treeview.get_selection()
        (model, iter) = selection.get_selected()
        if iter:
            mode = model.get_value(iter, self.MODE)
            name = None
            if mode == self.POOL_SUMMARY:
                m_node = model.get_value(iter, self.M_NODE)
                if isinstance(m_node, ServerGroup):
                    name = m_node.name
                    type = left_nav.SERVER_POOL
                else:
                    name = m_node.hostname
                    type = left_nav.MANAGED_NODE
                    
                left_nav.set_selection(name,
                                       type,
                                       "row-activated")
            else:
                dom_info = model.get_value(iter, self.DOM_INFO)
                if not dom_info.isDom0():
                    name = dom_info.name
                    left_nav.set_selection(name,
                                       left_nav.DOMAIN,
                                       "row-activated")

    def disable_tab(self):
        self.tab_name.set_sensitive(False)

    def enable_tab(self):
        self.tab_name.set_sensitive(True)


    def storage_cmp(self, model, iter1, iter2, column=None):
        #print "storage cmp called"
        try:
            (pos, key, format) = (column.data_source,
                                  column.data_key,
                                  column.format)
            s1 = model.get_value(iter1, pos)
            s2 = model.get_value(iter2, pos)
            
            v1 = None
            v2 = None
            if s1:
                v1 = s1.get(VM_TOTAL_STORAGE)
            if s2:
                v2 = s2.get(VM_TOTAL_STORAGE)
                
        except:
            print traceback.print_exc()
            raise

        #print "comparing ", v1, v2
        if v1 < v2:
            return -1
        elif v1 == v2:
            return 0
        else:
            return 1

    def pool_storage_cmp(self, model, iter1, iter2, column=None):
        #print "storage cmp called"
        try:
            (pos, key, format) = (column.data_source,
                                  column.data_key,
                                  column.format)
            s1 = model.get_value(iter1, pos)
            s2 = model.get_value(iter2, pos)
            
            v1 = None
            v2 = None
            if s1:
                v1 = s1.get(VM_SHARED_STORAGE)
            if s2:
                v2 = s2.get(VM_SHARED_STORAGE)
                
        except:
            print traceback.print_exc()
            raise

        #print "comparing ", v1, v2
        if v1 < v2:
            return -1
        elif v1 == v2:
            return 0
        else:
            return 1




    def summary_cmp(self, model, iter1, iter2, column=None):
        #print "summary cmp called"
        try:
            v1 = self.get_text(model, column, iter1)
            v2 = self.get_text(model, column, iter2)
        except:
            print traceback.print_exc()
            raise
            
        if v1 < v2:
            return -1
        elif v1 == v2:
            return 0
        else:
            return 1
        

    def col_clicked(self, column):
        print "Column clicked"

        


    # Call back function to get the data and show it.
    def summary_cell_data(self,column,cell,model,iter):
        key = column.data_key
        text = self.get_text(model, column, iter, cell)
        r = None    
        renderers = column.get_cell_renderers()
        num_r = len(renderers)

        if key == "NODE_STATUS" and num_r > 1: # special handling for the node status column
            text_r = renderers[1]
            pix_r  = renderers[0]

            if text.find("/") < 0 :
                text_r.set_property("text","")
                pix_r.set_property("pixbuf", self.get_connection_pb(text))

            else:
                text_r.set_property("text", text)
                pix_r.set_property("pixbuf", dialogs.connected_pb)
        else:
            for r in renderers:
                if r is not None and isinstance(r, gtk.CellRendererProgress):
                    r.set_property('value',0)
                    if text is not None and text is not '':
                        v=float(text)
                        if v > 100.0:
                            #print "clipping ", v, " to 100.0 for % bar"
                            v = 100.0
                        r.set_property('value',v)

                if text == None or text == '':
                    text='N/A'

                if r is not None:
                    if isinstance(r, gtk.CellRendererPixbuf):
                        if key == "NODE_TYPE":
                            pb = dialogs.get_node_type_pb(text, model, iter)
                        else:  # connection status
                            pb = self.get_connection_pb(text)
                        r.set_property('pixbuf', pb)
                    else:
                        r.set_property('text',text)

    def get_connection_pb(self,state):
        if state == "Connected":
            pb = dialogs.connected_pb
        else:
            pb = dialogs.disconnected_pb

        return pb
    
    def get_storage_prefix(self, k):
        prefix = ""
        return prefix
        if k == VM_SHARED_STORAGE:
            prefix = "P:"
        elif k==POOL_STORAGE_TOTAL:
            prefix = "PS:"
        elif k == VM_LOCAL_STORAGE:
            prefix = "L:"

        return prefix

    def get_text(self, model, column, iter, cell=None):
        format = None
        (pos, key, format) = (column.data_source,column.data_key,column.format)
        dp = model.get_value(iter, pos)
        text = ''
        if dp is not None:
            if pos == 1: # dom access
                text = dp[key]
            elif pos == 2: # snapshot access
                if dp.has_key(key):
                    text = dp[key]
            elif pos == 0:
                text = getattr(dp, key)


        if text is None:
            text = ''

        if key == 'Empty':
            text = ' ' # a space so N/A is not displayed
        # special handling for name
        if (key=='name' or key=='NAME') and text=='Domain-0':#uggh,hard coding
            managed_node = model.get_value(iter,0)
            text = managed_node.hostname
            
        if key=='state' or key=='STATE':
            # assume that data provider is an instance of VM
            if dp:
                text = dp.get_state_string()

        if key=='VM_SUMMARY' and dp is not None: # construct the string
            text = ''
            for k in ('TOTAL_VMs', 'RUNNING_VMs', 'PAUSED_VMs', 'CRASHED_VMs'):
                if dp.has_key(k):
                    text = text + str(dp[k])
                else:
                    text = text + '?'
                text = text + '/'
            text = text[:-1]

        if key=='NET_SUMMARY' and dp is not None: # construct the string
            text = ''
            for k in ('NETS', 'NETRX(k)',
                      'NETTX(k)'):
                if dp.has_key(k):
                    text = text + str(dp[k])
                else:
                    text = text + '?'
                text = text + '/'
            text = text[:-1]

        if key=='VBD_SUMMARY' and dp is not None: # construct the string
            text = ''
            for k in ('VBDS', 'VBD_OO',
                      'VBD_RD', 'VBD_WR'):
                if dp.has_key(k):
                    text = text + str(dp[k])
                else:
                    text = text + '?'
                text = text + '/'
            text = text[:-1]


        if key=='TOTAL_NET_SUMMARY' and dp is not None: # construct the string
            text = ''
            for k in ('VM_TOTAL_NETS', 'VM_TOTAL_NETRX(k)',
                      'VM_TOTAL_NETTX(k)'):
                if dp.has_key(k):
                    text = text + str(dp[k])
                else:
                    text = text + '?'
                text = text + '/'
            text = text[:-1]

        if key=='TOTAL_VBD_SUMMARY' and dp is not None: # construct the string
            text = ''
            for k in ('VM_TOTAL_VBDS', 'VM_TOTAL_VBD_OO',
                      'VM_TOTAL_VBD_RD', 'VM_TOTAL_VBD_WR'):
                if dp.has_key(k):
                    text = text + str(dp[k])
                else:
                    text = text + '?'
                text = text + '/'
            text = text[:-1]

        if key==self.VM_STORAGE and dp is not None: # construct the string
            text = ''
            for k in (VM_LOCAL_STORAGE, VM_SHARED_STORAGE, POOL_STORAGE_TOTAL):
                if dp.has_key(k):
                    prefix = self.get_storage_prefix(k)
                    v = "%s%6.2f" % (prefix,dp[k])
                    text = text + v
                else:
                    text = text + '?'
                text = text + '/'
            text = text[:-1]
        
        if key==self.POOL_STORAGE and dp is not None: # construct the string
            text = ''
            for k in (VM_SHARED_STORAGE, POOL_STORAGE_TOTAL):
                if dp.has_key(k):
                    prefix = self.get_storage_prefix(k)
                    v = "%s%6.2f" % (prefix, dp[k])
                    text = text + v
                else:
                    text = text + '?'
                text = text + '/'
            text = text[:-1]


        if key=='NODE_STATUS' and dp is not None:
            if dp.get("NODES_CONNECTED") is not None:
                return str(dp["NODES_CONNECTED"]) + "/" +str(dp["NODE_COUNT"])
            
        if text is not None and text != '' and format is not None:
            if format.find('float') == 0:
                text= "%12.2f" % float(text)            

        return text

    # refresh can be done smartly(in place update) to reduce flicker
    
    def refresh(self):
        """Refreshes the statistics on the home tab"""
        (name, node_type,managed_node, group_name, provider_id, obj_id)  = self.left_nav.get_selection()
        # save current selection and restore it once the refresh is done.
        path = None
        old_mode = None
        new_mode = None
        old_managed_node = None
        selection = self.statview.get_selection()
        if selection:
            (tm, ti) = selection.get_selected()
            if ti is not None:
                path = tm.get_path(ti)
                # special check to see if the view is changing
                old_mode = tm.get_value(ti, self.MODE)
                old_managed_node = tm.get_value(ti, self.M_NODE)

        self.statmodel.clear()        
        if node_type == self.left_nav.SERVER_POOL or \
               node_type == self.left_nav.DATA_CENTER:
            self._populate_pool_summary()
            new_mode = self.POOL_SUMMARY
        else:
            # old call
            self._populate_node_summary(managed_node, group_name)
            new_mode = self.NODE_SUMMARY
            
        if selection is not None and path is not None:
            if old_mode == new_mode:
                #if managed_node is old_managed_node:
                selection.select_path(path)
                


    def _populate_pool_summary(self):

        (pool_name, pool_type, pool, group_name, provider_id, obj_id) = self.left_nav.get_selection()

        if pool_type == left_nav.SERVER_POOL:
            node_list = manager.getNodeNames(pool_name)
        elif pool_type == left_nav.DATA_CENTER:
            pool_name = None
            node_list = manager.getNodeNames()
        else:
            return   

        # get the storage stats for the server pool
        pool_storage_stats = storage_manager.get_pool_stats(pool_name)
        if pool_storage_stats and pool_storage_stats.get("TOTAL"):
            pool_storage_total = pool_storage_stats.get("TOTAL")
        else:
            pool_storage_total = -1
            

        node_list.sort()
        for m_name in node_list:
            m_node = manager.getNode(m_name, pool_name)
            node_status = "Unknown"
            if m_node is None :
                continue

            if m_node.is_authenticated():
                node_status = "Connected"
            else:
                node_status = "Not Connected"

            #if m_node.is_in_error():
            #    node_status = "Error"
            
        
            if m_node is not None:
                if m_node.is_authenticated() and not m_node.is_in_error():
                    node_snapshot = None
                    dom_count = 0
                    try:
                        node_snapshot = m_node.get_metrics()
                    except Exception ,ex:
                        #print "error getting info for ", m_node.hostname, ex
                        pass
                    
                    if node_snapshot is None:
                        node_snapshot = {}
                        node_snapshot["NODE_NAME"] = m_node.hostname

                    node_snapshot["NODE_NAME"]= m_node.hostname
                    node_snapshot["NODE_STATUS"]= node_status

                    # update the snapshot to have pool total
                    if pool_storage_total >=0 :
                        node_snapshot[POOL_STORAGE_TOTAL] = pool_storage_total
                    else:
                        node_snapshot[POOL_STORAGE_TOTAL] = 0
                    
                    try:
                        dom_count = m_node.get_VM_count()
                        node_snapshot["TOTAL_VMs"] = dom_count
                    except Exception ,ex:
                        #print "error getting dom count ", m_node.hostname, ex
                        pass
                        
                else:
                    node_snapshot = {"NODE_NAME":m_node.hostname,
                                     "NODE_STATUS":node_status
                                     }
                self.adjust_columns(self.POOL_SUMMARY,
                                    len(node_snapshot.keys()) > 0)

                node_snapshot["NODE_TYPE"] = self.left_nav.MANAGED_NODE
                #print node_snapshot["NODE_NAME"], node_snapshot
                iter = self.statmodel.insert_before(None, None)
                self.statmodel.set(iter,
                                   self.M_NODE, m_node,
                                   self.DOM_INFO, None,
                                   self.SNAPSHOT, node_snapshot,
                                   self.MODE, self.POOL_SUMMARY,
                                   self.GROUP_NAME, pool_name
                                   )

        # Append the group summary if the node selection is data center
        if pool_type == left_nav.DATA_CENTER:
            group_names = manager.getGroupNames()
            for group_name in group_names:
                group = manager.getGroup(group_name)
                group_info = {}
         
                # summarize nodes within group.
                node_names = group.getNodeNames()
                group_info["NODE_COUNT"] =  len(node_names)
                group_info["NODE_TYPE"] = self.left_nav.SERVER_POOL
                connected = 0
                servers = 0
                vm_mem = 0
                vm_cpu = 0

                mem = 0
                cpu = 0
                
                vm_running = 0
                vm_paused = 0
                vm_crashed = 0
                vm_total = 0

                nets=0
                net_tx = 0
                net_rx =0

                vbds=0
                vbd_oo = 0
                vbd_rd = 0
                vbd_wr = 0
                
                vm_shared_storage = 0
                vm_local_storage = 0
                vm_total_storage = 0

                # get the storage stats for the server pool
                pool_storage_stats = storage_manager.get_pool_stats(group_name)
                if pool_storage_stats and pool_storage_stats.get("TOTAL"):
                    pool_storage_total = pool_storage_stats.get("TOTAL")
                else:
                    pool_storage_total = -1
            
                
                for node_name in node_names:
                    m_node = manager.getNode(node_name, group.name)
                    if m_node is None :
                        print "m_node is None ", node_name, pool_name
                        continue
                    
                    servers = servers + 1
                    if m_node is not None:
                        if m_node.is_authenticated() and not m_node.is_in_error():
                            node_snapshot = None
                            dom_count = 0
                            try:
                                node_snapshot = m_node.get_metrics()
                                dom_count = len(m_node.get_dom_names())-1
                            except Exception, ex:
                                #print "error getting info for ", m_node.hostname, ex
                                pass
                            
                            if node_snapshot is None:
                                continue

                            connected = connected + 1
                            # TBD : This needs to be streamlined
                            if m_node["nr_cpus"] is not None:
                                cpu +=  m_node["nr_cpus"]
                                mem +=  m_node["total_memory"]
                            else:
                                cpu +=  m_node.get_cpu_info()[key_cpu_count]
                                mem +=  m_node.get_memory_info()[key_memory_total]
                            node_snapshot["TOTAL_VMs"] = dom_count
                            vm_cpu += node_snapshot["VM_TOTAL_CPU"]
                            vm_mem += node_snapshot["VM_TOTAL_MEM"]

                            if node_snapshot.get("RUNNING_VMs") is not None:
                                vm_running += node_snapshot["RUNNING_VMs"]
                            if node_snapshot.get("PAUSED_VMs") is not None:
                                vm_paused += node_snapshot["PAUSED_VMs"]
                            if node_snapshot.get("CRASHED_VMs") is not None:
                                vm_crashed += node_snapshot["CRASHED_VMs"]
                            if node_snapshot.get("TOTAL_VMs") is not None:
                                vm_total += node_snapshot["TOTAL_VMs"]
                            if node_snapshot.get("VM_TOTAL_NETS") is not None:
                                nets += node_snapshot.get("VM_TOTAL_NETS")
                            if node_snapshot.get("VM_TOTAL_NETTX(k)") is not None:
                                net_tx += node_snapshot.get("VM_TOTAL_NETTX(k)")
                            if node_snapshot.get("VM_TOTAL_NETRX(k)") is not None:
                                net_rx += node_snapshot.get("VM_TOTAL_NETRX(k)")
                            if node_snapshot.get("VM_TOTAL_VBDS") is not None:
                                vbds += node_snapshot.get("VM_TOTAL_VBDS")
                            if node_snapshot.get("VM_TOTAL_VBD_OO") is not None:
                                vbd_oo += node_snapshot.get("VM_TOTAL_VBD_OO")
                            if node_snapshot.get("VM_TOTAL_VBD_RD") is not None:
                                vbd_rd += node_snapshot.get("VM_TOTAL_VBD_RD")
                            if node_snapshot.get("VM_TOTAL_VBD_WR") is not None:
                                vbd_wr += node_snapshot.get("VM_TOTAL_VBD_WR")
                            if node_snapshot.get(VM_SHARED_STORAGE) is not None:
                                vm_shared_storage += node_snapshot.get(VM_SHARED_STORAGE)
                            if node_snapshot.get(VM_LOCAL_STORAGE) is not None:
                                vm_local_storage += node_snapshot.get(VM_LOCAL_STORAGE)
                            if node_snapshot.get(VM_TOTAL_STORAGE) is not None:
                                vm_total_storage += node_snapshot.get(VM_TOTAL_STORAGE)

##                          else:
##                              print "skipping node ", m_node.hostname, \
##                                    m_node.is_authenticated(), \
##                                    m_node.is_in_error()
 
                                            
                # add group information
                group_info["NODE_NAME"] = group.name
                group_info["NODES_CONNECTED"] = connected
                
                # summarized stats
                group_info["SERVER_CPUs"] = cpu
                group_info["SERVER_MEM"] = str(mem) + "M"

                # VM stats
                group_info["RUNNING_VMs"] = vm_running
                group_info["PAUSED_VMs"] = vm_paused
                group_info["CRASHED_VMs"] = vm_crashed
                group_info["TOTAL_VMs"] = vm_total


                if connected > 0:
                    group_info["VM_TOTAL_CPU(%)"] = vm_cpu / cpu
                    group_info["VM_TOTAL_MEM(%)"] = (vm_mem * 100.0)/ mem
                else:
                    group_info["VM_TOTAL_CPU(%)"] = 0
                    group_info["VM_TOTAL_MEM(%)"] = 0


                group_info["VM_TOTAL_NETS"] = nets
                group_info["VM_TOTAL_NETTX(k)"] = net_tx
                group_info["VM_TOTAL_NETRX(K)"] = net_rx

                group_info["VM_TOTAL_VBDS"] = vbds
                group_info["VM_TOTAL_VBD_OO"] = vbd_oo
                group_info["VM_TOTAL_VBD_RD"] = vbd_rd
                group_info["VM_TOTAL_VBD_WR"] = vbd_wr

                group_info[VM_SHARED_STORAGE] = vm_shared_storage
                group_info[VM_LOCAL_STORAGE] = vm_local_storage
                group_info[VM_TOTAL_STORAGE] = vm_total_storage

                if pool_storage_total >= 0 :
                    group_info[POOL_STORAGE_TOTAL] = pool_storage_total
                else:
                    group_info[POOL_STORAGE_TOTAL] = 0.0

                
                #import pprint 
                #pprint.pprint(group_info)
                # Add the group summary row as
                self.adjust_columns(self.POOL_SUMMARY, True)


                iter = self.statmodel.insert_before(None, None)
                self.statmodel.set(iter,
                                   self.M_NODE, group,
                                   self.DOM_INFO, None,
                                   self.SNAPSHOT, group_info,
                                   self.MODE, self.POOL_SUMMARY,
                                   self.GROUP_NAME, None  # change this when we 
                                   )                      # support group within
                                                          # groups
                
                

    def adjust_columns(self,mode, snapshot_available):
        
        for col in self.statview.get_columns():
            show_col = (mode in col.display_modes or \
                       self.ALL in col.display_modes)
            col.set_visible(show_col)
            if not show_col:
                continue
            
            if snapshot_available : # snapshot available
                if col.data_source == self.SNAPSHOT:
                    col.set_visible(True)
                    
                if col.hide_if_snapshot==True:
                    col.set_visible(False)
                    
            else: # no snapshot
                if col.data_source == self.SNAPSHOT:
                    col.set_visible(False)
                    
                if col.hide_if_snapshot==True:
                    col.set_visible(True)



    def _populate_node_summary(self, managed_node, group_name):
        
        if managed_node is None : return
        if not managed_node.is_authenticated(): return
        if managed_node.is_in_error():
            return
        
        
        pool_storage_stats = storage_manager.get_pool_stats(group_name)
        if pool_storage_stats and pool_storage_stats.get("TOTAL"):
            pool_storage_total = pool_storage_stats.get("TOTAL")
        else:
            pool_storage_total = -1
            


        snapshot = managed_node.get_metrics()
        if snapshot is not None:
            snapshot_keys = snapshot.keys()
            snapshot_len = len(snapshot_keys)
        else:
            snapshot_keys = []
            snapshot_len = 0

        self.adjust_columns(self.NODE_SUMMARY, snapshot_len > 0)
        doms = managed_node.get_dom_names()
        doms.sort()

        for dom_name in doms:
            dom = managed_node.get_dom(dom_name)
            if dom and dom.is_resident():
                if snapshot_len > 0 and dom_name in snapshot_keys:
                    snapshot_dom = snapshot[dom_name]
                else:
                    snapshot_dom = None

                if pool_storage_total >=0 and snapshot_dom :
                    snapshot_dom[POOL_STORAGE_TOTAL] = pool_storage_total
                else:
                    if snapshot_dom:
                        snapshot_dom[POOL_STORAGE_TOTAL] = 0.0
                    
                #import pprint; pprint.pprint(snapshot_dom)
                iter = self.statmodel.insert_before(None, None)
                self.statmodel.set(iter,
                                   self.M_NODE, managed_node,
                                   self.DOM_INFO, dom,
                                   self.SNAPSHOT, snapshot_dom,
                                   self.MODE, self.NODE_SUMMARY,
                                   self.GROUP_NAME, group_name
                                       )
            


    def set_default_title(self):
        pass
        #self.tab_name.set_text("Summary")
        

class Timer:
    """This class initializes a GTK call back loop that runs one of it's
    methods on a regular basis to perform refreshes and such operations"""



    def __init__(self):
        self.timeoutid = gobject.timeout_add(2000, self.__callback)

    def __callback(self):
        """This is the callback that handles the refresh"""
        try:
            threads_enter()
            return Coordinator.handle_timer_callback()
        finally:
            threads_leave()
            pass



#
# function definitions
#
def cb_new_dom(hostname,select=True):
    try:
        threads_enter()
        left_nav.set_selection(hostname,
                               left_nav.MANAGED_NODE,
                               op="row-activated",
                               select=select)
    finally:
        threads_leave()





def cb_set_selection(node_name, node_type,op=None,select=True):
    try:
        threads_enter()
        left_nav.set_selection(node_name,
                               node_type,
                               op=op,
                               select=select)
    finally:
        threads_leave()



def validate_node_selected(widget):
    if Coordinator.get_selection_type(widget) == LeftNav.MANAGED_NODE:
        return True
    else:
        showmsg("Select a Server for this operation")
        return False


def quitProgram(*args):
    """Quit the execution of the program"""
    #print "calling shutdown"
    if manager is not None:
        manager.shutdown()
    gtk.main_quit()

def show_about(*args):
    """handler that shows the about dialog"""

    wtree.get_widget('AboutDialog').show()

def hide_about(widget, *args):
    """handler that hides the about dialog"""

    widget.hide()
    return True


def savedom(widget):
    """Take Snapshot of a running dom. (a.k.a save)"""

    (name,node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.DOMAIN:
        dom = managed_node.get_dom(name)
        snap_dir = managed_node.config.get(utils.XMConfig.PATHS,prop_snapshots_dir)
        default_ext = managed_node.config.get(utils.XMConfig.PATHS,prop_snapshot_file_ext);
        snap_file = dom.name
        if default_ext is not None:
            snap_file += default_ext
        mainwin = wtree.get_widget('MainWindow')
        if snap_dir and not managed_node.node_proxy.file_exists(snap_dir):
            utils.mkdir2(managed_node, snap_dir) 
        (res, fname) = file_selection(managed_node,
                                      "Save Snapshot", "save", snap_dir,
                                      snap_file,
                                      parentwin = mainwin)
        if res and fname:
            do_work(lambda : dom._save(fname),
                    "Save VM snapshot ",
                    lambda : cb_savedom(dom))


def cb_savedom(dom):
    try:
        threads_enter()
        Coordinator.handle_save_dom(dom)
        delayed_lef_nav_refresh()
    finally:
        threads_leave()
    
    



def restoredom(widget):
    """Restore a dom from a file."""

    if not validate_node_selected(widget):
        return
    managed_node = Coordinator.get_managed_node(widget)
    snap_dir = managed_node.config.get(utils.XMConfig.PATHS,prop_snapshots_dir)
    mainwin = wtree.get_widget('MainWindow')
    (res, fname) = file_selection(managed_node,
                                  "Restore from Snapshot","open",
                                  snap_dir,
                                  parentwin = mainwin)
    if res and fname:
        if managed_node is not None:
            do_work(lambda : managed_node.restore_dom(fname),
                    "Restore VM snapshot ",
                    lambda : cb_restoredom(managed_node))
            
def cb_restoredom(managed_node):
    try:
        threads_enter()
        managed_node.refresh()
        left_nav.refresh_doms()
    finally:
        threads_leave()
    


def rebootdom(widget):
    """Reboot the currently selected domain"""
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.DOMAIN:
        dom = managed_node.get_dom(name)
        if confirmation("Reboot " + dom.name + " on " + managed_node.hostname + "?"):
            try:
                show_wait_cursor()
                dom._reboot()
                managed_node = dom.node
                managed_node.refresh()
                delayed_lef_nav_refresh()
            finally:
                hide_wait_cursor()
            

def shutdowndom(widget):
    """shutdown the currently selected domain"""

    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.DOMAIN:
        dom = managed_node.get_dom(name)

        if confirmation("Shutdown " + dom.name+ " on " + managed_node.hostname + "?"):
            try:
                show_wait_cursor()
                dom._shutdown()
                managed_node = dom.node
                delayed_lef_nav_refresh()
            finally:
                hide_wait_cursor()

            

def startdom(widget):
    """Start the selected domain"""
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.DOMAIN:
        dom = managed_node.get_dom(name)
    else:
        return
    

    if not managed_node.is_resident(dom.name):
        try:
            try:
                show_wait_cursor()
                dom._start()
            finally:
                hide_wait_cursor()
        except Exception, e:
            traceback.print_exc()
            showmsg("Error starting " + dom.name +". "+ str(e))
            return


        managed_node = dom.node
        left_nav.refresh_doms()


def killdom(widget):
    """Kills the currently selected domain"""
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.DOMAIN:
        dom = managed_node.get_dom(name)

        if (confirmation("Kill " + dom.name + " on " + managed_node.hostname+ "?")):
            # sometime the xen destroy gives socket error after destorying vm
            # lets ignore it for now.
            try:
                show_wait_cursor()
                try:
                    dom._destroy()                
                    #left_nav.refresh()
                except (socket.error,xmlrpclib.Fault), ex:
                    print ex
                    pass
            finally:
                hide_wait_cursor()

            
            managed_node = dom.node
            delayed_lef_nav_refresh()
            Coordinator.handle_kill_dom(dom)


def delayed_lef_nav_refresh(delay=1000):
    gobject.timeout_add(delay, left_nav_refresh)
            
# can be used as one time call back 
def left_nav_refresh():
    try:
        left_nav.refresh_doms()
    except Exception, ex:
        pass
    return False


def migrate_all(widget):
    """ Migrate all running vms from the selected node to a new node.
        In later versions, the s/w would determine where to migrate them
        automatically
    """
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if managed_node is None :
        return

    need_refresh = False

    if node_type == LeftNav.MANAGED_NODE:
        node_selection_dlg.show(widget, manager, True, platform = managed_node.get_platform())
        (name, type, dest_node, group_name, live) = node_selection_dlg.get_selection()

        if dest_node is None:
            return

        if managed_node is dest_node or \
           managed_node.hostname == dest_node.hostname:
            showmsg("Error : Migration : Source and destinations are the same.")
            return

        if managed_node is not None and dest_node is not None:
            msg = ""
        if live:
            msg = "Migrate live all VMs on " + \
                  managed_node.hostname + " to " + dest_node.hostname + "?"
        else:
            msg = "Migrate all VMs on " + \
                  managed_node.hostname + " to " + dest_node.hostname + "?"

        if confirmation(msg):
            if not dest_node.is_remote():
                l  = GetLocalIPDlg()
                r = l.show(manager, dest_node, mainwin)

            ret = False
            if managed_node is not None:
                vm_list = []
                for vm in managed_node.get_doms():
                    if not vm.isDom0():
                        vm_list.append(vm)
                    

                (e, w) = managed_node.migration_checks(vm_list, dest_node, live)
                if len(e) or len(w):
                    dlg = MigrationChecksResultsDlg()
                    ret = dlg.show(e,w,mainwin)
                else:
                    ret = True
            if ret:    
                do_work(lambda : manager.migrateNode( managed_node,
                                                      dest_node, live,
                                                      force=True),
                        "Migrate all domains ",
                        lambda : cb_suc_migrate_domain(managed_node,
                                                       dest_node))
        else:
            return

    
def migratedom(widget):
    """ Migrate the currently selected VM to a Managed Node 
       selected in a list, allowing the VM to be migrated live
    """

    if not Coordinator.fromUserAction: return

    # Get the selection
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if managed_node is None :
        return
    
    vm = managed_node.get_dom(name)
    need_refresh = False

    if node_type == LeftNav.DOMAIN:
        node_selection_dlg.show(widget, manager, True, platform = vm.get_platform())
        (name, type, dest_node, group_name, live) = node_selection_dlg.get_selection()

        if dest_node is None:
            return
        
        if managed_node is dest_node or \
           managed_node.hostname == dest_node.hostname:
            showmsg("Error : Migration : Source and destinations are the same.")
            return

        if managed_node is not None and dest_node is not None:
            msg = ""
        if live:
            msg = "Migrate Live " + vm.name + " on " + \
                  managed_node.hostname + " to " + dest_node.hostname + "?"
        else:
            msg = "Migrate " + vm.name + " on " + \
                  managed_node.hostname + " to " + dest_node.hostname + "?"

        need_refresh = False
        if confirmation(msg):
            state = vm.get_state()
            migrate_doms(managed_node, [vm], dest_node, live)
            
        else:
            return
           
        #if need_refresh:
            #left_nav.refresh_doms()
            #delayed_lef_nav_refresh()



def cb_suc_migrate_domain(src_node, dest_node):
    try:
        threads_enter()
        left_nav.set_selection(dest_node.hostname,
                               left_nav.MANAGED_NODE,
                               op="row-activated")

        left_nav.set_selection(src_node.hostname,
                               left_nav.MANAGED_NODE,
                               select=False,op="row-activated")
        Coordinator.stateRefresh()
    finally:
        threads_leave()

            
def migrate_doms(src_node, vm_list, dest_node, live):
    try:
        #show_wait_cursor()
        if not dest_node.is_remote():
                l  = GetLocalIPDlg()
                r = l.show(manager, dest_node,mainwin)

        ret = False
        # do the checks.
        if src_node is not None:
            (e, w) = src_node.migration_checks(vm_list, dest_node, live)
            if len(e) or len(w):
                dlg = MigrationChecksResultsDlg()
                ret = dlg.show(e,w, mainwin)
            else:
                ret = True
            
        if ret :        
            do_work(lambda : manager.migrateDomains(src_node,
                                                    vm_list,
                                                    dest_node, live,
                                                    force=True),
                    "Migrate domain ",
                    lambda : cb_suc_migrate_domain(src_node,
                                                   dest_node))
    finally:
        #hide_wait_cursor()
        pass



## later :
##    def do_work(work, context, cb_suc, cb_fail, cb_error, synchornos = True):
    
def do_work(work, context=None,
            cb_suc=None,
            cb_error = dialogs.cb_showmsg,
            background_op = enable_background_ops):
    
    if not background_op:
        try:
            show_wait_cursor()
            try:
                try:
                    #gc.disable()
                    result = work()
                finally:
                    #gc.enable()
                    pass
                if cb_suc: cb_suc()
            except Exception , ex:
                if cb_error is not None:
                    cb_error(ex)
                else:
                    raise
        finally:
            hide_wait_cursor()
    else:
        #threads_leave()   # release the GTK lock (as called from call back)
        worker = UIWorker(work, context, cb_suc, cb_error)
        worker.start()
        #threads_enter() # re-aquire it.
            

def pausedom(widget):
    """Pause the currently selected domain"""

    # We use set_active on the pause button, which may fire
    # unnecessary pasuedom calls, to prevent this the callback from the
    # UI actually sets fromUserAction to True.
    # Note : There must be a better way of doing this. 
    if not Coordinator.fromUserAction: return

    need_refresh = False
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.DOMAIN:
        dom = managed_node.get_dom(name)
        
        state = dom.get_state()
        if state == VM.PAUSED:
            if confirmation("Resume " + dom.name + " on " + managed_node.hostname + "?"):
                try:
                    show_wait_cursor()
                    dom._unpause()
                    need_refresh = True
                finally:
                    hide_wait_cursor()


        else:
            if confirmation("Pause " + dom.name + " on " + managed_node.hostname+ "?"):
                try:
                    show_wait_cursor()
                    dom._pause()
                    need_refresh = True
                finally:
                    hide_wait_cursor()
                    

        if need_refresh:
            managed_node = dom.node
            left_nav.refresh_doms()

            Coordinator.stateRefresh()


def summary_popupmenu(widget, event):
    """Checks whether the right mouse button was clicked
       and displays a popup menu"""

    if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
        x = int(event.x)
        y = int(event.y)
        time = event.time
        pthinfo = widget.get_path_at_pos(x, y)
        if pthinfo is not None:
            path, col, cellx, celly = pthinfo
            widget.grab_focus()
            #widget.set_cursor( path, col, 0)

            #selection = widget.get_selection()
            #(model,iter) = selection.get_selected()

            Coordinator.set_popup_path(path)

            model = widget.get_model()
            iter = model.get_iter(path)
            
            if iter:
                mode = model.get_value(iter, SummaryTab.MODE)
                node = model.get_value(iter, SummaryTab.M_NODE)

            if mode == SummaryTab.POOL_SUMMARY:
                if isinstance(node, ManagedNode):
                    node_popup.popup(None, None, None,
                                     event.button,
                                     event.time)
                    Coordinator.popup_stateRefresh(node_popup)
                elif isinstance(node, ServerGroup):
                    pool_popup.popup(None, None, None,
                                     event.button,
                                     event.time)
                    Coordinator.popup_stateRefresh(pool_popup)
            if mode == SummaryTab.NODE_SUMMARY:
                dom_info = model.get_value(iter, SummaryTab.DOM_INFO)
                name = dom_info.name
                show_vm_popup(widget, event, node, name)


            return 1
            
# dynamic integration.. for now the map is in the code.
# can be externalize easily.
def do_appliance_integration():
    appliance_providers = { "rPath" : "rPathProxy",
                            "JumpBox" : "JBProxy"}
    appliance_proxy = {}
    for provider_id, a_proxy in appliance_providers.iteritems():
        try:
            code = "from convirt.core.appliance.%s.%s import %s; proxy=%s(); ops = proxy.getProxyIntegration()"  % (provider_id, a_proxy,a_proxy, a_proxy)
            exec(code)
            appliance_proxy[provider_id] = (proxy,ops)
        except Exception, ex:
            print "Skipping Application interation for " + provider_id, ex

    # take the operations and create a menu
    appliance_menu_map = {}
    for provider, (proxy, ops) in appliance_proxy.iteritems():
        provider_menu = gtk.Menu()
        for op, desc in ops:
            if op == "SEPARATOR" or desc.find("--") == 0:
                menu_item = gtk.MenuItem()
            else:
                menu_item = gtk.MenuItem(desc)
                menu_item.connect("activate",
                                  appliance_menu_callback, proxy, op)
            menu_item.show()
            provider_menu.append(menu_item)

        appliance_menu_map[provider] = provider_menu

    return appliance_menu_map

def appliance_menu_callback(widget, proxy, op):
    # generic callback to dispatch menu item events to the
    # provider implementation
    #print "Appliance menu clicked ", proxy, op
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.DOMAIN:
        vm = managed_node.get_dom(name)

    context = {}
    context["vm"] = vm
    try: 
        proxy.executeOp(vm, op)
    except Exception, ex:
        traceback.print_exc()
        showmsg(ex)
    

def show_vm_popup(widget, event, managed_node, vm_name):
    provider_id = None
    submenu = None
    if managed_node is not None and vm_name:
        vm = managed_node.get_dom(vm_name)
        if vm and vm.is_resident() and vm.get_config():
            config = vm.get_config()
            provider_id = config["provider_id"]

    if provider_id:
        submenu = appliance_menu_map.get(provider_id)
    
    if submenu:
        #parent = submenu.get_attach_widget()
        #if parent:
        #    submenu.detach()
        #if appliance_popup_item.get_submenu():
        #    appliance_popup_item.remove_submenu()
        appliance_popup_item.set_submenu(submenu)
        appliance_popup_item.show()
    else:
        appliance_popup_item.hide()
        
    vm_popup.popup(None, None, None,
                               event.button,
                               event.time)
    Coordinator.popup_stateRefresh(vm_popup)
                

def popupmenu(widget, event):
    """Checks whether the right mouse button was clicked within the domain
    TreeView and if so, displays a popup menu"""

    # if multiselect, do not show popup menu.
    try:
        (selected, parent_data) = left_nav.get_multi_selected()
    except Exception, ex:
        return

    if len(selected) > 1:
        return

    if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
        x = int(event.x)
        y = int(event.y)
        time = event.time
        pthinfo = left_nav.left_nav_view.get_path_at_pos(x, y)
        if pthinfo is not None:
            path, col, cellx, celly = pthinfo
            left_nav.left_nav_view.grab_focus()
            #left_nav.left_nav_view.set_cursor( path, col, 0)

            (name, node_type, managed_node, group, provider_id, obj_id) = left_nav.get_selection(path)
            Coordinator.set_popup_path(path)
            
            if node_type == LeftNav.DOMAIN:
                show_vm_popup(widget, event, managed_node,name)            
            elif node_type == LeftNav.MANAGED_NODE:
                node_popup.popup(None, None, None,
                                 event.button,
                                 event.time)
                Coordinator.popup_stateRefresh(node_popup)
            elif node_type == LeftNav.SERVER_POOL:
                pool_popup.popup(None, None, None,
                                 event.button,
                                 event.time)
                Coordinator.popup_stateRefresh(pool_popup)
            elif node_type == LeftNav.DATA_CENTER:
                dc_popup.popup(None, None, None,
                               event.button,
                               event.time)
                Coordinator.popup_stateRefresh(dc_popup)
            elif node_type == LeftNav.IMAGE:
                image_popup.popup(None, None, None,
                                  event.button,
                                  event.time)
                Coordinator.popup_stateRefresh(image_popup)
            elif node_type == LeftNav.IMAGE_GROUP:
                image_group_popup.popup(None, None, None,
                                  event.button,
                                  event.time)
                Coordinator.popup_stateRefresh(image_group_popup)
            elif node_type == LeftNav.IMAGE_STORE:
                image_store_popup.popup(None, None, None,
                                  event.button,
                                  event.time)
                Coordinator.popup_stateRefresh(image_store_popup)
            return 1
            

def opendom(widget):
    """Handles the open domain menu item which adds a dom by file name to
    the list of doms in the UI"""
    if not validate_node_selected(widget):
        return
    managed_node = Coordinator.get_managed_node(widget)
    
    mainwin = wtree.get_widget('MainWindow')
    result, file_list = \
            file_selection(managed_node,
                           "Please select VM configuration files", "open",
                           managed_node.get_config_dir(),
                           parentwin = mainwin,
                           multi_select=True)

    if result and file_list:
        for filename in file_list:
            left_nav.addDomFile(managed_node, filename)


def deletedom(widget):
    """Handles the menu items requesting to delete of a dom from the
    left_nav"""
    
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.DOMAIN:
        dom = managed_node.get_dom(name)
        msg = "Delete " + dom.name + " on " + managed_node.hostname+ "?"
        msg += "\n" + \
               "WARNING : Related VBDs/Volumes would also be deleted."
        if confirmation(msg):
            try:
                show_wait_cursor()
                host = dom.node.hostname
                cleanupQCDomain(managed_node, dom.name)
                left_nav.remDomFile(managed_node, dom.get_config().filename)
                Coordinator.handle_remove_dom(dom)
            finally:
                hide_wait_cursor()

def removedom(widget):
    """Handles the menu items requesting to removal of a dom from the
    left_nav"""
    
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.DOMAIN:
        dom = managed_node.get_dom(name)
        msg = "Remove " + dom.name + " from list under " + \
              managed_node.hostname+ "?"

        if confirmation(msg):
            host = dom.node.hostname
            left_nav.remDomFile(managed_node, dom.get_config().filename)
            Coordinator.handle_remove_dom(dom)


def show_settings(widget, blank=False):
    (name, node_type, managed_node, group_name, ignore, obj_id) = \
                                      Coordinator.get_selection(widget)

    if node_type == LeftNav.IMAGE_GROUP:
        return
    if node_type == LeftNav.SERVER_POOL and blank==True:
        provision_group_vm(widget)
        return
    if node_type == LeftNav.IMAGE and blank == True:
        provision_image(widget)
        return

    if managed_node is not None:
        eGroup = None
        if group_name is not None:
            eGroup = manager.getGroup( group_name )

        dom = managed_node.get_dom(name)
        if dom == None:
            blank = True

        if blank:
            ctx = dynamic_map()
            ctx.image_store = image_store
            ctx.managed_node= managed_node
            ctx.vm = None
            ctx.image_id = None
            ctx.server_pool= eGroup
            ctx.new_vm_callback = cb_new_dom
            ctx.platform = managed_node.get_platform()
            ctx.storage_manager = storage_manager
            ctx.nw_manager = nw_manager
            print "platform = ", ctx.platform
            
            platform = managed_node.platform
            #platform = "xen"
            helper = registry.get_ui_helper(platform)
            vm_settings_dlg = helper.get_vm_settings_dialog("PROVISION_VM",
                                                            ctx,mainwin)
            vm_settings_dlg.show()

        else:
            if dom.get_config() is not None:
                ctx = dynamic_map()
                ctx.image_store = image_store
                ctx.managed_node= managed_node
                ctx.vm = dom
                ctx.image_id = None
                ctx.server_pool= eGroup
                ctx.platform = dom.get_platform()
                ctx.storage_manager = storage_manager
                ctx.nw_manager = nw_manager
                
                platform = dom.get_platform()
                helper = registry.get_ui_helper(platform)
                vm_settings_dlg = helper.get_vm_settings_dialog("EDIT_VM_CONFIG",
                                                                ctx,mainwin)
                vm_settings_dlg.show()
            else:
                #if dom.isDom0():
                ctx = dynamic_map()
                ctx.managed_node= managed_node
                ctx.image_store = image_store
                ctx.vm = dom
                ctx.platform = managed_node.get_platform()
                ctx.storage_manager = storage_manager
                ctx.nw_manager = nw_manager
                
                platform = managed_node.get_platform()
                helper = registry.get_ui_helper(platform)
                vm_settings_dlg = helper.get_vm_settings_dialog("EDIT_VM_CONFIG",
                                                                ctx,mainwin)
                vm_settings_dlg.show()
                
    



def show_file_view_edit_dlg(widget):
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if managed_node is not None:
        dom = managed_node.get_dom(name)
        if dom is not None and dom.get_config() is not None:
            
            file_editor.show(widget,
                             managed_node,
                             dom.get_config().filename)

    
def kill_all_domains(widget):
    """ kill all running domains on a node """
    if not validate_node_selected(widget):
        return

    err_doms = []
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if managed_node is not None:
        if confirmation("Kill all running domains on " +
                        managed_node.hostname + "?"):
            domains = managed_node.get_dom_names()
            for dom in domains:
                try:
                    show_wait_cursor()
                    try:
                        if managed_node.is_resident(dom) and \
                               managed_node.isDomU(dom):
                            d = managed_node.get_dom(dom)
                            if d is not None:
                                d._destroy()
                            #managed_node.destroy_dom(dom)
                            
                    except Exception ,ex:
                        #print_stack()
                        print "kill all : Error killing ",dom,str(ex) 
                        # do best effort start, do not bother user.
                        err_doms.append(dom)
                finally:
                    hide_wait_cursor()
            if len(err_doms) > 0:
                showmsg(str(err_doms) + " could not be killed.\n" +
                        "Please try killing individually.")




def shutdown_all_domains(widget):
    """ shutdown all running domains on a node """
    if not validate_node_selected(widget):
        return

    err_doms = []
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if managed_node is not None:
        if confirmation("Shutdown all running domains on " +
                        managed_node.hostname + "?"):
            domains = managed_node.get_dom_names()
            for dom in domains:
                try:
                    show_wait_cursor()
                    try:
                        if managed_node.is_resident(dom) and \
                               managed_node.isDomU(dom):
                            managed_node.shutdown_dom(dom)
                    except Exception ,ex:
                        print "shutdown  all : Error shutting down ",dom,str(ex) 
                        # do best effort start, do not bother user.
                        err_doms.append(dom)
                finally:
                    hide_wait_cursor()
                    
            if len(err_doms) > 0:
                showmsg(str(err_doms) + " did not shutdown.\n" +
                        "Please try shutting them down individually.")


def start_all_domains(widget):
    """ start all domains on a node"""
    if not validate_node_selected(widget):
        return

    err_doms = []
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if managed_node is not None:
        if confirmation("Start  all domains on " +
                        managed_node.hostname + "?"):
            domains = managed_node.get_dom_names()
            for dom in domains:
                try:
                    show_wait_cursor()
                    try:
                        if not managed_node.is_resident(dom): 
                            managed_node.start_dom(dom)
                    except Exception ,ex:
                        print "Start all : Error starting " , dom, str(ex) 
                        # do best effort start, do not bother user.
                        err_doms.append(dom)
                finally:
                    hide_wait_cursor()

            if len(err_doms) > 0:
                showmsg(str(err_doms) + " could not be started.\n" +
                        "Please try starting them individually.")

def select_platform(widget):
    # show the dialogbox to select the platform from the
    # list of platform registerd.

    platform = None
    #TODO : fix registry to give this info is easily available!!
    if len(registry.get_platforms().keys()) > 1:
        dlg = dialogs.SelectPlatformDlg()
        ret = dlg.show(registry, mainwin)
        if ret:
            print "Platfom Selected = ", dlg.selected_platform
            platform = dlg.selected_platform
        else:
            return
    elif registry.get_platforms().keys() > 0:
        platform = registry.get_platforms().keys()[0]
        print "single platform ", platform
    
    # for now
    if not platform :
        raise Exception("A platform must be selected")

    return platform

        

def add_node(widget):
    """ add a new managed node to convirt """
    (name, node_type, group, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type is not None:
        if node_type == dialogs.SERVER_POOL:
            g_name = name
        else:
            g_name = None

        platform = select_platform(widget)
        if not platform:
            return
        helper = registry.get_ui_helper(platform)
        ret = helper.show_add_server_dialog(mode="add",
                                            group_name=g_name,
                                            platform = platform,
                                            existing_node=None,
                                            parentwin=mainwin)
        

def edit_node(widget):
    """ edit exiting node. """
    if not validate_node_selected(widget):
        return

    (name, node_type, \
     managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)

    helper = registry.get_ui_helper(managed_node.platform)
    ret = helper.show_add_server_dialog(mode="edit",
                                        group_name=group_name,
                                        platform = managed_node.platform,
                                        existing_node=managed_node,
                                        parentwin=mainwin)

def edit_group_vars(widget):
    (name, node_type, group, ignore1,\
     ignore2, ignore3) = Coordinator.get_selection(widget)
    if node_type == LeftNav.SERVER_POOL:
        eGroup = group
        groupvars = eGroup.getGroupVars( )
        dlg = GroupVariablesDlg( groupvars )
        dlg.show(widget, None)
        groupvars = dlg.get_group_vars()
        if groupvars is not None:
            eGroup.setGroupVars( groupvars )
            manager.setGroupVars(eGroup)


def remove_node(widget):
    """ add a new managed node to convirt """
    if not validate_node_selected(widget):
        return

    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if group_name:
        msg = "Remove " + managed_node.hostname + " from " + group_name + "?"
    else:
        msg = "Remove " + managed_node.hostname + "?"
    if confirmation(msg):
        left_nav.remove_node(managed_node, group_name)

def show_console(widget):
    """ show cpnsole """
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.DOMAIN:
        dom = managed_node.get_dom(name)
        nbook.showTab(dom)

def provision_image(widget):
    (image_name, node_type, managed_node, image_group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.IMAGE:
        image = image_store.get_image(obj_id)
        image_platform = image.get_platform()
        vm_config, image_config = image.get_configs()

        print "image platform ", image_platform
        node_selection_dlg.show(widget, manager, allow_groups = True,
                                platform = None, image = image)
        (name, type, m_node, group_name, ignore) = node_selection_dlg.get_selection()
        grp = None
        if type == dialogs.SERVER_POOL:
            grp = m_node
            policy_ctx = dynamic_map()
            policy_ctx.image = image
            node = grp.getAllocationCandidate(policy_ctx)
            if node is None:
                showmsg("Did not find any suitable Server in '%s'. \n Some of the reasons can be :\n  - Not connected to server \n - Server is not capable of provisioning the image. " % name)
                return
                
        else:
            node = m_node
            if group_name is not None :
                grp = manager.getGroup(group_name)
            
            
        if node is not None:
            ctx = dynamic_map()
            ctx.image_store = image_store
            ctx.managed_node = node
            ctx.image_id = obj_id
            ctx.image_group_id = image_group_name
            ctx.server_pool = grp
            ctx.new_vm_callback=cb_new_dom
            ctx.platform = node.get_platform()  #image_platform
            platform = ctx.platform
            ctx.storage_manager = storage_manager
            ctx.nw_manager = nw_manager

            helper = registry.get_ui_helper(platform)
            vm_settings_dlg = helper.get_vm_settings_dialog("PROVISION_VM",
                                                            ctx,mainwin)
            vm_settings_dlg.show()


def edit_image(widget):
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.IMAGE:
        ctx = dynamic_map()
        ctx.image_store = image_store
        ctx.managed_node = local_node
        ctx.image_id = obj_id
        if node_type == LeftNav.IMAGE:
            ctx.image_group_id = group_name
        else:
            ctx.server_pool = group_name

        platform = image_store.get_image(ctx.image_id).get_platform()
        ctx.platform = platform
        ctx.storage_manager = storage_manager
        ctx.nw_manager = nw_manager

        helper = registry.get_ui_helper(platform)
        vm_settings_dlg = helper.get_vm_settings_dialog("EDIT_IMAGE",
                                                        ctx,mainwin)
        vm_settings_dlg.show()


def edit_image_script(widget):
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.IMAGE:
        file_editor.show(widget,
                         local_node,
                         image_store.get_provisioning_script(obj_id))
        

def edit_image_desc(widget):
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.IMAGE:
        desc_file = image_store.images[obj_id].get_image_desc()
        if not local_node.node_proxy.file_exists(desc_file):
            file = local_node.node_proxy.open(desc_file,"w")
            file.write("Add description for %s image here\n" % name)
            file.close()
        file_editor.show(widget,
                         local_node,
                         desc_file)
        Coordinator.handle_nav_selection(widget)

def create_like_image(widget):
    (name, node_type, managed_node, group_id, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.IMAGE:
        clone_img_dialog.show(image_store, group_id, obj_id) 
        
def rename_image(widget):
    (name, node_type, managed_node, group_id, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.IMAGE:
        rename_img_dialog.show(image_store, group_id, obj_id) 

def rename_image_group(widget):
    (name, node_type, managed_node, group_id, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.IMAGE_GROUP:
        rename_img_grp_dialog.show(image_store, obj_id) 
        
def add_image_group(widget):
    (name, node_type, managed_node, group_id, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.IMAGE_STORE:
        add_image_group_dlg.show(image_store)

def delete_image(widget):
    (name, node_type, managed_node, group_id, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.IMAGE:
        if confirmation("Delete %s image ? " % name):
            image_store.delete_image(group_id, obj_id)
            left_nav.refresh_nodes()
            left_nav.set_selection("Image Store",left_nav.IMAGE_STORE,
                                   op="row-activated")

def delete_image_group(widget):
    (name, node_type, managed_node, group_id, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.IMAGE_GROUP:
        if len(image_store.image_groups[obj_id].get_images()) > 0:
            msg = "Image group '" + name + "' is not empty. All images in the Image group should be removed."
            showmsg(msg)
            return
            
        if confirmation("Delete image group %s? " % name):
            image_store.delete_group(image_store.image_groups[obj_id]) 
            left_nav.refresh_nodes()
            left_nav.set_selection("Image Store",left_nav.IMAGE_STORE,
                                   op="row-activated")

def import_appliance(widget):
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    group_id = None 
    if node_type == LeftNav.IMAGE_GROUP:
        group_id = obj_id
        
    appliance_dialog.show(widget,  group_id, parentwin = mainwin )


        
def connect_node(widget):
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.MANAGED_NODE:
        if managed_node is not None:
            do_work(lambda : cb_connect(managed_node, creds_helper),
                    "Connect Node " + managed_node.hostname,
                    lambda : cb_set_selection(managed_node.hostname,
                                              left_nav.MANAGED_NODE,
                                              op="row-activated"))
        

def networks_activate(widget):
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)    
    if node_type == LeftNav.SERVER_POOL:
        group = managed_node
        managed_node=None
    elif node_type == LeftNav.MANAGED_NODE:
        group = None # indicate that it is a host only network.
        
        

    if node_type in (LeftNav.SERVER_POOL, LeftNav.MANAGED_NODE):
        nw_list_dlg = NWListDlg()
        nw_list_dlg.show(widget, nw_manager,
                         group, managed_server = managed_node, parent = mainwin)


def shared_storage_activate(widget):
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)    
    if node_type == LeftNav.SERVER_POOL:
        group = managed_node
        managed_server = None
        
        shared_storage_definition = StorageDefinitionListDialog()
        shared_storage_definition.show(widget, storage_manager,
                                   managed_server, group, parent = mainwin)
        
def set_boot_image_activate(widget):
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)    
    if node_type == LeftNav.DOMAIN:
        dom = managed_node.get_dom(name)
        vm_config = dom.get_config()

        if not vm_config:
            showmsg("No configuration file associated with this VM.")
            return 
        boot_image = vm_config['boot']
        
        boot_image_dialog = SelectBootImageDialog()
        ret = boot_image_dialog.show(name, boot_image)
        
        if ret != gtk.RESPONSE_OK:
            return
        boot_image = boot_image_dialog.get_boot_image()

        if dom.is_resident():
            showmsg("The VM is running. The new Boot Location will take effect when VM is restarted.")
         
        # Set only if it is a proper option    
        if boot_image is not None:
            vm_config['boot'] = boot_image
            vm_config.write()
    else:
        return


def cb_connect(managed_node, creds_helper=None):
    while not managed_node.is_authenticated():
        try:
            managed_node.connect()
        except AuthenticationException ,ex:
            try:
                threads_enter()
                creds = None
                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)
            finally:
                threads_leave()

    

def disconnect_node(widget):
    (name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.MANAGED_NODE:
        if managed_node is not None:
            managed_node.disconnect()
    

def connect_all_nodes(widget):
    (grp_name, node_type, managed_node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.SERVER_POOL or node_type == LeftNav.DATA_CENTER:
        if node_type == LeftNav.DATA_CENTER:
            grp_name = None
        names = manager.getNodeNames(grp_name)
        names.sort()
        def cb_connect_all_nodes(names):
            err = []
            for name in names:
                node = manager.getNode(name, grp_name)

                if not node.is_authenticated():
                    try:
                        cb_connect(node, creds_helper)
                        #node.connect()
                    except Exception ,ex:
                        err.append("%s connect Error : %s " %
                                      (node.hostname, str(ex)))
                        continue
                    

            if len(err) > 0:
                raise Exception(err)
            
        do_work(lambda : cb_connect_all_nodes(names), "Connect all Servers")

def add_server_pool(widget):
    add_server_group_dlg.show()

def remove_server_pool(widget):
    (name, node_type, node, group_name, ignore, obj_id) = Coordinator.get_selection(widget)
    if node_type == LeftNav.SERVER_POOL:
        if node is not None:
            group = node
            if len(group.getNodeNames()) > 0:
                msg = "Server Pool '" + name + "' is not empty. All servers in the Server Pool would also be removed.\nDo you want to Continue ? "
                if confirmation(msg): 
                    left_nav.remove_group(name, True)
            else:
                msg = "Remove '" + name + "' Server Pool ?"
                if confirmation(msg): 
                    left_nav.remove_group(name)

def provision_group_vm(widget):
    (name, node_type, grp, grp_name, ignore, obj_id) = Coordinator.get_selection(widget)
    try:
        target_node = grp.getAllocationCandidate(None)
    except Exception, ex:
        traceback.print_exc()
        showmsg("Error selecting candindate server using policy.\n " +
               str(ex) +
               "\nPlease select a Server for provisioning." )
        node_selection_dlg.show(widget, manager)
        (target_node_name, target_type, target_node, group_name, ignore) = node_selection_dlg.get_selection()
        
    if target_node is not None:
        eGroup = grp
            
        print "Allocating new VM on: ", target_node.hostname
        ctx = dynamic_map()
        ctx.image_store = image_store
        ctx.managed_node = target_node
        ctx.server_pool = grp
        ctx.new_vm_callback=cb_new_dom
        ctx.platform = target_node.get_platform()
        ctx.storage_manager = storage_manager
        ctx.nw_manager = nw_manager
        
        platform = target_node.get_platform()
        helper = registry.get_ui_helper(platform)
        vm_settings_dlg = helper.get_vm_settings_dialog("PROVISION_VM",
                                                        ctx,mainwin)
        vm_settings_dlg.show()

    else:
        showmsg("Did not find any suitable Server in '%s'. \n You may not be connected to servers in the pool." % grp.name)


    
def show_action_menu(widget):
    #print "show action menu clicked"
    return 1

def wrapper(widget, func,*args, **cargs):
    try:
        func(widget, *args, **cargs)
        left_nav.left_nav_view.queue_draw()
    except Exception , ex:
        print_stack()
        showmsg("Wrapper : Exception : " + str(ex))

def display_wiki(widget):
    wiki_url = "http://www.convirture.com/wiki"
    utils.show_url(wiki_url)

def display_help(widget):
    """ display help """
    
   ##     import gnome
   ##     gnome.help_display_uri("./errata.html")
   ##     return
#    browser = client_config.get(utils.XMConfig.CLIENT_CONFIG,
#                                prop_browser)
#    if browser is None:
#        browser ="/usr/bin/yelp"
        
    
    if os.path.exists('doc/manual.html'):
        help_file = 'doc/manual.html'
    elif len(glob.glob('/usr/share/doc/convirt*/manual.html'))>0:
        help_file = glob.glob('/usr/share/doc/convirt*/manual.html')[0]
    else:
        help_file = None
        
    help_file="http://www.convirture.com/wiki/index.php?title=Documentation"
    utils.show_url(help_file)


def check_on_startup():
    chk_for_update = client_config.get(utils.XMConfig.CLIENT_CONFIG,
                                       prop_chk_updates_on_startup)
    if chk_for_update:
        chk_for_update = eval(chk_for_update)
    else:
        chk_for_update = True

    if chk_for_update:
        worker = Worker(check_for_updates,
                        cb_suc_update_check, dialogs.cb_showmsg)
        worker.start()

def check_for_updates(widget=None):
    u_mgr = utils.UpdatesMgr(local_node.config)
    updates = u_mgr.get_new_updates()
    if not widget:
        # invoked from a worker thread
        return updates
    else:
        # invoked from menu
        if updates and len(updates) > 0:
            updates_dlg = UpdatesDlg()
            updates_dlg.show(updates)
        else:
            showmsg("No updates since last check.")
            
def cb_suc_update_check(updates):
    if updates and len(updates) > 0:
        try:
            threads_enter()
            updates_dlg = UpdatesDlg()
            updates_dlg.show(updates)
        finally:
            threads_leave()

def show_license_dlg(widget=None):
    licence_dlg = LicenseDlg(store)
    licence_dlg.show(manager)
    
                
#############################################
# Main block                                #
#############################################

# add the threads init as recommended in pygtk FAQ
gobject.threads_init()
gtk.gdk.threads_init()

# set default timeout to 5 sec. This applies to setting connections.
# Fixes the problem when I tried to connect to my machine booted in
# Windows!!!.
socket.setdefaulttimeout(5)

showmsg = dialogs.showmsg
confirmation = dialogs.confirmation
file_selection = dialogs.file_selection


## initialize the phelper credentials helper
creds_helper = CredentialsHelper(wtree)
#PHelper.set_credentials_helper(creds_helper)

# Look at the command line arguments  and set up the server.
# for now simple checks for arguments

timer = None

# Create a local node
local_node = ManagedNode(hostname = LOCALHOST,
                         isRemote = False,
                         helper = None) #creds_helper)
client_config = local_node.config

# set the proxies from the config in to the environment
http_proxy=client_config.get(utils.XMConfig.CLIENT_CONFIG,
                               prop_http_proxy)
if http_proxy:
    if http_proxy.find("http") != 0:
        http_proxy="http://" + http_proxy

ftp_proxy=client_config.get(utils.XMConfig.CLIENT_CONFIG,
                               prop_ftp_proxy)
if ftp_proxy:
    if ftp_proxy.find("http") != 0:
        ftp_proxy="http://" + ftp_proxy
else:
    ftp_proxy=http_proxy


# guess the proxy if not set yet.
if http_proxy is None and ftp_proxy is None:
    try:
        guess_proxy=client_config.get(utils.XMConfig.CLIENT_CONFIG,
                               prop_guess_proxy)
        if guess_proxy:
            guess_proxy = eval(guess_proxy)
        else:
            guess_proxy = True
        if guess_proxy:
            (http_proxy, ftp_proxy) =  utils.guess_proxy_setup()
            print "guessed proxy setup ", http_proxy, ftp_proxy
    except Exception, ex:
        print "Error guessing proxy", ex

if http_proxy:
    os.environ["http_proxy"] = http_proxy
if ftp_proxy:
    os.environ["ftp_proxy"] = ftp_proxy


### lame logging.
enable_log = client_config.get(utils.XMConfig.CLIENT_CONFIG,
                               prop_enable_log)
if enable_log:
    log_file = client_config.get(utils.XMConfig.CLIENT_CONFIG,
                         prop_log_file)
    if log_file and log_file is not '':
        if log_file != "console":
            if log_file[0] != '/' and (log_file.find("./") != 0):
                # assume path relative to log_dir
                log_location = client_config.get(utils.XMConfig.PATHS,
                                                 prop_log_dir)
                log_file = os.path.join(log_location,log_file)

            try:
                if not os.path.exists(log_location):
                    utils.mkdir2(local_node,log_location)
                print "Log file at %s" % (log_file)
                f = open(log_file, "w")
                sys.stderr = f
                sys.stdout = f
            except Exception, ex:
                print "Could not create log file. ", log_file
                print "Consider changing log dir in convirt.conf"

        else:
            # do nothing
            pass

store = client_config   # for now application data stored in config file. :(
## Locate the registry file and get the registry info.

# pass the empty ui_context, populate it later.
# we might change this to set_ui_context in the registry.

ui_context = {}
registry = PlatformRegistry(client_config,store,ui_context)
platforms = registry.get_platforms()
if not platforms or len(platforms.keys()) ==0:
    print "No platforms found. Can not proceed."
    print "Check the registry file : %s" % reg_file
    sys.exit(1)

# initialize the platforms
registry.init_platforms(client_config)

manager = GridManager(store, client_config, registry, None) #creds_helper)

storage_manager = StorageManager(store)
nw_manager = NwManager(store)
# detect the platform for the local host.
plats = registry.detect_platforms(local_node)

# currently we support only one platform per node.
valid_plats = []
prompt = local_node.config.get(utils.XMConfig.CLIENT_CONFIG,
                                   prop_init_confirmation)

print "PROMPT ", prompt
for plat in plats:
    (res, msgs) = registry.runPrereqs(local_node, plat)
    if res:
        valid_plats.append(plat)
    elif prompt is None or prompt == "True":
        try:
            threads_enter()
            m = 'WARNING: Prereq failed for %s platform. %s\n' % (plat, msgs)
            if not confirmation( m + \
                                'Would you like to manage remote servers only? \n\n'+
                                'Click YES to proceed \n'+
                                'Click CANCEL to exit and launch ConVirt '+\
                                'with prerequisites met.'):
                sys.exit(0)
            else:
                local_node.config.set(utils.XMConfig.CLIENT_CONFIG,
                                      prop_init_confirmation,'False')
        finally:
            threads_leave()
        
local_platform = None

# TODO: May be throw up a dialgbox to let it pick a platform
if valid_plats and len(valid_plats) > 0:
    local_platform = valid_plats[0]

if local_platform:
    # add the node.
    factory = manager.getFactory(local_platform)
    local_managed_node = factory.create_node( platform=local_platform,
                                              hostname = LOCALHOST,
                                              isRemote = False )

    if local_managed_node.hostname not in manager.getNodeNames():
        manager.addNode(local_managed_node)
        local_dom_names = local_managed_node.get_dom_names() # force authentication



# Initialise the configuration objects to gain access to global defaults
try:
    image_store = ImageStore(local_node.config, registry)
except Exception, ex:
    traceback.print_exc()
    store_location = local_node.config.get(utils.XMConfig.PATHS,
                                           prop_image_store)
    (m_p, m_file) = get_path("mk_image_store", ("install/common",))
    showmsg("Error initializing image store.\n %s \n Run ConVirt as superuser OR execute '%s' to create a private image store." % (str(ex), m_file))
    sys.exit(1)

appliance_store = ApplianceStore(local_node, client_config)

#KLUDGE :populate the main context so dialogs and utils can share.
main_context["client_config"] = client_config
main_context["local_node"] = local_node
main_context["creds_helper"] = creds_helper

    
# Let's instantiate the dom management object

mainwin = wtree.get_widget("MainWindow")
left_nav = LeftNav(wtree)
nbook = NoteBook(left_nav)
Coordinator.set_nav(left_nav)
Coordinator.set_notebook(nbook)

# sequencing.... and hence here.
ui_context["left_nav"] = left_nav
ui_context["client_config"] = client_config
ui_context["manager"] = manager

signals = {"on_MainWindow_delete_event": quitProgram,
           "on_startbutton_clicked": (wrapper,startdom),
           "on_killbutton_clicked": (wrapper,killdom),
           "on_pausebutton_toggled": (wrapper,pausedom),
           "on_new_domain_activate": (wrapper,show_settings, True),
           "on_add_node_activate": (wrapper,add_node),
           "on_group_variables_activate" : (wrapper, edit_group_vars),
           "on_start_all_domains_activate": (wrapper,start_all_domains),
           "on_shutdown_all_domains_activate" : (wrapper,shutdown_all_domains),
           "on_kill_all_domains_activate" : (wrapper,kill_all_domains),
           "on_show_console_activate": (wrapper,show_console),
           "on_migrate_button_clicked": (wrapper,migratedom),
           "on_migrate_all_activate": (wrapper,migrate_all),
           "on_remove_node_activate": (wrapper,remove_node),
           "on_open_domain_activate": (wrapper,opendom),
           "on_Remove_activate": (wrapper,removedom),
           "on_delete_dom_activate": (wrapper,deletedom),
           "on_DomView_button_press_event": popupmenu,
           "on_statTable_button_press_event": summary_popupmenu,
           "on_DomView_focus_in_event": Coordinator.focus_in,
           "on_DomView_focus_out_event":Coordinator.focus_out,
           "on_statTable_focus_in_event":Coordinator.focus_in,
           "on_statTable_focus_out_event":Coordinator.focus_out,
           "on_Settings_activate": (wrapper,show_settings),
           "on_edit_config_file_activate": (wrapper,show_file_view_edit_dlg),
           "on_quit_activate": quitProgram,
           "on_rebootbutton_clicked": (wrapper,rebootdom),
           "on_shutdownbutton_clicked": (wrapper,shutdowndom),
           "on_snapshotbutton_clicked": (wrapper,savedom),
           "on_restorebutton_clicked": (wrapper,restoredom),
           "on_restore_vm_activate" : (wrapper,restoredom),
           'on_about_activate': show_about,
           'on_AboutDialog_response': hide_about,
           'on_AboutDialog_delete_event': hide_about,
           'on_help_activate': (wrapper,display_help),
           'on_wiki_activate': (wrapper,display_wiki),
           'on_image_popup_provision_activate' : (wrapper, provision_image),
           'on_image_popup_edit_activate' : (wrapper, edit_image),
           'on_image_popup_edit_script_activate' : (wrapper, edit_image_script),
           'on_image_popup_edit_desc_activate' : (wrapper, edit_image_desc),
           'on_image_popup_create_like_activate' : (wrapper, create_like_image),
           'on_image_popup_rename_image_activate' : (wrapper, rename_image),
           'on_image_popup_rename_group_image_activate' : (wrapper, rename_image_group),
           'on_image_popup_delete_group_image_activate' : (wrapper, delete_image_group),
           'on_image_popup_delete_image_activate' : (wrapper, delete_image),
           'on_add_image_group_activate': (wrapper,add_image_group),
           'on_appliance_import_activate' : (wrapper, import_appliance),
           'on_connect_activate': (wrapper, connect_node),
           'on_disconnect_activate': (wrapper, disconnect_node),
           'on_connect_all_nodes_activate': (wrapper,connect_all_nodes),
           'on_add_server_pool_activate': (wrapper,add_server_pool),
           'on_remove_server_pool_activate': (wrapper,remove_server_pool),
           'on_provision_group_vm_activate': (wrapper, provision_group_vm),
           'on_show_vm_menu' : (wrapper, show_action_menu),
           'on_edit_node_activate' : (wrapper, edit_node),
           'on_check_for_updates_activate' : (wrapper, check_for_updates),
           'on_show_license_information' : (wrapper, show_license_dlg),
           'on_shared_storage_activate' : (wrapper, shared_storage_activate),
           'on_networks_activate' : (wrapper, networks_activate),
           'on_popup_boot_image_activate' : (wrapper, set_boot_image_activate),
           }

wtree.signal_autoconnect(signals)

# Let's define the parent for the dialog windows (glade should do it but
# doesn't)

mainwin = wtree.get_widget('MainWindow')

# Wait cursor window

## attribs = { 'wmclass': gtk.gdk.INPUT_ONLY,
##             'window_type': gtk.gdk.WINDOW_CHILD,
##             'event_mask': 0,
##             'x': 0,
##             'y': 0,
##             'width': gtk.gdk.screen_width(),
##             'height': gtk.gdk.screen_height() }
## cursor_win = gtk.window_new(mainwin, attribs)
## gdk_cursor = gtk.cursor_new(gtk.gdk.WATCH)
## cursor_win.set_cursor(gdk_cursor)

## main_context["cursor_win"] = cursor_win
main_context["main_window"] = mainwin

for dname in ("SettingsDialog", "StatusDialog", "ConfirmationDialog",
              "AboutDialog", 
              "Credentials", "NodeSelection", "AddServerPool",
              "CloneImage", "RenameImage", "RenameImageGroup", "appliance_dialog", 
               ):
    
    dialog = wtree.get_widget(dname)
    dialog.set_transient_for(mainwin)

abt_dlg_label = wtree.get_widget("label_version")
v = abt_dlg_label.get_text()
abt_dlg_label.set_text(v + convirt.core.utils.constants._version)
node_selection_dlg = NodeSelection(wtree)
add_server_group_dlg = AddServerGroupDialog(wtree,left_nav)
clone_img_dialog = CloneImageDialog(wtree, left_nav)
rename_img_dialog = RenameImageDialog(wtree, left_nav)
rename_img_grp_dialog = RenameImageGroupDialog(wtree, left_nav)
add_image_group_dlg = AddImageGroupDialog(wtree,left_nav)

# Appliance store and list initialization
appliance_import_dlg = ImportApplianceDlg(wtree,
                                          left_nav,
                                          local_node,
                                          appliance_store,
                                          image_store,
                                          registry)

appliance_dialog = ApplianceList(wtree,
                                 appliance_store,
                                 image_store,
                                 appliance_import_dlg)


# save handles to popup menus
vm_popup = wtree.get_widget("PopupMenu")
node_popup = wtree.get_widget("NodePopup")
pool_popup = wtree.get_widget("PoolPopup")
dc_popup = wtree.get_widget("DCPopup")
image_popup = wtree.get_widget("ImagePopup")
image_group_popup = wtree.get_widget("ImageGroupPopup")
image_store_popup = wtree.get_widget("ImageStorePopup")


# appliance icon
from convirt.client.dialogs import appliance_pb
img_popup = gtk.Image()
img_popup.set_from_pixbuf(appliance_pb)
# get the menu for appliance operations
appliance_menu_map = do_appliance_integration()
appliance_popup_item = gtk.ImageMenuItem("Appliance")
appliance_popup_item.set_image(img_popup)
vm_popup.append(appliance_popup_item)



## TODO : Look at integrating this in to one.
img_menu = gtk.Image()
img_menu.set_from_pixbuf(appliance_pb)
appliance_menu_item = gtk.ImageMenuItem("Appliance")
appliance_menu_item.set_image(img_menu)
action_item = wtree.get_widget("action_menu")
action_submenu = action_item.get_submenu()
if action_submenu:
    action_submenu.append(appliance_menu_item)
    
#action_item.set_submenu(vm_popup)

# Setup the timer

# kick off population of summary tab
#TRICK
Coordinator.stat_refresh_count = 1

timer = Timer()


# paramiko logfile
enable_paramiko_log = local_node.config.get(utils.XMConfig.CLIENT_CONFIG,
                                            prop_enable_paramiko_log)
if enable_paramiko_log:
    paramiko_file = local_node.config.get(utils.XMConfig.CLIENT_CONFIG,
                             prop_paramiko_log_file)
    if paramiko_file and paramiko_file != '':
        if paramiko_file[0] != '/' and (paramiko_file.find("./") !=0):
            p_log_location = local_node.config.get(utils.XMConfig.PATHS,
                                                   prop_log_dir)
            if not os.path.exists(p_log_location):
                utils.mkdir2(local_node, p_log_location)
            p_log = os.path.join(p_log_location,paramiko_file)
        else:
            p_log = paramiko_file
        PHelper.init_log(p_log)


# check if the update/news for ConVirt are available.
check_on_startup()

# Run the main GUI loop
gtk.gdk.threads_enter()
gtk.main()
gtk.gdk.threads_leave()

# destroy wait window
#cursor_win.destroy()
cursor_win = None

