import gettext
import gnome
import Zone
from Zone import TestError
#import gnome.ui
import gtk
from gtk import FALSE
from gtk import TRUE
from copy import copy
import string
import os
#Columns for "a_treeview"
COLUMN_PIXBUF=0
COLUMN_TEXT=1
COLUMN_MAIL_XCHANGE=1
COLUMN_DATA=2
COLUMN_TEXT2=3
COLUMN_PRIORITY=3
COLUMN_HASH=4

##
## I18N stuff
##
PROGNAME="system-config-bind"
bindconf_dir = '/usr/share/'+PROGNAME

_=gettext.gettext
gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
gettext.textdomain(PROGNAME)


def add_dot (str):
    try:
        if str[-1] == '.':
            return str
        return str + '.'
    except:
        return ""

#Columns for "bindconf_treeview"
COLUMN_PIXBUF=0
COLUMN_TEXT=1
COLUMN_DATA=2

#columns for "rev_zone_treeview", "fwd_zone_treeview"
COLUMN_TEXT2=3
COLUMN_HASH=4

def verify_delete(arg):
    message=_("Are you sure you want to delete the %s?") % arg
    dlg = gtk.MessageDialog(None, 0, gtk.MESSAGE_INFO,
                            gtk.BUTTONS_YES_NO,
                            message)
    dlg.set_position(gtk.WIN_POS_MOUSE)
    dlg.show_all()
    rc = dlg.run()
    dlg.destroy()
    return rc

def load_image(filename):
    if not os.path.exists(filename):
        filename = bindconf_dir + "/" + filename
    return gtk.gdk.pixbuf_new_from_file(filename)

image_a = load_image("address.png")
image_cname = load_image("cname.png")
image_ns = load_image("domain.png")
image_mx = load_image("mail.png")

def generic_error_dialog (message, parent_dialog, dialog_type=gtk.MESSAGE_WARNING, widget=None, page=0, broken_widget=None):
    dialog = gtk.MessageDialog (parent_dialog,
                                gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
                                dialog_type,
                                gtk.BUTTONS_OK,
                                message)
    dialog.set_position(gtk.WIN_POS_MOUSE)
    if widget != None:
        if isinstance (widget, gtk.CList):
            widget.select_row (page, 0)
        elif isinstance (widget, gtk.Notebook):
            widget.set_page (page)

    if broken_widget != None:
        broken_widget.grab_focus ()
#        if isinstance (broken_widget, gtk.Entry):
            ##FIXME: supposedly deprecated?
#            broken_widget.select_region (0, -1)
    dialog.run ()
    dialog.destroy ()

class AProxy:
    ORDER='B'
    def __init__ (self, a=None):
        if a:
            self.host = a.getHost ()
            self.ip = a.getIp ()

    def get_str (self):
        return self.host + '->' + self.ip

    def get_hash (self):
        return AProxy.ORDER + self.host

    def get_pix (self):
        return image_a

    def run_edit_dialog (self, fwdzone, xml,parent):
        dialog = xml.get_widget ('a_dialog')
        dialog.set_transient_for (parent)
        host_entry = xml.get_widget ('a_host_entry')
        ip_entry = xml.get_widget ('a_ip_entry')
        label = xml.get_widget ('a_dialog_label')

        host_entry.set_text (self.host)
        ip_entry.set_text (self.ip)
        host_entry.grab_focus ()
        label.set_text ('.' + fwdzone.name)

        while 1:
            button = dialog.run ()
            if button != gtk.RESPONSE_OK:
                dialog.hide ()
                return button

            host = host_entry.get_text ()
            ip = ip_entry.get_text ()

            try:
                brw = host_entry
                Zone.testHost(host)
                brw = ip_entry
                Zone.testIp(ip)
                
            except TestError, e:
                generic_error_dialog (e.args, dialog, broken_widget=brw)
                continue

            dialog.hide ()
            break

        self.host = host
        self.ip = ip

        return button

    def check(self):
        Zone.testHost(self.host)
        Zone.testIp(self.ip)

