import web
from web import form
from main.model import Computer, OrganizativeUnit
from user.model import User
from decorators import i18n
from sqlalchemy.orm.exc import NoResultFound
from utils import IPConnectivityCheck
from dbadmin import dbadmin


def validate_unique(model, name, qid=0):
    def f(value):
        orm = web.ctx.orm
        q = orm.query(model).filter(getattr(model, name) == value)
        if q.count() == 0:
            return True
        if qid:
            return q.count() <= 1 and q.one().id == qid
    return f


class OuView:

    @i18n
    def get_form(self, qid=0):
        f = form.Form(
                form.Textbox("name",
                             form.notnull,
                             form.Validator(_("It's not unique"),
                                            validate_unique(OrganizativeUnit, 'name', qid)),
                             label=_("Name")),
                form.Textarea("description", label=_("Description")),
            )

        return f()


class ComputerView:

    @i18n
    def get_form(self, qid=0, ou=None):

        def only_one_repo(item):
            orm = web.ctx.orm
            if item.get('repository', False):
                q = orm.query(Computer).filter_by(repository=True)
                q = q.filter_by(ou=ou)
                if q.count():
                    return False
            return True

        f = form.Form(
                form.Textbox("name",
                             form.notnull,
                             form.Validator(_("It's not unique"),
                                            validate_unique(Computer, 'name', qid)),
                             label=_("Name")),
                form.Textbox("mac",
                             form.notnull,
                             form.Validator(_("It's not unique"),
                                            validate_unique(Computer, 'mac', qid)),
                             form.regexp('\d{12}', _('Only digits')),
                             label=_("MAC")),
                form.Textbox("ip",
                             form.Validator(_("It's not unique"),
                                            validate_unique(Computer, 'ip', qid)),
                             label=_("IP")),
                form.Textbox("port", label=_("Port")),
                form.Checkbox("repository", label=_("Repository"), value="repo"),
                form.Textbox("so", label=_("Operating System")),
                form.Textarea("description", label=_("Description")),
                validators = [form.Validator(_("There is one repo in %s") % ou.name, only_one_repo)],
            )

        return f()



class NavigatorComputer:
    @i18n
    def GET(self, name = None):
        orm = web.ctx.orm
        user = User.current()

        try:
            computer = orm.query(Computer).filter(Computer.name == name).one()

        except NoResultFound:
            raise web.notfound()


        check_permissions(computer, user)

        # Checking if the computer is online
        IPConnectivityCheck(computer.ip).start()

        form = dbadmin.edit_form(computer)
        form.configure(readonly=True)

        return web.ctx.render.navigator.computer(form, computer,
                user, web.ctx.plugin_manager.get_enabled_plugins())


class NavigatorComputerEdit(ComputerView):
    def GET(self, name):
        orm = web.ctx.orm
        user = User.current()

        try:
            computer = orm.query(Computer).filter(
                    Computer.name == name).one()
        except NoResultFound:
            raise web.notfound()

        check_permissions(computer, user)
        form = self.get_form(ou=computer.ou)
        for i in form.inputs:
            i.set_value(getattr(computer, i.name))

        return web.ctx.render.navigator.computer_edit(user, computer.ou, computer, form)

    def POST(self, name):
        orm = web.ctx.orm
        user = User.current()

        try:
            computer = orm.query(Computer).filter(
                    Computer.name == name).one()
        except NoResultFound:
            raise web.notfound()

        check_permissions(computer, user)
        form = self.get_form(computer.id, ou=computer.ou)
        if form.validates():
            for i in form.inputs:
                setattr(computer, i.name, i.get_value())
            raise web.seeother('/navigator/computer/%s' % computer.name)

        else:
            return web.ctx.render.navigator.computer_edit(user, computer.ou, computer, form)


class NavigatorComputerDel:
    def POST(self, name):
        try:
            computer = web.ctx.orm.query(Computer).filter_by(name=name).one()
        except NoResultFound:
            raise web.notfound()
        user = User.current()
        check_permissions(computer, user)
        ou = computer.ou
        web.ctx.orm.delete(computer)
        raise web.seeother('/navigator/ou/%s' % ou.name)


class NavigatorOrganizativeUnit:
    @i18n
    def GET(self, name = None):
        orm = web.ctx.orm
        user = User.current()

        # Checking if a argument is passed
        if name:
            try:
                ou = orm.query(OrganizativeUnit).filter(
                        OrganizativeUnit.name == name).one()
            # except sqlalchemy.orm.exc.NoResultFound:
            except NoResultFound:
                raise web.notfound()

            check_permissions(ou, user)

            # Checking if the computers are online
            for computer in ou.computers:
                IPConnectivityCheck(computer.ip).start()

            return web.ctx.render.navigator.organizativeunit(
                    ou, ou.children, ou.computers,
                    user, web.ctx.plugin_manager.get_enabled_plugins())

        # If not we show the root ous of the user
        else:
            # If it's super user it can see everything
            if user.super_user:
                ous = orm.query(OrganizativeUnit).filter(
                        OrganizativeUnit.parent_id==None).all()

            # If not will see its root ous
            else:
                ous = user.organizative_units

            return web.ctx.render.navigator.organizativeunit(
                    None, ous, [], user, web.ctx.plugin_manager.get_enabled_plugins())


