# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2017  Gabriel Détraz
# Copyright © 2017  Lara Kermarec
# Copyright © 2017  Augustin Lemesle
# Copyright © 2017  Maël Kervella
#
# 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.
"""
Forms to create, edit and delete:
    * machines
    * interfaces
    * domains (machine names)
    * aliases (CNAME)
    * services (DHCP, DNS...)
    * NS records (DNS server)
    * MX records (mail serveur)
    * open ports and ports opening for interfaces
"""

from __future__ import unicode_literals

from django import forms
from django.forms import Form, ModelForm
from django.utils.translation import ugettext_lazy as _

from re2o.field_permissions import FieldPermissionFormMixin
from re2o.mixins import FormRevMixin
from re2o.widgets import (AutocompleteModelWidget,
                          AutocompleteMultipleModelWidget)

from .models import (SOA, DName, Domain, Extension, Interface, IpList, IpType,
                     Ipv6List, Machine, MachineType, Mx, Nas, Ns,
                     OuverturePortList, Role, Service, Srv, SshFp, Txt, Vlan)


class EditMachineForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
    """Form used to edit a machine."""

    class Meta:
        model = Machine
        fields = "__all__"
        widgets = {"user": AutocompleteModelWidget(url="/users/user-autocomplete")}

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(EditMachineForm, self).__init__(*args, prefix=prefix, **kwargs)
        self.fields["name"].label = _("Machine name")


class NewMachineForm(EditMachineForm):
    """Form used to create a machine."""

    class Meta(EditMachineForm.Meta):
        fields = ["name"]


class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
    """Form used to edit an interface."""

    class Meta:
        model = Interface
        fields = ["machine", "machine_type", "ipv4", "mac_address", "details"]
        widgets = {
            "machine": AutocompleteModelWidget(url="/machines/machine-autocomplete"),
            "machine_type": AutocompleteModelWidget(
                url="/machines/machinetype-autocomplete"
            ),
            "ipv4": AutocompleteModelWidget(
                url="/machines/iplist-autocomplete",
                forward=["machine_type"],
                attrs={
                    "data-placeholder": "Automatic assigment. Type to choose specific ip."
                },
            ),
        }

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        user = kwargs.get("user")
        super(EditInterfaceForm, self).__init__(*args, prefix=prefix, **kwargs)
        self.fields["mac_address"].label = _("MAC address")
        self.fields["machine_type"].label = _("Machine type")
        self.fields["machine_type"].empty_label = _("Select a machine type")
        if "ipv4" in self.fields:
            self.fields["ipv4"].empty_label = _("Automatic IPv4 assignment")
            self.fields["ipv4"].queryset = IpList.objects.filter(interface__isnull=True)
            can_use_all_iptype, _reason, _permissions = IpType.can_use_all(user)
            if not can_use_all_iptype:
                self.fields["ipv4"].queryset = IpList.objects.filter(
                    interface__isnull=True
                ).filter(ip_type__in=IpType.objects.filter(need_infra=False))
            else:
                self.fields["ipv4"].queryset = IpList.objects.filter(
                    interface__isnull=True
                )
            # Add it's own address
            self.fields["ipv4"].queryset |= IpList.objects.filter(
                interface=self.instance
            )
        if "machine" in self.fields:
            self.fields["machine"].queryset = Machine.objects.all().select_related(
                "user"
            )
        can_use_all_machinetype, _reason, _permissions = MachineType.can_use_all(user)
        if not can_use_all_machinetype:
            self.fields["machine_type"].queryset = MachineType.objects.filter(
                ip_type__in=IpType.objects.filter(need_infra=False)
            )


class AddInterfaceForm(EditInterfaceForm):
    """Form used to add an interface to a machine."""

    class Meta(EditInterfaceForm.Meta):
        fields = ["machine_type", "ipv4", "mac_address", "details"]


class AliasForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
    """Form used to add and edit an alias (CNAME)."""

    class Meta:
        model = Domain
        fields = ["name", "extension", "ttl"]
        widgets = {
            "extension": AutocompleteModelWidget(url="/machines/extension-autocomplete")
        }

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        user = kwargs["user"]
        super(AliasForm, self).__init__(*args, prefix=prefix, **kwargs)
        can_use_all, _reason, _permissions = Extension.can_use_all(user)
        if not can_use_all:
            self.fields["extension"].queryset = Extension.objects.filter(
                need_infra=False
            )


class DomainForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
    """Form used to add and edit a domain record, related to an
    interface.
    """

    class Meta:
        model = Domain
        fields = ["name", "ttl"]

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(DomainForm, self).__init__(*args, prefix=prefix, **kwargs)


class DelAliasForm(FormRevMixin, Form):
    """Form used to delete one or several aliases."""

    alias = forms.ModelMultipleChoiceField(
        queryset=Domain.objects.all(),
        label=_("Current aliases"),
        widget=forms.CheckboxSelectMultiple,
    )

    def __init__(self, *args, **kwargs):
        interface = kwargs.pop("interface")
        super(DelAliasForm, self).__init__(*args, **kwargs)
        self.fields["alias"].queryset = Domain.objects.filter(
            cname__in=Domain.objects.filter(interface_parent=interface)
        )


class MachineTypeForm(FormRevMixin, ModelForm):
    """Form used to add and edit a machine type, related to an IP type."""

    class Meta:
        model = MachineType
        fields = ["name", "ip_type"]
        widgets = {
            "ip_type": AutocompleteModelWidget(url="/machines/iptype-autocomplete")
        }

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(MachineTypeForm, self).__init__(*args, prefix=prefix, **kwargs)
        self.fields["name"].label = _("Machine type to add")
        self.fields["ip_type"].label = _("Related IP type")


class DelMachineTypeForm(FormRevMixin, Form):
    """Form used to delete one or several machines types."""

    machinetypes = forms.ModelMultipleChoiceField(
        queryset=MachineType.objects.none(),
        label=_("Current machine types"),
        widget=forms.CheckboxSelectMultiple,
    )

    def __init__(self, *args, **kwargs):
        instances = kwargs.pop("instances", None)
        super(DelMachineTypeForm, self).__init__(*args, **kwargs)
        if instances:
            self.fields["machinetypes"].queryset = instances
        else:
            self.fields["machinetypes"].queryset = MachineType.objects.all()


class IpTypeForm(FormRevMixin, ModelForm):
    """Form used to add an IP type. The start and stop IP addresses cannot
    be changed afterwards.
    """

    class Meta:
        model = IpType
        fields = "__all__"
        widgets = {
            "vlan": AutocompleteModelWidget(url="/machines/vlan-autocomplete"),
            "extension": AutocompleteModelWidget(
                url="/machines/extension-autocomplete"
            ),
            "ouverture_ports": AutocompleteModelWidget(
                url="/machines/ouvertureportlist-autocomplete"
            ),
        }

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(IpTypeForm, self).__init__(*args, prefix=prefix, **kwargs)
        self.fields["name"].label = _("IP type to add")


class EditIpTypeForm(IpTypeForm):
    """Form used to edit an IP type. The start and stop IP addresses cannot
    be changed.
    """

    class Meta(IpTypeForm.Meta):
        fields = [
            "extension",
            "name",
            "need_infra",
            "domaine_ip_network",
            "domaine_ip_netmask",
            "prefix_v6",
            "prefix_v6_length",
            "vlan",
            "reverse_v4",
            "reverse_v6",
            "ouverture_ports",
        ]


class DelIpTypeForm(FormRevMixin, Form):
    """Form used to delete one or several IP types."""

    iptypes = forms.ModelMultipleChoiceField(
        queryset=IpType.objects.none(),
        label=_("Current IP types"),
        widget=forms.CheckboxSelectMultiple,
    )

    def __init__(self, *args, **kwargs):
        instances = kwargs.pop("instances", None)
        super(DelIpTypeForm, self).__init__(*args, **kwargs)
        if instances:
            self.fields["iptypes"].queryset = instances
        else:
            self.fields["iptypes"].queryset = IpType.objects.all()


class ExtensionForm(FormRevMixin, ModelForm):
    """Form used to add and edit extensions."""

    class Meta:
        model = Extension
        fields = "__all__"

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(ExtensionForm, self).__init__(*args, prefix=prefix, **kwargs)
        self.fields["name"].label = _("Extension to add")
        self.fields["origin"].label = _("A record origin")
        self.fields["origin_v6"].label = _("AAAA record origin")
        self.fields["soa"].label = _("SOA record to use")
        self.fields["dnssec"].label = _("Sign with DNSSEC")