class CNAMEProxy:
    ORDER='C'
    def __init__ (self, cname=None):
        if cname:
            self.alias = cname.getAlias ()
            self.host = cname.getHost ()

    def get_str (self):
        return _("%s aliased to %s") % (self.host,self.alias)

    def get_hash (self):
        return CNAMEProxy.ORDER + self.alias

    def get_pix (self):
        return image_cname

    def run_edit_dialog (self, fwdzone, xml, parent):
        dialog = xml.get_widget ('cname_dialog')
        dialog.set_transient_for (parent)
        cname_treeview = xml.get_widget ('cname_treeview')
        cname_model = cname_treeview.get_model()
        cname_model.clear()
        zlist = fwdzone.zone.getAList()
        seliter=None
        for z in zlist:
            name=z.getName()+ "." + fwdzone.name + "."
            iter = cname_model.append()
            if self.host == name:
                seliter=iter
            cname_model.set (iter,
                             COLUMN_PIXBUF, image_a,
                             COLUMN_TEXT, name)

        if seliter!= None:
            cname_treeview.get_selection ().select_iter (seliter)
            path = cname_model.get_path (seliter)
            cname_treeview.scroll_to_cell(path,None,FALSE,0,0)
        alias_entry = xml.get_widget ('cname_alias_entry')
        label = xml.get_widget ('cname_label')

        alias_entry.set_text (self.alias)
        alias_entry.grab_focus ()
        label.set_text ('.' + fwdzone.name)

        while 1:
            button = dialog.run ()
            if button != gtk.RESPONSE_OK:
                dialog.hide ()
                return button
            host = ""
            selected = cname_treeview.get_selection().get_selected ()
            if selected != None:
                (model, iter) = selected
                if iter != None:
                    host = model.get_value (iter, COLUMN_TEXT)

            alias = alias_entry.get_text ()

            if host == "":
                generic_error_dialog (_("You must select a host name."), dialog)
                continue
            if alias == "":
                generic_error_dialog (_("You must enter an alias."), dialog, broken_widget=alias_entry)
                continue

            try:
                brw = alias_entry
                Zone.testHost(alias)
            except TestError, e:
                generic_error_dialog (e.args, dialog, broken_widget=brw)
                continue

            try:
                for cname in fwdzone.cname:
                    if cname == self:
                        continue
                    if cname.alias == alias:
                        raise 'Duplicate'
            except 'Duplicate':
                generic_error_dialog (_("An alias with this name already exists."), dialog, broken_widget=alias_entry)
                continue
            dialog.hide ()
            break
        self.host = host
        self.alias = alias
        return button

    def check(self):
        Zone.testHost(self.alias)

class MXProxy:
    ORDER='D'
    def __init__ (self, mx=None):
        if mx:
            self.name = mx.getName()
            self.priority = mx.getPriority ()
            self.server = mx.getServer ()
        else:
            self.server = "@"
            self.name = ""
            self.priority = ""
            self.server = ""

    def get_str (self):
        return _("%s->Mail Server: %s Priority: %d") % (self.name,self.server,self.priority)

    def get_hash (self):
        return MXProxy.ORDER + self.name

    def getName (self):
        return self.name

    def get_priority_hash (self):
        str = "%8d" % self.priority
        return re.sub (' ', '0', str) + self.name

    def get_pix (self):
        return image_mx

    def run_edit_dialog (self, fwdzone, xml, parent, name=None):
        return self.run_dialog (fwdzone, xml, parent, name, TRUE)

    def run_add_dialog (self, fwdzone, xml, parent, name=None):
        return self.run_dialog (fwdzone, xml,parent, name, FALSE)

    def run_dialog (self, fwdzone, xml, parent,name, edit):
        dialog = xml.get_widget ('mx_dialog')
        dialog.set_transient_for (parent)
        host_entry = xml.get_widget ('mx_host_entry')
        priority_entry = xml.get_widget ('mx_priority_entry')
        treeview = xml.get_widget ('mx_treeview')
        model = treeview.get_model()
        model.clear()
        zlist = fwdzone.zone.getAList()
        seliter=None
        for z in zlist:
            name=z.getName()+ "." + fwdzone.name + "."
            iter = model.append()
            if self.server == name:
                seliter=iter
            model.set (iter,
                       COLUMN_PIXBUF, image_a,
                       COLUMN_TEXT, name)
        if seliter!= None:
            treeview.get_selection ().select_iter (seliter)
            path = model.get_path (seliter)
            treeview.scroll_to_cell(path,None,FALSE,0,0)

        host_entry.set_text (self.name)
        priority_entry.set_value (self.priority)
        dialog.set_title (_("Edit Mail Exchanger"))

        host_entry.grab_focus ()

        while 1:
            button = dialog.run ()
            if button != gtk.RESPONSE_OK:
                dialog.hide ()
                return button
            name = host_entry.get_text ()
            priority = priority_entry.get_text ()
            selected = treeview.get_selection().get_selected ()
            if selected != None:
                (model, iter) = selected
                if iter != None:
                    server = model.get_value (iter, COLUMN_TEXT)
            if name == "":
                generic_error_dialog (_("You must enter a host name."), dialog, broken_widget=host_entry)
                continue
            if priority == "":
                generic_error_dialog (_("You must enter an priority."), dialog, broken_widget=priority_entry)
                continue

            dialog.hide ()
            break
        self.name = name
        self.priority = int (priority)
        self.server = server
        return button
    def check(self):
        Zone.testHost(self.name)