class NavigatorOrganizativeUnitAdd(OuView):
    def GET(self, name=None):
        orm = web.ctx.orm
        user = User.current()

        # Checking if a argument is passed
        if name:
            try:
                ou = orm.query(OrganizativeUnit).filter(
                        OrganizativeUnit.name == name).one()
            # except sqlalchemy.orm.exc.NoResultFound:
            except NoResultFound:
                raise web.notfound()

            check_permissions(ou, user)
            form = self.get_form()

            return web.ctx.render.navigator.organizativeunit_edit(
                    user, ou, OrganizativeUnit(), form)

        # If not we show the root ous of the user
        else:
            # If it's super user it can see everything
            if user.super_user:
                form = self.get_form()

                return web.ctx.render.navigator.organizativeunit_edit(
                        user, None, OrganizativeUnit(), form)
            else:
                return web.notfound()

    def POST(self, name=None):
        orm = web.ctx.orm
        user = User.current()

        if name:
            try:
                ou = orm.query(OrganizativeUnit).filter(
                        OrganizativeUnit.name == name).one()
            except NoResultFound:
                raise web.notfound()

            check_permissions(ou, user)
            form = self.get_form()
            if form.validates():
                newou = OrganizativeUnit(**web.input())
                newou.parent = ou
                orm.add(newou)
                raise web.seeother('/navigator/ou/%s' % name)
            else:
                return web.ctx.render.navigator.organizativeunit_edit(
                        user, ou, OrganizativeUnit(), form)


        else:
            if user.super_user:
                form = self.get_form()
                if form.validates():
                    newou = OrganizativeUnit(**web.input())
                    newou.parent = None
                    orm.add(newou)
                    raise web.seeother('/navigator')
                else:
                    return web.ctx.render.navigator.organizativeunit_edit(
                        user, None, OrganizativeUnit(), form)
            else:
                return web.notfound()


class NavigatorOrganizativeUnitDel:
    def POST(self, name):
        try:
            ou = web.ctx.orm.query(OrganizativeUnit).filter_by(name=name).one()
        except NoResultFound:
            raise web.notfound()

        user = User.current()
        check_permissions(ou, user)
        parent = ou.parent
        web.ctx.orm.delete(ou)
        if parent:
            raise web.seeother('/navigator/ou/%s' % parent.name)
        else:
            raise web.seeother('/navigator')


class NavigatorOrganizativeUnitEdit(OuView):
    def GET(self, name):
        try:
            ou = web.ctx.orm.query(OrganizativeUnit).filter(
                    OrganizativeUnit.name == name).one()
        # except sqlalchemy.orm.exc.NoResultFound:
        except NoResultFound:
            raise web.notfound()

        user = User.current()
        check_permissions(ou, user)
        form = self.get_form()
        for i in form.inputs:
            i.set_value(getattr(ou, i.name))

        return web.ctx.render.navigator.organizativeunit_edit(
                user, ou.parent, ou, form)

    def POST(self, name):
        try:
            ou = web.ctx.orm.query(OrganizativeUnit).filter(
                    OrganizativeUnit.name == name).one()
        # except sqlalchemy.orm.exc.NoResultFound:
        except NoResultFound:
            raise web.notfound()

        user = User.current()
        check_permissions(ou, user)
        form = self.get_form(ou.id)
        if form.validates():
            for i in form.inputs:
                setattr(ou, i.name, i.get_value())

            raise web.seeother('/navigator/ou/%s' % ou.name)
        else:
            return web.ctx.render.navigator.organizativeunit_edit(
                user, ou.parent, ou, form)


class NavigatorComputerAdd(ComputerView):

    def GET(self, name):
        orm = web.ctx.orm
        user = User.current()

        try:
            ou = orm.query(OrganizativeUnit).filter(
                    OrganizativeUnit.name == name).one()
        except NoResultFound:
            raise web.notfound()

        check_permissions(ou, user)
        form = self.get_form(ou=ou)

        return web.ctx.render.navigator.computer_edit(user, ou, Computer(), form)

    def POST(self, name):
        orm = web.ctx.orm
        user = User.current()

        try:
            ou = orm.query(OrganizativeUnit).filter(
                    OrganizativeUnit.name == name).one()
        except NoResultFound:
            raise web.notfound()

        check_permissions(ou, user)
        form = self.get_form(ou=ou)
        if form.validates():
            new_computer = Computer(**web.input())
            new_computer.ou = ou
            orm.add(new_computer)
            raise web.seeother('/navigator/ou/%s' % name)

        else:
            return web.ctx.render.navigator.computer_edit(user, ou, Computer(), form)


def check_permissions(item, user):
    # Super users always have permisions
    if user.super_user:
        return
    if item.__class__.__name__ == "OrganizativeUnit":
        if item.parent_id == None and not item in user.organizative_units:
            # TODO: show the user it has no permissions
            raise web.seeother('/navigator')
        elif item in user.organizative_units:
            # Has permissions, so nothing to do
            return
        else:
            check_permissions(item.parent, user)
    else:
        check_permissions(item.ou, user)