class DelExtensionForm(FormRevMixin, Form):
    """Form used to delete one or several extensions."""

    extensions = forms.ModelMultipleChoiceField(
        queryset=Extension.objects.none(),
        label=_("Current extensions"),
        widget=forms.CheckboxSelectMultiple,
    )

    def __init__(self, *args, **kwargs):
        instances = kwargs.pop("instances", None)
        super(DelExtensionForm, self).__init__(*args, **kwargs)
        if instances:
            self.fields["extensions"].queryset = instances
        else:
            self.fields["extensions"].queryset = Extension.objects.all()


class Ipv6ListForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
    """Form used to manage lists of IPv6 addresses."""

    class Meta:
        model = Ipv6List
        fields = ["ipv6", "slaac_ip", "active"]

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(Ipv6ListForm, self).__init__(*args, prefix=prefix, **kwargs)


class SOAForm(FormRevMixin, ModelForm):
    """Form used to add and edit SOA records."""

    class Meta:
        model = SOA
        fields = "__all__"

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(SOAForm, self).__init__(*args, prefix=prefix, **kwargs)


class DelSOAForm(FormRevMixin, Form):
    """Form used to delete one or several SOA records."""

    soa = forms.ModelMultipleChoiceField(
        queryset=SOA.objects.none(),
        label=_("Current SOA records"),
        widget=forms.CheckboxSelectMultiple,
    )

    def __init__(self, *args, **kwargs):
        instances = kwargs.pop("instances", None)
        super(DelSOAForm, self).__init__(*args, **kwargs)
        if instances:
            self.fields["soa"].queryset = instances
        else:
            self.fields["soa"].queryset = SOA.objects.all()


class MxForm(FormRevMixin, ModelForm):
    """Form used to add and edit MX records."""

    class Meta:
        model = Mx
        fields = ["zone", "priority", "name", "ttl"]
        widgets = {
            "zone": AutocompleteModelWidget(url="/machines/extension-autocomplete"),
            "name": AutocompleteModelWidget(url="/machines/domain-autocomplete"),
        }

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(MxForm, self).__init__(*args, prefix=prefix, **kwargs)
        self.fields["name"].queryset = Domain.objects.exclude(
            interface_parent=None
        ).select_related("extension")


class DelMxForm(FormRevMixin, Form):
    """Form used to delete one or several MX records."""

    mx = forms.ModelMultipleChoiceField(
        queryset=Mx.objects.none(),
        label=_("Current MX records"),
        widget=forms.CheckboxSelectMultiple,
    )

    def __init__(self, *args, **kwargs):
        instances = kwargs.pop("instances", None)
        super(DelMxForm, self).__init__(*args, **kwargs)
        if instances:
            self.fields["mx"].queryset = instances
        else:
            self.fields["mx"].queryset = Mx.objects.all()


class NsForm(FormRevMixin, ModelForm):
    """Form used to add and edit NS records. Only interface names are
    available because CNAME aliases should not be used in the records.
    """

    class Meta:
        model = Ns
        fields = ["zone", "ns", "ttl"]
        widgets = {
            "zone": AutocompleteModelWidget(url="/machines/extension-autocomplete"),
            "ns": AutocompleteModelWidget(url="/machines/domain-autocomplete"),
        }

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(NsForm, self).__init__(*args, prefix=prefix, **kwargs)
        self.fields["ns"].queryset = Domain.objects.exclude(
            interface_parent=None
        ).select_related("extension")


class DelNsForm(FormRevMixin, Form):
    """Form used to delete one or several NS records."""

    nss = forms.ModelMultipleChoiceField(
        queryset=Ns.objects.none(),
        label=_("Current NS records"),
        widget=forms.CheckboxSelectMultiple,
    )

    def __init__(self, *args, **kwargs):
        instances = kwargs.pop("instances", None)
        super(DelNsForm, self).__init__(*args, **kwargs)
        if instances:
            self.fields["nss"].queryset = instances
        else:
            self.fields["nss"].queryset = Ns.objects.all()