class NSProxy:
    ORDER = 'Z'
    def __init__ (self, ns=None):
        if ns:
            self.host = ns.getHost ()
            self.served_by = ns.getServedBy ()
        else:
            self.host=""
            self.served_by = ""

    def get_str (self):
        return _("%s served by %s") % (str(self.host),str(self.served_by))

    def getHost (self):
        return self.host
    
    def get_hash (self):
        return NSProxy.ORDER + self.host

    def get_pix (self):
        return image_ns

    def run_dialog (self, name, xml, edit, zone, parent, full_ns_host = FALSE):
        dialog = xml.get_widget ('ns_dialog')
        dialog.set_transient_for (parent)
        host_entry = xml.get_widget ('ns_host_entry')
        served_by_entry = xml.get_widget ('ns_applies_to_entry')
        label = xml.get_widget ('ns_label')

        if edit:
            host_entry.set_text (self.host)
            served_by_entry.set_text (self.served_by)
        else:
            host_entry.set_text ('')
            served_by_entry.set_text ('')
        host_entry.grab_focus ()
        if zone:
            served_by_entry.hide ()
            label.set_text (name)
        else:
            served_by_entry.show ()
            label.set_text ('.' + name)

        while 1:
            button = dialog.run ()
            if button != gtk.RESPONSE_OK:
                dialog.hide ()
                return button

            host = add_dot(host_entry.get_text ())
            served_by = served_by_entry.get_text ()

            if host == "":
                generic_error_dialog (_("You must enter a host name."), dialog, broken_widget=host_entry)
                continue
            if served_by == "" and not zone:
                generic_error_dialog (_("You must enter a resolution address."), dialog, broken_widget=served_by_entry)
                continue

            try:
                brw = host_entry
                Zone.testHost(host)
                if full_ns_host and (not ((len(host) > 1) and host[-1] == '.')):
                    full_ns_host=full_ns_host+"."
                if not zone:
                    brw = served_by_entry
                    Zone.testServedBy(served_by)
            except TestError, e:
                generic_error_dialog (e.args, dialog, broken_widget=brw)
                continue

            dialog.hide ()
            break
        self.host = host

        if zone:
            self.served_by = '@'
        else:
            self.served_by = served_by
        return button

    def run_edit_dialog (self, fwdzone, xml, parent, zone=FALSE):
        return self.run_dialog (fwdzone.name, xml, TRUE, zone, parent)

    def run_add_dialog (self, fwdzone, xml, parent, zone=FALSE):
        return self.run_dialog (fwdzone.name, xml, FALSE, zone, parent)

    def check(self):
        Zone.testHost(self.host)
        Zone.testServedBy(self.served_by)

