# Copyright (c) 2015 iXsystems, Inc.
# All rights reserved.
# This file is a part of TrueNAS
# and may not be copied and/or distributed
# without the express permission of iXsystems.

import logging
import sys

from django.core.urlresolvers import reverse
from django.shortcuts import render
from django.utils.html import escapejs
from django.utils.translation import ugettext as _

from freenasUI.common.system import get_sw_login_version, get_sw_name
from freenasUI.freeadmin.hook import AppHook
from freenasUI.failover.mixins import FailoverAlert
from freenasUI.failover.notifier import FailoverNotifier

log = logging.getLogger('failover.hook')


class FailoverHook(AppHook):

    name = 'failover'

    def _common_failover_view(self, request):
        from freenasUI.failover.forms import TakeoverForm
        from freenasUI.failover.models import Failover
        from freenasUI.middleware.notifier import notifier
        from freenasUI.network.models import Interfaces
        status = notifier().failover_status()
        if status not in ('SINGLE', 'MASTER'):
            ips = []
            try:
                for iface in Interfaces.objects.all().exclude(
                    int_vip=None
                ):
                    if iface.int_vip:
                        ips.append(str(iface.int_vip))
            except:
                pass
            try:
                failover = Failover.objects.order_by('-id')[0]
            except:
                failover = Failover.objects.create()
            return render(request, "failover/failover.html", {
                'ips': ips,
                'status': status,
                'sw_login_version': get_sw_login_version(),
                'sw_name': get_sw_name(),
                'form': TakeoverForm(),
                'failover': failover,
            })

    def _common_ha_abort(self):
        from freenasUI.middleware.notifier import notifier
        """
        This method detects whether this unit is part of a HA pair
        and if so whether it is active or passive.  If this is
        HA and passive returns True.
        If this is currently the master of an HA pair or not
        in an HA pair it returns False.
        """

        status = notifier().failover_status()
        if status not in ("SINGLE", "MASTER"):
            return True
        return False

    def base_js(self, request):
        return [
            'lib/js/failover.js',
        ]

    def base_css(self, request):
        return [
            'css/failover.css',
        ]

    def hook_app_index_freeadmin(self, request):
        return self._common_failover_view(request)

    def hook_app_index_account_login(self, request):
        return self._common_failover_view(request)

    def hook_app_tabs_system(self, request):
        from freenasUI.failover.models import Failover
        from freenasUI.middleware.notifier import notifier
        try:
            oid = Failover.objects.order_by('-id')[0].id
        except IndexError:
            oid = Failover.objects.create().id
        if not notifier().failover_licensed():
            return []
        return [
            {
                'name': 'Failover',
                'focus': 'system.Failover',
                'verbose_name': _('Failover'),
                'url': reverse('freeadmin_failover_failover_edit', kwargs={
                    'oid': oid,
                }) + '?deletable=false&inline=true',
                'order': 100,
            }
        ]

    def hook_class_new_VolumeStatusAlert(self, bases, attrs):
        bases.insert(0, FailoverAlert)

    def hook_class_new_notifier(self, bases, attrs):
        bases.insert(0, FailoverNotifier)

    def hook_form_buttons_AdvancedForm(self, form, action, *args, **kwargs):
        from freenasUI.middleware.notifier import notifier
        btns = []
        status = notifier().failover_status()
        if status not in ('SINGLE', 'MASTER'):
            btns.append({
                'name': 'ForceMaster',
                'verbose_name': _('Failover Force Master'),
                'onclick': 'failoverForceMaster(this, "%s")' % (
                    escapejs(reverse('failover_force_master'))
                ),
            })
        return btns

    def _virtual_ip_configured(self):
        from freenasUI.network.models import Interfaces
        from django.db.models import Q
        return Interfaces.objects.exclude(
            Q(int_vip=None) | Q(int_vip='')
        ).count() > 0

    def _volume_configured(self):
        from freenasUI.storage.models import Volume
        return Volume.objects.all().count() > 0

    def hook_form_init_AutoImportWizard(self, form, *args, **kwargs):
        from freenasUI.middleware.notifier import notifier
        if not notifier().failover_licensed():
            return
        form._volume_configured = self._volume_configured()

    def hook_form_done_AutoImportWizard(self, form, request, events, **kwargs):
        from freenasUI.middleware.notifier import notifier
        if not notifier().failover_licensed():
            return
        notifier().start("ix-devd")
        if (
            not form._volume_configured and self._volume_configured()
        ) and self._virtual_ip_configured():
            _n = notifier()
            _n.failover_sync_peer('to')
            s = _n.failover_rpc()
            s.service([
                ('start', 'ix-devd'),
            ])
            events.append('window.location="/";')

    def hook_form_init_InterfacesForm(self, form, *args, **kwargs):
        from freenasUI.middleware.notifier import notifier
        if not notifier().failover_licensed():
            return
        form._vip_configured = self._virtual_ip_configured()

    def hook_form_done_InterfacesForm(self, form, request, events, **kwargs):
        """
        Sync to peer the first time a Virtual IP is configured
        This will sync the database and /data files plus restart services
        required for HA to work
        """
        from freenasUI.middleware.notifier import notifier
        if not notifier().failover_licensed():
            return
        notifier().start("ix-devd")
        notifier().restart("devd")
        # Configure HA for the first time once a Virtual IP is set
        vip_configured = self._virtual_ip_configured()
        if not form._vip_configured and vip_configured:
            _n = notifier()
            _n.failover_sync_peer('to')
            s = _n.failover_rpc()
            s.service([
                ('start', 'ix-devd'),
                ('restart', 'devd'),
                ('start', 'network'),
            ])
            if self._volume_configured():
                events.append('window.location="/";')
        elif form._vip_configured and not vip_configured:
            if self._volume_configured():
                events.append('window.location="/";')

    def hook_form_done_SSHForm(self, form, request, events, **kwargs):
        """
        Needs to run generate_failover_json.py in case SSH port has changed
        because of pf.conf.block rule
        """
        from freenasUI.middleware.notifier import notifier
        if not notifier().failover_licensed():
            return
        notifier().start("ix-devd")

    def hook_form_done_SettingsForm(self, form, request, events, **kwargs):
        """
        Needs to run generate_failover_json.py in case HTTP(S)? port has changed
        because of pf.conf.block rule
        """
        from freenasUI.middleware.notifier import notifier
        if not notifier().failover_licensed():
            return
        notifier().start("ix-devd")

    def hook_form_done_LicenseUpdateForm(self, form, request, events, **kwargs):
        from freenasUI.support.utils import get_license
        license, error = get_license()
        if license and license.system_serial_ha:
            events.append('dojo.byId("failoveren_menuitem").style["display"] = "";')
            events.append('checkDisabled()')

    def hook_form_done_VolumeExport(self, form, request, events, **kwargs):
        from freenasUI.middleware.notifier import notifier
        if not notifier().failover_licensed():
            return
        notifier().start("ix-devd")
        if not self._volume_configured():
            _n = notifier()
            _n.failover_sync_peer('to')
            s = _n.failover_rpc()
            s.service([
                ('start', 'ix-devd'),
            ])
            events.append('window.location="/";')

    def hook_form_init_VolumeManagerForm(self, form, *args, **kwargs):
        from freenasUI.middleware.notifier import notifier
        if not notifier().failover_licensed():
            return
        form._volume_configured = self._volume_configured()

    def hook_form_done_VolumeManagerForm(self, form, request, events, **kwargs):
        from freenasUI.middleware.notifier import notifier
        if not notifier().failover_licensed():
            return
        notifier().start("ix-devd")
        if (
            not form._volume_configured and self._volume_configured()
        ) and self._virtual_ip_configured():
            _n = notifier()
            _n.failover_sync_peer('to')
            s = _n.failover_rpc()
            s.service([
                ('start', 'ix-devd'),
            ])
            events.append('window.location="/";')

    def hook_tool_run_autorepl(self):
        if self._common_ha_abort():
            sys.exit(0)

    def hook_tool_run_autosnap(self):
        if self._common_ha_abort():
            sys.exit(0)

    def top_menu(self, request):
        from freenasUI.middleware.notifier import notifier

        rv = []

        node = notifier().failover_node()
        if not node:
            return rv

        licensed = notifier().failover_licensed()

        status = notifier().failover_status()
        if status == 'SINGLE':
            name = 'HA Disabled'
        else:
            name = 'HA Enabled'

        rv.append({
            'id': 'failoveren_menuitem',
            'name': (
                '<span id="failover_disabled_text">%s</span>' % (
                    name,
                )
            ),
            'img': (
                '<div data-dojo-type="dijit.layout.ContentPane" '
                'data-node="%s" id="failover_disabled"></div>' % (
                    node,

                )
            ),
            'onclick': 'haStatus();',
            'align': 'right',
            'weight': 0,
            'style': None if licensed else 'display: none;',
        })

        return rv
