# -*- coding: utf-8 -*-

###########################################################################
#    Copyright (C) 2004 by Wido Depping
#    <widod@users.sourceforge.net>
#
# Copyright: See COPYING file that comes with this distribution
#
###########################################################################

from qt import *
import os.path
import ldap
import string

import environment
from plugins.usermanagement.UsermanagementWidgetDesign import UsermanagementWidgetDesign
from plugins.usermanagement.NameDialog import NameDialog
from plugins.usermanagement.GroupWizard import GroupWizard
from base.backend.LumaConnection import LumaConnection
from base.utils.gui.PasswordDialog import PasswordDialog
from base.utils.gui.MailDialog import MailDialog
from plugins.usermanagement.GroupDialog import GroupDialog
from base.utils.gui.LumaErrorDialog import LumaErrorDialog

from sets import Set



class UsermanagementWidget(UsermanagementWidgetDesign):

    def __init__(self,parent = None,name = None,fl = 0):
        UsermanagementWidgetDesign.__init__(self,parent,name,fl)
        
        iconDir = os.path.join (environment.lumaInstallationPrefix, "share", "luma", "icons", "plugins", "usermanagement")
        lumaIconPath = os.path.join (environment.lumaInstallationPrefix, "share", "luma", "icons")

        accountPixmap = QPixmap(os.path.join(iconDir, "entry.png"))
        groupPixmap = QPixmap(os.path.join(iconDir, "group.png"))
        shellPixmap = QPixmap(os.path.join(iconDir, "shell.png"))
        homePixmap = QPixmap(os.path.join(iconDir, "home.png"))
        passwordPixmap = QPixmap(os.path.join(iconDir, "password.png"))
        mailPixmap = QPixmap(os.path.join(iconDir, "email.png"))
        self.savePixmap = QPixmap(os.path.join(lumaIconPath, "save.png"))
        deletePixmap = QPixmap(os.path.join(lumaIconPath, "editdelete.png"))
        
        self.accountLabel.setPixmap(accountPixmap)
        self.groupLabel.setPixmap(groupPixmap)
        self.shellLabel.setPixmap(shellPixmap)
        self.homeLabel.setPixmap(homePixmap)
        self.passwordLabel.setPixmap(passwordPixmap)
        self.mailLabel.setPixmap(mailPixmap)
        

        self.otherGroups = {}
        
        self.ENABLED = False
        self.dataObject = None
        self.enableWidget()
        
        self.EDITED = False
        self.ENABLEDELETE = True
        
        # Indicates if were are creating a new entry.
        self.NEWENTRY = False
        
        # a list of user ids which are stored in the ldap tree
        self.usedUserIds = None
        
        
        

###############################################################################

    def initView(self, dataObject):
        self.dataObject = dataObject
        
        self.ENABLED = True
        self.EDITED = False
        self.usedUserIds = None
        
        self.enableWidget()
        self.displayValues()
        
###############################################################################

    def enableWidget(self):
        blapp = self
        if self.ENABLED:
            self.setEnabled(True)
            
            self.expireEdit.setEnabled(self.dataObject.hasObjectClass('shadowAccount'))
            
            posixBool = self.dataObject.hasObjectClass('posixAccount')
            self.uidEdit.setEnabled(posixBool)
            self.uidBox.setEnabled(posixBool)
            self.nameEdit.setEnabled(posixBool)
            self.groupNumberEdit.setEnabled(posixBool)
            self.addGroupButton.setEnabled(posixBool)
            self.shellEdit.setEnabled(posixBool)
            self.homeEdit.setEnabled(posixBool)
            self.passwordEdit.setEnabled(posixBool)
            self.passwordButton.setEnabled(posixBool)
        
            inetOrgBool = self.dataObject.hasObjectClass('inetOrgPerson') or self.dataObject.hasAttribute('mail')
            self.mailBox.setEnabled(inetOrgBool)
            self.deleteMailButton.setEnabled(inetOrgBool)
            self.addMailButton.setEnabled(inetOrgBool)
        else:
            self.setEnabled(False)
        
        
        