class FwdZone:
    ORDER='A'
    def __init__(self, zone, xml):
        self.zone = zone
        self.xml = xml
        self.hydrating = FALSE
        if not hasattr(self.zone, 'dirty'):
	    self.zone.dirty = FALSE
	self.dirty = self.zone.dirty

        #slurp from the zone
        soa = zone.getSOA ()

        self.name = zone.getName ()
        self.file = zone.getFile ()

        self.contact = soa.getContact ()
        self.serial = soa.getSerial ()
        self.refresh = soa.getRefresh ()
        self.retry = soa.getRetry ()
        self.expire = soa.getExpire ()
        self.minimum = soa.getTTL()
        self.pns = soa.getPNS()
        
        self.ns = []
        nslist = zone.getNSList ()
        for ns in nslist:
            proxy = NSProxy (ns)
            self.ns.append (proxy)

        self.mx = []
        mxlist = zone.getMXList ()
        for mx in mxlist:
            proxy = MXProxy (mx)
            self.mx.append (proxy)

        self.cname = []
        cnamelist = zone.getCNAMEList ()
        for cname in cnamelist:
            proxy = CNAMEProxy (cname)
            self.cname.append (proxy)

        self.a = []
        alist = zone.getAList ()
        for a in alist:
            proxy = AProxy (a)
            self.a.append (proxy)

    def get_str (self):
        return self.name

    def get_pix (self):
        return None

    def get_hash (self):
        return FwdZone.ORDER

    def getCNAMEProxy(self,alias):
        for cname in self.cname:
            if cname.alias == alias:
                return cname

    def getMXProxy(self,name):
        for mx in self.mx:
            if mx.name == name:
                return mx

    def hydrate (self):
        self.hydrating = TRUE
        xml = self.xml
        dialog = xml.get_widget ('fwd_master_dialog')
        name_entry = xml.get_widget ('fwd_zone_name_entry')
        contact_entry = xml.get_widget ('fwd_zone_contact_entry')
        serial_entry = xml.get_widget ('fwd_zone_serial_entry')
        tree_view = xml.get_widget ('fwd_zone_treeview')
        self.pns_entry = xml.get_widget ('fwd_zone_pns_entry')
        name_entry.set_text (self.name)
        contact_entry.set_text (self.contact)
        serial_entry.set_text (str (self.serial))
        self.pns_entry.set_text(self.pns)
        self.hydrating = FALSE

    def hydrate_soa (self):
        self.hydrating = TRUE
        xml = self.xml
        xml.get_widget ('soa_refresh_entry').set_text (str (self.refresh))
        xml.get_widget ('soa_retry_entry').set_text (str (self.retry))
        xml.get_widget ('soa_expire_entry').set_text (str (self.expire))
        xml.get_widget ('soa_minimum_entry').set_text (str (self.minimum))
        self.hydrating = FALSE

    def dehydrate_soa (self):
        xml = self.xml
        def my_int (str):
            try:
                i = int (str)
                return i
            except:
                return 0

        self.refresh = my_int (xml.get_widget ('soa_refresh_entry').get_text ())
        self.retry = my_int (xml.get_widget ('soa_retry_entry').get_text ())
        self.expire = my_int (xml.get_widget ('soa_expire_entry').get_text ())
        self.minimum = my_int (xml.get_widget ('soa_minimum_entry').get_text ())

    def set_dirty (self):
        if self.hydrating: return
        if self.dirty: return
        self.dirty = TRUE

    def set_name (self, name):
        xml = self.xml
        self.name = name
        self.set_dirty ()
        xml.get_widget ('fwd_zone_file_entry').set_text (self.file)

    def check(self):
        self.zone.testName(self.name)
        self.zone.testFile(self.file)
        #test_soa_values
        soa = self.zone.getSOA()
        soa.testPNS(self.pns_entry.get_text())
        if self.refresh < self.retry:
            raise TestError, _("SOA Refresh value should be bigger than Retry")
        soa.testSerial(self.serial)
        soa.testRefresh(self.refresh)
        soa.testRetry(self.retry)
        soa.testExpire(self.expire)
        soa.testTTL(self.minimum)

        #test_a_list
        for I in self.a:
            I.check()
        #test_ns_list
        for I in self.ns:
            I.check()
        #test_cname_list
        for I in self.cname:
            I.check()
        #test_mx_list
        for I in self.mx:
            I.check()