class TxtForm(FormRevMixin, ModelForm):
    """Form used to add and edit TXT records."""

    class Meta:
        model = Txt
        fields = "__all__"
        widgets = {
            "zone": AutocompleteModelWidget(url="/machines/extension-autocomplete")
        }

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(TxtForm, self).__init__(*args, prefix=prefix, **kwargs)


class DelTxtForm(FormRevMixin, Form):
    """Form used to delete one or several TXT records."""

    txt = forms.ModelMultipleChoiceField(
        queryset=Txt.objects.none(),
        label=_("Current TXT records"),
        widget=forms.CheckboxSelectMultiple,
    )

    def __init__(self, *args, **kwargs):
        instances = kwargs.pop("instances", None)
        super(DelTxtForm, self).__init__(*args, **kwargs)
        if instances:
            self.fields["txt"].queryset = instances
        else:
            self.fields["txt"].queryset = Txt.objects.all()


class DNameForm(FormRevMixin, ModelForm):
    """Form used to add and edit DNAME records."""

    class Meta:
        model = DName
        fields = "__all__"
        widgets = {
            "zone": AutocompleteModelWidget(url="/machines/extension-autocomplete")
        }

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(DNameForm, self).__init__(*args, prefix=prefix, **kwargs)


class DelDNameForm(FormRevMixin, Form):
    """Form used to delete one or several DNAME records."""

    dnames = forms.ModelMultipleChoiceField(
        queryset=Txt.objects.none(),
        label=_("Current DNAME records"),
        widget=forms.CheckboxSelectMultiple,
    )

    def __init__(self, *args, **kwargs):
        instances = kwargs.pop("instances", None)
        super(DelDNameForm, self).__init__(*args, **kwargs)
        if instances:
            self.fields["dnames"].queryset = instances
        else:
            self.fields["dnames"].queryset = DName.objects.all()


class SrvForm(FormRevMixin, ModelForm):
    """Form used to add and edit SRV records."""

    class Meta:
        model = Srv
        fields = "__all__"
        widgets = {
            "extension": AutocompleteModelWidget(
                url="/machines/extension-autocomplete"
            ),
            "target": AutocompleteModelWidget(url="/machines/domain-autocomplete"),
        }

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(SrvForm, self).__init__(*args, prefix=prefix, **kwargs)


class DelSrvForm(FormRevMixin, Form):
    """Form used to delete one or several SRV records."""

    srv = forms.ModelMultipleChoiceField(
        queryset=Srv.objects.none(),
        label=_("Current SRV records"),
        widget=forms.CheckboxSelectMultiple,
    )

    def __init__(self, *args, **kwargs):
        instances = kwargs.pop("instances", None)
        super(DelSrvForm, self).__init__(*args, **kwargs)
        if instances:
            self.fields["srv"].queryset = instances
        else:
            self.fields["srv"].queryset = Srv.objects.all()


class NasForm(FormRevMixin, ModelForm):
    """Form used to create and edit NAS devices."""

    class Meta:
        model = Nas
        fields = "__all__"
        widgets = {
            "nas_type": AutocompleteModelWidget(
                url="/machines/machinetype-autocomplete"
            ),
            "machine_type": AutocompleteModelWidget(
                url="/machines/machinetype-autocomplete"
            ),
        }

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(NasForm, self).__init__(*args, prefix=prefix, **kwargs)


class DelNasForm(FormRevMixin, Form):
    """Form used to delete one or several NAS devices."""

    nas = forms.ModelMultipleChoiceField(
        queryset=Nas.objects.none(),
        label=_("Current NAS devices"),
        widget=forms.CheckboxSelectMultiple,
    )

    def __init__(self, *args, **kwargs):
        instances = kwargs.pop("instances", None)
        super(DelNasForm, self).__init__(*args, **kwargs)
        if instances:
            self.fields["nas"].queryset = instances
        else:
            self.fields["nas"].queryset = Nas.objects.all()


class RoleForm(FormRevMixin, ModelForm):
    """Form used to add and edit roles."""

    class Meta:
        model = Role
        fields = "__all__"
        widgets = {
            "servers": AutocompleteMultipleModelWidget(
                url="/machines/interface-autocomplete"
            )
        }

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(RoleForm, self).__init__(*args, prefix=prefix, **kwargs)
        self.fields["servers"].queryset = Interface.objects.all().select_related(
            "domain__extension"
        )