###############################################################################

    def serverChanged(self):
        self.ENABLED = False
        self.enableWidget()
        self.clearValues()
        self.usedUserIds = None
        
###############################################################################

    def displayValues(self):
        self.uidEdit.blockSignals(True)
        if self.dataObject.hasAttribute('uid'):
            value = self.dataObject.getAttributeValue('uid', 0)
            self.uidEdit.setText(value)
        else:
            self.uidEdit.setText("")
        self.uidEdit.blockSignals(False)
        
        
        self.uidBox.blockSignals(True)
        if self.dataObject.hasAttribute('uidNumber'):
            value = int(self.dataObject.getAttributeValue('uidNumber',0))
            self.uidBox.setValue(value)
        else:
            # FIXME
            # Make it configurable how to generate a uidNumber..
            self.uidBox.setValue(self.nextFreeUserID())
            # 1: Manual - always
            # 2: Using the nextFreeUserID-method
            # 3: Using a ldap-object to store the next userid to use (might get race-conditions)
        self.uidBox.blockSignals(False)
        
        
        self.nameEdit.blockSignals(True)
        if self.dataObject.hasAttribute('cn'):
            value = self.dataObject.getAttributeValue('cn', 0)
            self.nameEdit.setText(value)
        else:
            self.nameEdit.setText("")
        self.nameEdit.blockSignals(False)
        
        
        self.expireEdit.blockSignals(True)
        if self.dataObject.hasAttribute('shadowExpire'):
            days = int(self.dataObject.getAttributeValue('shadowExpire',0))
            date = QDate(1970, 1, 1)
            date = date.addDays(days)
            self.expireEdit.setDate(date)
        else:
            self.expireEdit.setDate(QDate(0, 0, 0))
        self.expireEdit.blockSignals(False)
           
          
        self.shellEdit.blockSignals(True)
        if self.dataObject.hasAttribute('loginShell'):
            value = self.dataObject.getAttributeValue('loginShell', 0)
            self.shellEdit.setText(value)
        else:
            self.shellEdit.setText("")
        self.shellEdit.blockSignals(False)
            
            
        self.homeEdit.blockSignals(True)
        if self.dataObject.hasAttribute('homeDirectory'):
            value = self.dataObject.getAttributeValue('homeDirectory', 0)
            self.homeEdit.setText(value)
        else:
            self.homeEdit.setText("")
        self.homeEdit.blockSignals(False)


        self.passwordEdit.blockSignals(True)
        if self.dataObject.hasAttribute('userPassword'):
            value = self.dataObject.getAttributeValue('userPassword', 0)
            self.passwordEdit.setText(value)
        else:
            self.passwordEdit.setText("")
        self.passwordEdit.blockSignals(False)
            
        self.displayGroupInfo()
        self.displayMailInfo()
        
        self.enableToolBar()
            
###############################################################################

    def clearValues(self):
        pass

###############################################################################

    def displayGroupInfo(self):
        print "displayGroupInfo"
        self.groupNumberEdit.blockSignals(True)
        
        if self.dataObject.hasAttribute('gidNumber'):
            value = self.dataObject.getAttributeValue('gidNumber', 0)
            self.groupNumberEdit.setText(value)
            self.groupNumberEdit.blockSignals(False)
            
            connectionObject = LumaConnection(self.dataObject.getServerMeta())
            bindSuccess, exceptionObject = connectionObject.bind()
            
            if not bindSuccess:
                dialog = LumaErrorDialog()
                errorMsg = self.trUtf8("Could not bind to server.<br><br>Reason: ")
                errorMsg.append(str(exceptionObject))
                dialog.setErrorMessage(errorMsg)
                dialog.exec_loop()
                self.groupNumberEdit.blockSignals(False)
                return
            
            filter = "(&(objectClass=posixGroup)(gidNumber=" + self.dataObject.getAttributeValue('gidNumber', 0) + "))"
            success, resultList, exceptionObject = connectionObject.search(self.dataObject.getServerMeta().currentBase, 
                        ldap.SCOPE_SUBTREE, filter)
            
            if success:
                if len(resultList) > 0:
                    groupName = ''
                    tmpObject = resultList[0]
                    if tmpObject.hasAttribute('cn'):
                        groupName = tmpObject.getAttributeValue('cn', 0)
                    self.groupEdit.setText(groupName)
            else:
                self.groupEdit.setText("")
                
        else:
            self.groupNumberEdit.setText("")
            self.groupEdit.setText("")
            
        self.groupNumberEdit.blockSignals(False)
            
            
        
