# Copyright (c) 2005 Infrae. All rights reserved.
# See also LICENSE.txt
from zope.app import zapi
from zope.app.pagetemplate import ViewPageTemplateFile
from zope.app.component.hooks import getSite
from zope.app.intid.interfaces import IIntIds
from zope.app.publisher.browser.menu import getMenu
from zope.app.form.interfaces import ConversionError

from zope.formlib import form

from documentlibrary.core import interfaces, user
from documentlibrary.core.browser.form import FormMixin, DO_NOT_RENDER
from documentlibrary.core.browser import widgets

class ItemListPage(form.PageForm, FormMixin):
    
    form_fields = () # no fields, only actions
    
    def items(self):
        items = self._getItems()
        sort_names = list(items.keys())
        sort_names.sort()
        intid = zapi.getUtility(IIntIds)
        for name in sort_names:
            item = items[name]
            yield {'id': intid.getId(item), 'value': item}

    def _selectedItems(self):
        form = self.request.form
        # the checkboxes' name
        ids = form.get(self.prefix + '.ids', [])
        ids = [int(id) for id in ids] # handle non-int input better?
        intid = zapi.getUtility(IIntIds)
        return [intid.getObject(id) for id in ids]
    
    @form.action('delete')
    def handleDelete(self, action, data):
        items = self._selectedItems()
        parent = self.__parent__
        names = []
        for item in items:
            names.append(item.__name__)
            del parent[item.__name__]
        if not items:
            self.addError('No items deleted as none selected')
        else:
            self.addFeedback('Items deleted: %s' % ', '.join(names))
            
class UserListPage(ItemListPage):
    
    label = u'users list'
    
    template = ViewPageTemplateFile('templates/users.pt')
    
    prefix = 'user.listing'
    
    def _getItems(self):
        return getSite()['users']

    def getMenu(self):
        return getMenu('user_menu', self.context, self.request)
    
class GroupListPage(ItemListPage):
     
    form_fields = () # no fields, only actions
    
    label = u'groups list'
    
    template = ViewPageTemplateFile('templates/groups.pt')
    
    prefix = 'groups.listing'
    
    def _getItems(self):
        return getSite()['groups']

    def getMenu(self):
        return getMenu('group_menu', self.context, self.request)
    
class IpGroupListPage(ItemListPage):
    form_fields = ()

    label = u'IP-based groups list'

    template = ViewPageTemplateFile('templates/groups.pt')

    prefix = 'groups.listing'

    def _getItems(self):
        return getSite()['ipgroups']
    
    def getMenu(self):
        return getMenu('ip_group_menu', self.context, self.request)
    
def loginValidator(addform, action, data):
    # do normal validation
    errors = form.PageAddForm.validate(addform, action, data)
    # check to see of username already exists for a user or group
    login = data['login']
    if login in getSite()['users'] or login in getSite()['groups']:
        error = ConversionError((
            '"%s" is already in use for another user or group, '
            'Please choose a different identifier.') % data['login'])
        addform.widgets['login']._error = error
        errors.append(error)
    return errors
    
class UserAddForm(FormMixin, form.PageAddForm):
    
    form_fields = form.Fields(interfaces.IUserInfo)
    form_fields['password'].custom_widget = widgets.PasswordConfirmationWidget
    form_fields['email'].custom_widget = widgets.EmailWidget
        
    label = u'add user'
        
    template = ViewPageTemplateFile('templates/form.pt')

    validate = loginValidator
    
    def create(self, data):
        return user.UserInfo(**data)
    
    def nextURL(self):
        return zapi.absoluteURL(
            getSite()['users'], self.request)
    
class UserEditForm(FormMixin, form.PageEditForm):

    form_fields = form.Fields(interfaces.IUserInfo)
    form_fields = form_fields.omit('password')
    form_fields['login'].for_display = True

    form_fields['email'].custom_widget = widgets.EmailWidget
    
    label = u'user edit'
    
    template = ViewPageTemplateFile('templates/form.pt')
    
    # XXX shouldn't have to copy this from form.PageEditForm,
    # actions don't seem to deal with subclassing properly yet
    @form.action('save changes')
    def handleEditAction(self, action, data):
        self.editAction(data)
        return self.redirect(zapi.absoluteURL(
            self.context, self.request) + '/@@display_user')
    
class UserPasswordEditForm(FormMixin, form.PageEditForm):

    form_fields = form.Fields(interfaces.IUserInfo)
    form_fields = form_fields.select('login', 'password')
    form_fields['login'].for_display = True
    form_fields['password'].custom_widget = widgets.PasswordConfirmationWidget
    
    label = u'user login edit'
    
    template = ViewPageTemplateFile('templates/form.pt')
    
    # XXX shouldn't have to copy this from form.PageEditForm,
    # actions don't seem to deal with subclassing properly yet
    @form.action('save changes')
    def handleEditAction(self, action, data):
        self.editAction(data)
        return self.redirect(zapi.absoluteURL(
            self.context, self.request) + '/@@display_user')
    