#        if len (self.ns) < 1:
#            raise TestError, _("Forward zone '%s' must list at least one nameserver record.\nUse \"Add ...\" button to add nameserver.") % self.name

    def dehydrate (self):
        for I in self.ns + self.mx + self.cname + self.a:
            if hasattr(I, 'dirty') and I.dirty:
                self.dirty = TRUE
        
	if self.dirty and not self.zone.dirty:
        	self.serial = self.serial+1
                self.zone.dirty = TRUE
	        self.xml.get_widget ('fwd_zone_serial_entry').set_text (str (self.serial))

        self.name = self.xml.get_widget ('fwd_zone_name_entry').get_text ()
        self.file = self.xml.get_widget ('fwd_zone_file_entry').get_text ()
        self.contact = self.xml.get_widget ('fwd_zone_contact_entry').get_text()
        self.pns = self.pns_entry.get_text()
        
        soa = self.zone.getSOA ()
        self.zone.setName (self.name)
        self.zone.setFile (self.file)
        soa.setContact (self.contact)
        soa.setSerial (self.serial)
        soa.setRefresh (self.refresh)
        soa.setRetry (self.retry)
        soa.setExpire (self.expire)
        soa.setTTL (self.minimum)
        soa.setPNS(self.pns)
        
#####
    def run_edit_dialog (self, fwdzone, xml,parent):
        dialog = xml.get_widget ('zone_dialog')
        dialog.set_transient_for (parent)
        entry = xml.get_widget ('zone_address_entry')

        dialog.set_title (_("Settings for %s") % self.name)

        tmp = ''
        first = TRUE
        for a in self.a:
            if a.host == '@':
                if first:
                    tmp = a.ip
                    first = FALSE
                else:
                    tmp = tmp + " " + a.ip
        entry.set_text (tmp)

        ns_tree_view = xml.get_widget ('zone_ns_treeview')
        ns_model = ns_tree_view.get_model()
        ns_model.clear ()
        for ns in self.ns:
            if ns.served_by != '@':
                continue
            iter = ns_model.append ()
            ns_model.set (iter,
                          COLUMN_PIXBUF,ns.get_pix (),
                          COLUMN_TEXT,ns.host,
                          COLUMN_TEXT2, '',
                          COLUMN_HASH, ns.get_hash(),
                          COLUMN_DATA,ns)

        tree_view = xml.get_widget ('zone_mx_treeview')
        model = tree_view.get_model()
        model.clear ()
        for mx in self.mx:
            if mx.served_by != '@':
                continue
            iter = model.append ()
            model.set (iter,
                       COLUMN_PIXBUF,mx.get_pix (),
                       COLUMN_MAIL_XCHANGE,mx.getHost(),
                       COLUMN_PRIORITY, str (mx.priority),
                       COLUMN_HASH, mx.get_priority_hash(),
                       COLUMN_DATA,mx)

        while 1:
            button = dialog.run ()
            if button != gtk.RESPONSE_OK:
                dialog.hide ()
                return button
            #FIXME: put checks in here.
            break

        dialog.hide ()

        dellist = []
        for ns in self.ns:
            if ns.served_by == '@':
                dellist.append (ns)

        for ns in dellist:
            self.ns.remove (ns)

        dellist = []
        for a in self.a:
            if a.host == '@':
                dellist.append (a)

        for a in dellist:
            self.a.remove (a)

        dellist = []
        for mx in self.mx:
            if mx.served_by == '@':
                dellist.append (mx)

        for mx in dellist:
            self.mx.remove (mx)

        ns_tree_view = xml.get_widget ('zone_ns_treeview')
        ns_model = ns_tree_view.get_model ()
        iter = ns_model.get_iter_first ()
        def foreach_ns_func (model, path, iter, text):
            ns = model.get_value (iter, COLUMN_DATA)
            ns.served_by = '@'
            fwdzone.ns.append (ns)

        ns_model.foreach (foreach_ns_func, None)

        tree_view = xml.get_widget ('zone_mx_treeview')

        tmp = entry.get_text ()
        list = string.split (tmp, " ")
        for i in list:
            if len(i):
                a = AProxy ()
                a.host = '@'
                a.ip = i
                fwdzone.a.append (a)

        return button