###############################################################################
    
    def displayMailInfo(self):
        self.mailBox.clear()
        
        self.mailBox.blockSignals(True)
        
        if self.dataObject.hasAttribute('mail'):
            tmpList = self.dataObject.getAttributeValueList('mail')
            tmpList.sort()
            map(self.mailBox.insertItem, tmpList)
                
        self.mailBox.blockSignals(False)
            
###############################################################################

    def editPassword(self):
        dialog = PasswordDialog()
        dialog.exec_loop()
        
        if dialog.result() == 1:
            passwordHash = dialog.passwordHash
            if self.dataObject.isAttributeAllowed("userPassword"):
                self.dataObject.addAttributeValue('userPassword', [passwordHash], True)
            
            self.EDITED = True
            self.displayValues()
            
###############################################################################

    def deleteMail(self):
        if not self.dataObject.hasAttribute('mail'):
            return
            
        mail = unicode(self.mailBox.currentText())
        position = self.dataObject.getAttributeValueList('mail').index(mail)
        self.dataObject.deleteAttributeValue('mail', position)
        
        self.EDITED = True
        self.displayValues()

###############################################################################
    def addMail(self):
        dialog = MailDialog()
        dialog.exec_loop()
        
        if (dialog.result() == QDialog.Accepted):
            mail = unicode(dialog.mailEdit.text()).strip().encode("utf-8")
            
            if mail == '':
                return
                
            if self.dataObject.isAttributeAllowed('mail'):
                if self.dataObject.hasAttribute('mail'):
                    # We only want to have each email address one time.
                    if not (mail in self.dataObject.getAttributeValueList('mail')):
                        self.dataObject.addAttributeValue('mail', [mail])
                else:
                    self.dataObject.addAttributeValue('mail', [mail])
                
            self.EDITED = True
            self.displayValues()
                
###############################################################################

    def addGroup(self):
        print "addGroup"
        dialog = GroupWizard()
        #dialog.serverMeta = self.dataObject.getServerMeta()
        #dialog.userName = self.dataObject.getAttributeValue('uid', 0)
        #dialog.retrieveGroups()

        dialog.show()
        dialog.exec_loop()

###############################################################################


    def editGroups(self):
        print "editGroups"
        dialog = GroupDialog()
        dialog.serverMeta = self.dataObject.getServerMeta()
        dialog.userName = self.dataObject.getAttributeValue('uid', 0)
        dialog.retrieveGroups()
        
        if self.dataObject.hasAttribute("gidNumber"):
            value = int(self.dataObject.getAttributeValue('gidNumber', 0))
            dialog.groupNumberBox.setValue(value)
        dialog.exec_loop()
        
        if (dialog.result() == QDialog.Accepted):
            gid = str(dialog.groupNumberBox.value())
            if self.dataObject.isAttributeAllowed('gidNumber'):
                self.dataObject.addAttributeValue('gidNumber', [gid], True)
            
            self.otherGroups = {}
            
            listIterator = QListViewItemIterator(dialog.groupView)
            while listIterator.current():
                item = listIterator.current()
                self.otherGroups[unicode(item.text(2))] = item.isOn()
                
                listIterator += 1
            
            self.EDITED = True
            self.displayValues()

###############################################################################

    def enableToolBar(self):
        if not self.NEWENTRY:
            self.saveButton.setEnabled(self.EDITED)
        