class UserDisplayForm(FormMixin, form.PageDisplayForm):
    
    form_fields = form.Fields(interfaces.IUserInfo)
    form_fields = form_fields.omit('password')

    label = u'user information'
    
    template = ViewPageTemplateFile('templates/display_form.pt')

    @form.action('edit user information')
    def handleEdit(self, action, data):
        return self.redirect(zapi.absoluteURL(
            self.context, self.request) + '/@@edit_user')

    @form.action('edit password')
    def handleEditLogin(self, action, data):
        return self.redirect(zapi.absoluteURL(
            self.context, self.request) + '/@@edit_user_password')

    def redirect(self, url):
        self.request.response.redirect(url)
        return DO_NOT_RENDER

class GroupAddForm(FormMixin, form.PageAddForm):
    
    form_fields = form.Fields(interfaces.IGroupInfo)
        
    label = u'add group'
        
    template = ViewPageTemplateFile('templates/form.pt')

    validate = loginValidator
    
    def create(self, data):
        return user.GroupInfo(**data)
    
    def nextURL(self):
        return zapi.absoluteURL(
            getSite()['groups'], self.request)

class IpGroupAddForm(FormMixin, form.PageAddForm):
    form_fields = form.Fields(interfaces.IIpGroupInfo)
    form_fields['ip_ranges'].custom_widget = widgets.IpRangesWidget
    
    label = u'add IP group'
        
    template = ViewPageTemplateFile('templates/form.pt')

    def create(self, data):
        return user.IpGroupInfo(**data)
    
    def nextURL(self):
        return zapi.absoluteURL(
            getSite()['ipgroups'], self.request)

class GroupEditForm(FormMixin, form.PageEditForm):

    form_fields = form.Fields(interfaces.IGroupInfo)
    form_fields['login'].for_display = True
    
    label = u'group edit'
    
    template = ViewPageTemplateFile('templates/form.pt')
    
    # XXX shouldn't have to copy this from form.PageEditForm,
    # actions don't seem to deal with subclassing properly yet
    @form.action('save changes')
    def handleEditAction(self, action, data):
        self.editAction(data)
        return self.redirect(zapi.absoluteURL(
            self.context, self.request) + '/@@display_group')

class IpGroupEditForm(FormMixin, form.PageEditForm):
    form_fields = form.Fields(interfaces.IIpGroupInfo)
    form_fields['login'].for_display = True
    form_fields['ip_ranges'].custom_widget = widgets.IpRangesWidget
    
    label = u'IP-based group edit'
    
    template = ViewPageTemplateFile('templates/form.pt')
    
    # XXX shouldn't have to copy this from form.PageEditForm,
    # actions don't seem to deal with subclassing properly yet
    @form.action('save changes')
    def handleEditAction(self, action, data):
        self.editAction(data)
        return self.redirect(zapi.absoluteURL(
            self.context, self.request) + '/@@display_group')

class GroupDisplayForm(FormMixin, form.PageDisplayForm):
    
    form_fields = form.Fields(interfaces.IGroupInfo)

    label = u'group information'
    
    template = ViewPageTemplateFile('templates/display_form.pt')

    @form.action('edit group')
    def handleEdit(self, action, data):
        return self.redirect(zapi.absoluteURL(
            self.context, self.request) + '/@@edit_group')

    def redirect(self, url):
        self.request.response.redirect(url)
        return DO_NOT_RENDER

class IpGroupDisplayForm(FormMixin, form.PageDisplayForm):
    
    form_fields = form.Fields(interfaces.IIpGroupInfo)
    form_fields['ip_ranges'].custom_widget = widgets.IpRangesDisplayWidget
    
    label = u'IP-based group information'
    
    template = ViewPageTemplateFile('templates/display_form.pt')

    @form.action('edit group')
    def handleEdit(self, action, data):
        return self.redirect(zapi.absoluteURL(
            self.context, self.request) + '/@@edit_group')

    def redirect(self, url):
        self.request.response.redirect(url)
        return DO_NOT_RENDER

class BrowseGroupListPage(form.PageForm):

    form_fields = ()
    actions = ()
    
    label = u'browse groups'
    
    template = ViewPageTemplateFile('templates/browse_groups.pt')

    def items(self):
        items = list(getSite()['groups'].items())
        items.sort()
        for dummy, group in items:
            yield group

class BrowseGroupDisplayForm(FormMixin, form.PageDisplayForm):
    form_fields = form.Fields(interfaces.IGroupInfo)

    label = u'group information'

    template = ViewPageTemplateFile('templates/display_form.pt')

class UsernameView(object):
    def __init__(self, context, request):
        self.request = request

    def __call__(self):
        username = self.request.principal.id
        # XXX argh prefix handling
        if username.startswith('documentlibrary'):
            username = username[len('documentlibrary'):]
        lookup = zapi.getUtility(interfaces.IUserInfoLookup)
        userinfo = lookup.getUserInfo(username)
        if userinfo is not None:
            return userinfo.title
        else:
            return username
    
