# -----------------------------------------------------------------------
# OpenXenManager
#
# Copyright (C) 2009 Alberto Gonzalez Rodriguez alberto@pesadilla.org
# Copyright (C) 2014 Daniel Lintott <daniel@serverb.co.uk>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# -----------------------------------------------------------------------
from window_vm_network import *
from window_vm_storage import *
from window_vm_snapshot import *
from window_vm_performance import *
import gtk
import time
import os
import utils
selection = None


class oxcWindowVM(oxcWindowVMNetwork,oxcWindowVMStorage,oxcWindowVMSnapshot,oxcWindowVMPerformance):
    """
    Class to manage window actions
    """

    def update_memory_tab(self):
        if self.treeview.get_cursor()[1]:
                dynamicmin = self.xc_servers[self.selected_host].all['vms'][self.selected_ref]["memory_dynamic_min"]
                dynamicmax = self.xc_servers[self.selected_host].all['vms'][self.selected_ref]["memory_dynamic_max"]
                staticmin = self.xc_servers[self.selected_host].all['vms'][self.selected_ref]["memory_static_min"]
                staticmax = self.xc_servers[self.selected_host].all['vms'][self.selected_ref]["memory_static_max"]
                ishvm = self.xc_servers[self.selected_host].all['vms'][self.selected_ref]["HVM_boot_policy"]
                if ishvm:
                    self.builder.get_object("lbldynamicmin").set_label(self.convert_bytes_mb(dynamicmin) + " MB")
                    self.builder.get_object("lbldynamicmax").set_label(self.convert_bytes_mb(dynamicmax) + " MB")
                    self.builder.get_object("lblstaticmax").set_label(self.convert_bytes_mb(staticmax) + " MB")

                    self.builder.get_object("txtdynamicmin").set_text(self.convert_bytes_mb(dynamicmin))
                    self.builder.get_object("txtdynamicmax").set_text(self.convert_bytes_mb(dynamicmax))
                    self.builder.get_object("txtstaticmax").set_text(self.convert_bytes_mb(staticmax))
                    self.builder.get_object("tabboxmem").set_current_page(0)
                else:
                    self.builder.get_object("lbldynamicmin1").set_label(self.convert_bytes_mb(dynamicmin) + " MB")
                    self.builder.get_object("lbldynamicmax1").set_label(self.convert_bytes_mb(dynamicmax) + " MB")
                    self.builder.get_object("txtfixedmemory").set_text(self.convert_bytes_mb(staticmax))

                    self.builder.get_object("txtdynamicmin1").set_text(self.convert_bytes_mb(dynamicmin))
                    self.builder.get_object("txtdynamicmax1").set_text(self.convert_bytes_mb(dynamicmax))

                    self.builder.get_object("radiomemstatic").set_active(dynamicmin == dynamicmax)
                    self.builder.get_object("radiomemdynamic").set_active(dynamicmin != dynamicmax)
                    self.builder.get_object("tabboxmem").set_current_page(1)


    def on_btapplymemory_clicked(self, widget, data=None):
        dynamicmin = self.builder.get_object("txtdynamicmin").get_text()
        dynamicmax = self.builder.get_object("txtdynamicmax").get_text()
        staticmax = self.builder.get_object("txtstaticmax").get_text()
        self.xc_servers[self.selected_host].set_memory(self.selected_ref, dynamicmin, dynamicmax, staticmax)

    def on_btapplymemory1_clicked(self, widget, data=None):
        if self.builder.get_object("radiomemstatic").get_active():
            minimun = maximun = self.builder.get_object("txtfixedmemory").get_text()
            self.xc_servers[self.selected_host].set_memory_limits(self.selected_ref, minimun, maximun, minimun, maximun)
        else:
            minimun = self.builder.get_object("txtdynamicmin1").get_text()
            maximun = self.builder.get_object("txtdynamicmax1").get_text()
            self.xc_servers[self.selected_host].set_memory_limits(self.selected_ref, minimun, maximun, minimun, maximun)

    def on_btsendctraltdel_clicked(self, widget, data=None):
        """
        Function called when you press "send ctrl alt del" on vm console
        """
        self.on_menuitem_tools_cad_activate(widget, data)


    def vnc_button_release(self, clipboard, data, user=None):
        global selection
        selection = data
        self.vnc[self.selected_ref].client_cut_text(data)
        return 

    def copy_cb(self, clipboard, data, info, user=None):
        global selection
        data.set_text(selection, -1)

    def clear_cb(self, clipboard, data, user=None):
        return

    def on_consolescale_toggled(self, widget):
        """
        Function called when toggle the console scale option
        """
        if hasattr(self, 'vnc'):
            if widget.get_active():
                self.vnc[self.selected_ref].set_scaling(True)
            else:
                self.vnc[self.selected_ref].set_scaling(False)

    def on_btcopytext_clicked(self, widget, data=None):
        """
        Function called when you press "Copy selected text" on console tab
        """
        clipboard = self.vnc[self.selected_ref].get_clipboard(gtk.gdk.SELECTION_CLIPBOARD)
        clipboard.connect("owner-change", self.vnc_button_release)
        text = clipboard.wait_for_text()
        targets = [('TEXT', 0, 1), ('STRING', 0, 2), ('COMPOUND_TEXT', 0, 3), ('UTF8_STRING', 0, 4)]
        clipboard.set_with_data(targets, self.copy_cb, self.clear_cb, None);
        def text_get_func(clipboard, text, data):
            if text:
                self.vnc[self.selected_ref].client_cut_text(text)
        clipboard.request_text(text_get_func)


    def on_btundockconsole_clicked(self, widget, data=None):
        """
        Function called when you press "undock"
        """
        #create a new window and append the vnc
        if self.selected_ref not in self.vnc_builders.keys():
            self.noclosevnc = True
            self.builder.get_object("console_area").remove(self.vnc[self.selected_ref])
            glade_dir = os.path.join(utils.module_path(), 'ui')
            self.vnc_builders[self.selected_ref] = gtk.Builder()
            self.vnc_builders[self.selected_ref].add_from_file(os.path.join(glade_dir,"window_vnc.glade"))
            self.vnc_builders[self.selected_ref].get_object("console_area3").add(self.vnc[self.selected_ref])
            self.vnc_builders[self.selected_ref].get_object("btredockconsole").connect("clicked", self.on_btredockconsole_clicked,self.selected_ref)
            self.vnc_builders[self.selected_ref].get_object("btredockconsole").connect("destroy", self.on_btredockconsole_clicked,self.selected_ref)
            self.vnc_builders[self.selected_ref].get_object("btsendctrlaltdel1").connect("clicked", self.on_btsendctraltdel_clicked,self.selected_ref)
            self.vnc_builders[self.selected_ref].get_object("windowvncundock").set_title(self.selected_name)
            self.vnc_builders[self.selected_ref].get_object("windowvncundock").show_all()
            
        else:
            #If the vnc window already exists (partially covered or minimized), present it to the user.
            self.vnc_builders[self.selected_ref].get_object("windowvncundock").present()

    def on_btredockconsole_clicked(self, widget, data=None):
        """
        Function called when you press "redock"
        """
        try: self.vnc_builders[data].get_object("console_area3").remove(self.vnc[data])
        except: print "Failed to remove vnc object from window"

        self.vnc_builders[data].get_object("windowvncundock").destroy()
        if self.selected_ref == data:
            self.builder.get_object("console_area").add(self.vnc[self.selected_ref])
        #Pop key from vnc_builders dict
        if data in self.vnc_builders.keys(): del self.vnc_builders[data]        


    def on_btenterfullscreen_clicked(self, widget, data=None):
        """
        Function called when you press "enter fullscreen"
        """
        self.builder.get_object("windowvnc").show()
        self.builder.get_object("console_area").remove(self.vnc[self.selected_ref])
        self.builder.get_object("console_area2").add(self.vnc[self.selected_ref])
        self.builder.get_object("windowvnc").fullscreen()

    def on_btexitfullscreen_clicked(self, widget, data=None):
        """
        Function called when you press "exit fullscreen"
        """
        self.builder.get_object("windowvnc").hide()
        self.builder.get_object("console_area2").remove(self.vnc[self.selected_ref])
        self.builder.get_object("console_area").add(self.vnc[self.selected_ref])

    def on_windowcopyvm_cancel_activate(self, widget, data=None):
        """
        Function called when you cancel "window copy" window
        """
        self.builder.get_object("windowcopyvm").hide()

    def on_windowcopyvm_copy_activate(self, widget, data=None):
        """
        Function called when you accept "window copy" window
        """
        listcopystg = self.builder.get_object("listcopystg")
        treecopystg = self.builder.get_object("treecopystg")
        # Get the name and description
        name = self.builder.get_object("txtcopyvmname").get_text()
        desc = self.builder.get_object("txtcopyvmdesc").get_text()
        full = False
        # Check if "fast clone" is selected or "full clone"
        if self.builder.get_object("radiofullclone").get_active():
            full = True
        # Get the selected storage
        selection = treecopystg.get_selection()
        if selection.get_selected()[1] == None:
            iter = listcopystg.get_iter((0,1))
        else:
            iter = selection.get_selected()[1]
        sr = listcopystg.get_value(iter, 1)
        # Call to function to copy the vm
        self.xc_servers[self.selected_host].copy_vm(self.selected_ref, name, desc, sr, full)
        self.builder.get_object("windowcopyvm").hide()

    def on_btimportaddnetwork_clicked(self, widget, data=None):
        """
        Function called whe you press add a new network when you are doing "import" process
        """
        treeimportservers = self.builder.get_object("treeimportservers")
        listimportservers = self.builder.get_object("listimportservers")
        selection = treeimportservers.get_selection()
        host = listimportservers.get_value(selection.get_selected()[1], 3)
        listimportnetworks = self.builder.get_object("listimportnetworks")
        # Get first network as default and network ref
        network = self.xc_servers[host].first_network()
        network_ref = self.xc_servers[host].first_network_ref()
        # Add to network list
        listimportnetworks.append(["interface " + str(listimportnetworks.__len__()),
                "auto-generated",
                network, network_ref
            ])
    def on_btimportdeletenetwork_clicked(self, widget, data=None):
        """
        Function called whe you press delete a network when you are doing "import" process
        """
        listimportnetworks = self.builder.get_object("listimportnetworks")
        treeimportnetworks = self.builder.get_object("treeimportnetworks")
        selection = treeimportnetworks.get_selection()
        # Get selected
        iter = selection.get_selected()[1]
        # And remove from list
        listimportnetworks.remove(iter)
 

    def on_dialogdelete_cancel_activate(self, widget, data=None):
        """
        Function called when you cancel the "delete vm" confirmation
        """
        self.builder.get_object("dialogdeletevm").hide()
    def on_dialogdelete_accept_activate(self, widget, data=None):
        """
        Function called when you cancel the "delete vm" confirmation
        """
        # Get if "delete disks" and "delete snapshots" are active
        delete_vdi = self.builder.get_object("dialogdelete_vdi").get_active()
        delete_snap = self.builder.get_object("dialogdelete_snap").get_active()
        # Remove first from list
        self.treestore.remove(self.selected_iter)
        # And late remove from server
        self.xc_servers[self.selected_host].destroy_vm(self.selected_ref, delete_vdi, delete_snap)
        # And hide confirmation window
        self.builder.get_object("dialogdeletevm").hide()
    def on_filechooserimportvm_file_set(self, widget, data=None):
        """"
        Function called when you select a file to import
        """
        # Enable "Next >" button because filename was selected
        self.builder.get_object("nextvmimport").set_sensitive(True)
    def on_tabboximport_switch_page(self, widget, data=None, data2=None):
        """
        Function called when you change the page in "import vm" process
        """
        # Set colors..
        white = gtk.gdk.color_parse("white")
        blue = gtk.gdk.color_parse("#d5e5f7")
        for i in range(0,5):
             self.builder.get_object("eventimport" + str(i)).modify_bg(gtk.STATE_NORMAL, white)
        self.builder.get_object("eventimport" + str(data2)).modify_bg(gtk.STATE_NORMAL, blue)
        # If page is the first, you cannot go to previous page
        self.builder.get_object("previousvmimport").set_sensitive(data2 != 0)
    def on_nextvmimport_clicked(self, widget, data=None):
        """
        Function called when you press "Next" button on Import VM process
        """
        # Get the current page
        page = self.builder.get_object("tabboximport").get_current_page()
        # Move the tabbox to next tab
        self.builder.get_object("tabboximport").set_current_page(page+1)
        if page+1 == 1:
            # If next page is the second.. 
            treeimportservers = self.builder.get_object("treeimportservers")
            selection = treeimportservers.get_selection().get_selected()[1]
            # If in possible servers to import there is one element, enable "Next" button
            self.builder.get_object("nextvmimport").set_sensitive(selection != None)
        if page+1 == 2:
            # If next page is the third..
            treeimportservers = self.builder.get_object("treeimportservers")
            listimportservers = self.builder.get_object("listimportservers")
            selection = treeimportservers.get_selection()
            # Get selected host
            host = listimportservers.get_value(selection.get_selected()[1], 3)
            listimportstg = self.builder.get_object("listimportstg")
            # Fill the list of possible storage to import the VM, returns default storage position
            defstg = self.xc_servers[host].fill_importstg(listimportstg)
            treeimportstg = self.builder.get_object("treeimportstg")
            # Select the "default storage"
            treeimportstg.set_cursor((defstg, ), treeimportstg.get_column(0))
            treeimportstg.get_selection().select_path((defstg, ))
            listimportnetworks = self.builder.get_object("listimportnetworks")
            listimportnetworkcolumn = self.builder.get_object("listimportnetworkcolumn")
            # Fill the list the networks with option "automatically add to new servers"
            self.xc_servers[host].fill_list_networks(listimportnetworks, listimportnetworkcolumn)
            # If page is the third, button is called "Import >"
            widget.set_label("Import >")
        else:
            # If next page is different to third, the button is called "Next >"
            widget.set_label("Next >")
        if page+1 == 3:
            # If page is the fourth..
            filename = self.builder.get_object("filechooserimportvm").get_filename()
            treeimportservers = self.builder.get_object("treeimportservers")
            listimportservers = self.builder.get_object("listimportservers")
            selection = treeimportservers.get_selection()
            # Get selected host
            host = listimportservers.get_value(selection.get_selected()[1], 3)
            treeimportstg = self.builder.get_object("treeimportstg")
            listimportstg = self.builder.get_object("listimportstg")
            selection = treeimportstg.get_selection()
            # Get selected storage
            sr = listimportstg.get_value(selection.get_selected()[1], 1)
            self.xc_servers[host].halt_import = False
            # Show a progress with import progerss
            self.builder.get_object("wprogressimportvm").show()
            # And begin to import the VM
            self.xc_servers[host].thread_import_vm(sr, filename)
        if page+1 == 4:
            # If page is the last..
            widget.set_sensitive(False)
            # Then enable "finish" button
            self.builder.get_object("finishvmimport").set_sensitive(True)
    def on_previousvmimport_clicked(self, widget, data=None):
        """"
        Function called when you press "< Previous" button
        """
        page = self.builder.get_object("tabboximport").get_current_page()
        # Move to previous tab
        self.builder.get_object("tabboximport").set_current_page(page-1)
        # And set next button with correct label
        self.builder.get_object("nextvmimport").set_label("Next >")

    def on_cancelvmimport_clicked(self, widget, data=None):
        """
        Function called when you cancel the import vm process
        """
        treeimportservers = self.builder.get_object("treeimportservers")
        listimportservers = self.builder.get_object("listimportservers")
        selection = treeimportservers.get_selection()
        if selection.get_selected()[1]:
            # Get the selected host
            host = listimportservers.get_value(selection.get_selected()[1], 3)
            # Stop the import
            self.xc_servers[host].halt_import = False
        # hide the window
        self.builder.get_object("vmimport").hide()
    def on_finishvmimport_clicked(self, widget, data=None):
        """
        Function called when you press the "Finish" button
        """
        treeimportservers = self.builder.get_object("treeimportservers")
        listimportservers = self.builder.get_object("listimportservers")
        selection = treeimportservers.get_selection()
        host = listimportservers.get_value(selection.get_selected()[1], 3)
        vif_cfg = {
            'name': 'API_VIF',
            'type': 'ioemu',
            'device': '0',
            'network': '',
            'MAC': '',
            'MTU': '0',
            "qos_algorithm_type":   "ratelimit",
            "qos_algorithm_params": {},
            "other_config":         {}
        }

        selection = self.builder.get_object("treeimportnetworks").get_selection()
        selection.set_mode(gtk.SELECTION_MULTIPLE)
        selection.select_all()
        model, selected = selection.get_selected_rows()
        iters = [model.get_iter(path) for path in selected]
        # For each network... 
        for iter in iters:
            network = self.builder.get_object("listimportnetworks").get_value(iter, 3)
            vm  = self.xc_servers[host].import_ref
            # Add to new imported VM
            self.xc_servers[host].vm_add_interface(vm, network, None, "0")
            # Sleep 1 second between action
            time.sleep(1)
        # Set if "file is a imported template" or/and "start after import"
        self.xc_servers[host].import_start = self.builder.get_object("checkstartvmafterimport").get_active()
        self.xc_servers[host].import_make_into_template = self.builder.get_object("radioexportedtpl").get_active()
        # Hide the window
        selection.set_mode(gtk.SELECTION_SINGLE)
        self.builder.get_object("vmimport").hide()
 
    def on_networkcolumn1_changed(self, widget, data=None, data2=None):
        """
        Function called when you change the network combo for selected interface
        """
        treeimportnetworks = self.builder.get_object("treeimportnetworks")
        listimportnetworks = self.builder.get_object("listimportnetworks")
        listnetworkcolumn = self.builder.get_object("listimportnetworkcolumn")
        selection = treeimportnetworks.get_selection()
        iter = selection.get_selected()[1]
        listimportnetworks.set_value(iter, 2,
             listnetworkcolumn.get_value(data2, 0))
        listimportnetworks.set_value(iter, 3,
             listnetworkcolumn.get_value(data2, 1))                                                                 
    def on_radiofastclone_toggled(self, widget, data=None):
        """
        Function called when you toggle "fast clone" or "full clone"
        """
        if widget.get_active():
            if gtk.Buildable.get_name(widget) == "radiofastclone":
                self.builder.get_object("treecopystg").set_sensitive(False)
            else:
                self.builder.get_object("treecopystg").set_sensitive(True)