###############################################################################

    def homeChanged(self, newHome):
        newHome = unicode(newHome)
        
        if self.dataObject.isAttributeAllowed('homeDirectory'):
            self.dataObject.addAttributeValue('homeDirectory', [newHome], True)
            
        self.EDITED = True
        self.enableToolBar()
      
###############################################################################

        
    def shellChanged(self, newShell):
        newShell = unicode(newShell)
        
        if self.dataObject.isAttributeAllowed('loginShell'):
            self.dataObject.addAttributeValue('loginShell', [newShell], True)
            
        self.EDITED = True
        self.enableToolBar()
    
###############################################################################
        
    def expireChanged(self, newDate):
        newExpire = str(QDate(1970, 1, 1).daysTo(newDate))
        
        if self.dataObject.isAttributeAllowed('shadowExpire'):
            self.dataObject.addAttributeValue('shadowExpire', [newExpire], True)
        
        self.EDITED = True
        self.enableToolBar()
        
###############################################################################
        
    def commonNameChanged(self, newName):
        newName = unicode(newName)
        
        if self.dataObject.isAttributeAllowed('cn'):
            self.dataObject.addAttributeValue('cn', [newName], True)
            if self.dataObject.isAttributeAllowed('gecos'):
                try:
                    self.dataObject.addAttributeValue('gecos', [newName.encode('us-ascii')], True)
                except UnicodeEncodeError, e:
                    tmpName = ""
                    for x in newName:
                        if x in string.ascii_letters:
                            tmpName = tmpName + x
                            
                    self.dataObject.addAttributeValue('gecos', [tmpName], True)
            
        self.EDITED = True
        self.enableToolBar()
    
###############################################################################

    def uidChanged(self, newID):
        newID= unicode(newID)
        
        if self.dataObject.isAttributeAllowed('uidNumber'):
            self.dataObject.addAttributeValue('uidNumber', [newID], True)
            
        self.EDITED = True
        self.enableToolBar()
        
###############################################################################

    def uidNameChanged(self, newName):
        newName= unicode(newName)
        
        if self.dataObject.isAttributeAllowed('uid'):
            self.dataObject.addAttributeValue('uid', [newName], True)
            
        self.EDITED = True
        self.enableToolBar()

###############################################################################

    def saveAccount(self):
        print "saveAccount"
        connectionObject = LumaConnection(self.dataObject.getServerMeta())
        bindSuccess, exceptionObject = connectionObject.bind()
        
        if not bindSuccess:
                dialog = LumaErrorDialog()
                errorMsg = self.trUtf8("Could not bind to server.<br><br>Reason: ")
                errorMsg.append(str(exceptionObject))
                dialog.setErrorMessage(errorMsg)
                dialog.exec_loop()
                return 
                
        success, exceptionObject = connectionObject.updateDataObject(self.dataObject)
        connectionObject.unbind()
        
        if success:
            self.saveOtherGroups()

            self.EDITED = False
            self.enableToolBar()
            self.usedUserIds = None
            self.emit(PYSIGNAL("account_saved"), ())
        else:
            dialog = LumaErrorDialog()
            errorMsg = self.trUtf8("Could not save entry.<br><br>Reason: ")
            errorMsg.append(str(exceptionObject))
            dialog.setErrorMessage(errorMsg)
            dialog.exec_loop()
        