class DelRoleForm(FormRevMixin, Form):
    """Form used to delete one or several roles."""

    role = forms.ModelMultipleChoiceField(
        queryset=Role.objects.none(),
        label=_("Current roles"),
        widget=forms.CheckboxSelectMultiple,
    )

    def __init__(self, *args, **kwargs):
        instances = kwargs.pop("instances", None)
        super(DelRoleForm, self).__init__(*args, **kwargs)
        if instances:
            self.fields["role"].queryset = instances
        else:
            self.fields["role"].queryset = Role.objects.all()


class ServiceForm(FormRevMixin, ModelForm):
    """Form to add and edit services (DHCP, DNS etc.)."""

    class Meta:
        model = Service
        fields = "__all__"
        widgets = {
            "servers": AutocompleteMultipleModelWidget(
                url="/machines/interface-autocomplete"
            )
        }

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(ServiceForm, self).__init__(*args, prefix=prefix, **kwargs)
        self.fields["servers"].queryset = Interface.objects.all().select_related(
            "domain__extension"
        )

    def save(self, commit=True):
        # TODO : None of the parents of ServiceForm use the commit
        # parameter in .save()
        instance = super(ServiceForm, self).save(commit=False)
        if commit:
            instance.save()
        instance.process_link(self.cleaned_data.get("servers"))
        return instance


class DelServiceForm(FormRevMixin, Form):
    """Form used to delete one or several services."""

    service = forms.ModelMultipleChoiceField(
        queryset=Service.objects.none(),
        label=_("Current services"),
        widget=forms.CheckboxSelectMultiple,
    )

    def __init__(self, *args, **kwargs):
        instances = kwargs.pop("instances", None)
        super(DelServiceForm, self).__init__(*args, **kwargs)
        if instances:
            self.fields["service"].queryset = instances
        else:
            self.fields["service"].queryset = Service.objects.all()


class VlanForm(FormRevMixin, ModelForm):
    """Form used to add and edit VLANs."""

    class Meta:
        model = Vlan
        fields = ["vlan_id", "name", "comment"]

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(VlanForm, self).__init__(*args, prefix=prefix, **kwargs)


class EditOptionVlanForm(FormRevMixin, ModelForm):
    """Form used to edit the options of a VLAN."""

    class Meta:
        model = Vlan
        fields = ["dhcp_snooping", "dhcpv6_snooping", "arp_protect", "igmp", "mld"]

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(EditOptionVlanForm, self).__init__(*args, prefix=prefix, **kwargs)


class DelVlanForm(FormRevMixin, Form):
    """Form used to delete one or several VLANs."""

    vlan = forms.ModelMultipleChoiceField(
        queryset=Vlan.objects.none(),
        label=_("Current VLANs"),
        widget=forms.CheckboxSelectMultiple,
    )

    def __init__(self, *args, **kwargs):
        instances = kwargs.pop("instances", None)
        super(DelVlanForm, self).__init__(*args, **kwargs)
        if instances:
            self.fields["vlan"].queryset = instances
        else:
            self.fields["vlan"].queryset = Vlan.objects.all()


class EditOuverturePortConfigForm(FormRevMixin, ModelForm):
    """Form to edit the ports opening list of an interface."""

    class Meta:
        model = Interface
        fields = ["port_lists"]
        widgets = {
            "port_lists": AutocompleteMultipleModelWidget(
                url="/machines/ouvertureportlist-autocomplete"
            )
        }

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(EditOuverturePortConfigForm, self).__init__(
            *args, prefix=prefix, **kwargs
        )


class EditOuverturePortListForm(FormRevMixin, ModelForm):
    """Form used to add and edit ports opening lists."""

    class Meta:
        model = OuverturePortList
        fields = "__all__"

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(EditOuverturePortListForm, self).__init__(*args, prefix=prefix, **kwargs)


class SshFpForm(FormRevMixin, ModelForm):
    """Form used to add and edit SSHFP records."""

    class Meta:
        model = SshFp
        exclude = ("machine",)

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop("prefix", self.Meta.model.__name__)
        super(SshFpForm, self).__init__(*args, prefix=prefix, **kwargs)