###############################################################################

    def saveOtherGroups(self):
        print "saveOtherGroups"
        connectionObject = LumaConnection(self.dataObject.getServerMeta())
        bindSuccess, exceptionObject = connectionObject.bind()
        
        if not bindSuccess:
                dialog = LumaErrorDialog()
                errorMsg = self.trUtf8("Could not bind to server.<br><br>Reason: ")
                errorMsg.append(str(exceptionObject))
                dialog.setErrorMessage(errorMsg)
                dialog.exec_loop()
                return 
    
        groupUpdateSuccess = True
        failureException = None
        userName = self.dataObject.getAttributeValue('uid', 0)
        
        for x in self.otherGroups.keys():
            success, resultList, exceptionObject = connectionObject.search(x)
            
            if success:
                if len(resultList) > 0:
                    tmpObject = resultList[0]
            
                    if tmpObject.hasAttribute("memberUid"):
                        if userName in tmpObject.getAttributeValueList("memberUid"):
                            if not(self.otherGroups[x]):
                                index = tmpObject.getAttributeValueList("memberUid").index(userName)
                                tmpObject.deleteAttributeValue('memberUid', index)
                        else:
                            if self.otherGroups[x]:
                                tmpObject.addAttributeValue('memberUid', [userName])
                    else:
                        if self.otherGroups[x]:
                            tmpObject.addAttributeValue("memberUid", [userName])
                        
            
                    updateSuccess, exceptionObject = connectionObject.updateDataObject(tmpObject)
            
                    if not updateSuccess:
                        groupUpdateSuccess = False
                        failureException = exceptionObject
                    
            else:
                groupUpdateSuccess = False
                failureException = exceptionObject
                    
                
        if not groupUpdateSuccess:
            dialog = LumaErrorDialog()
            errorMsg = self.trUtf8("Could not update all group information.<br><br>Reason: ")
            errorMsg.append(str(failureException))
            dialog.setErrorMessage(errorMsg)
            dialog.exec_loop()
        
        connectionObject.unbind()
        
        
###############################################################################

    def nextFreeUserID(self):
        if self.usedUserIds == None:
            result = self.retrieveUserIDs()
            if result == None:
                return
            else:
                self.usedUserIds = result
            
        uid = self.uidBox.value() + 1
        while uid in self.usedUserIds:
            uid = uid + 1
            
        self.uidBox.setValue(uid)
        
###############################################################################

    def retrieveUserIDs(self):
        connectionObject = LumaConnection(self.dataObject.getServerMeta())
        bindSuccess, exceptionObject = connectionObject.bind()
        
        if not bindSuccess:
                dialog = LumaErrorDialog()
                errorMsg = self.trUtf8("Could not bind to server.<br><br>Reason: ")
                errorMsg.append(str(exceptionObject))
                dialog.setErrorMessage(errorMsg)
                dialog.exec_loop()
                return []
        
        success, resultList, exceptionObject = connectionObject.search(self.dataObject.getServerMeta().currentBase, ldap.SCOPE_SUBTREE,
                "(&(objectClass=*)(uidNumber=*))", ["uidNumber"], 0)
        connectionObject.unbind()
        
        if success:
            uidList = []
            for x in resultList:
                for y in x.getAttributeValueList("uidNumber"):
                    uidList.append(int(y))
            
            return uidList
        else:
            dialog = LumaErrorDialog()
            errorMsg = self.trUtf8("Could not retrieve used userids.<br><br>Reason: ")
            errorMsg.append(str(exceptionObject))
            dialog.setErrorMessage(errorMsg)
            dialog.exec_loop()
            
            return []
    
###############################################################################

    def aboutToChange(self):
        """Is called as a slot when new data arrives. 
        
        This way we are able to save the changed values.
        """
    
        if not self.EDITED:
            return
            
        value =QMessageBox.question(None,
            self.trUtf8("Save entry"),
            self.trUtf8("""The account has been modified. Do you want to save it?"""),
            self.trUtf8("&Yes"),
            self.trUtf8("&No"),
            None,
            0, -1)
            
        # button order says, that 'yes' is zero
        if value == 0:
            self.saveAccount()
        
###############################################################################

    def buildToolBar(self, parent):
        toolBar = QToolBar(parent)
    
        self.saveButton = QToolButton(toolBar, "saveValues")
        self.saveButton.setIconSet(QIconSet(self.savePixmap))
        self.saveButton.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.saveButton.setAutoRaise(True)
        self.saveButton.setBackgroundMode(self.backgroundMode())
        QToolTip.add(self.saveButton, self.trUtf8("Save"))
        self.connect(self.saveButton, SIGNAL("clicked()"), self.saveAccount)
    
        self.enableToolBar()
