# 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 cgi
import json
import logging
import os
import socket
import struct
import xmlrpclib

from django.http import HttpResponse
from django.shortcuts import render
from django.utils.translation import ugettext as _

from freenasUI.common.system import get_sw_version
from freenasUI.freeadmin.middleware import public
from freenasUI.freeadmin.views import JsonResp
from freenasUI.network.forms import IPMIForm
from freenasUI.middleware.notifier import notifier
from . import forms, utils

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

SW_VERSION = get_sw_version()


def failovers_sync_peer(request, fromto):

    # FIXME: import from tools.alert
    SYNC_FILE = '/var/tmp/sync_failed'

    if request.method == "POST":
        if fromto == "to" and os.path.exists(SYNC_FILE):
            os.unlink(SYNC_FILE)
        try:
            failover = notifier().failover_sync_peer(fromto=fromto)
            assert failover is not False
            return JsonResp(
                request,
                message=_("You have successfully synced %s peer.") % (
                    fromto,
                )
            )
        except Exception as e:
            if fromto == "to":
                open(SYNC_FILE, 'w').close()
            return JsonResp(
                request,
                error=True,
                message='An error occured: %s' % cgi.escape(str(e)),
            )
    else:
        return render(
            request,
            "system/failover_sync_%s_peer.html" % (fromto),
            {'ip': notifier().failover_pair_ip()},
        )


def failover_disabled(request):
    reasons = utils.failover_disabled_reasons()
    return HttpResponse(
        json.dumps(reasons),
        content_type='application/json',
    )


def failover_disabled_detail(request):
    reasons = utils.failover_disabled_reasons()
    return render(request, "failover/disabled.html", {
        'reasons': reasons,
    })


@public
def failovers_status(request):
    if not hasattr(notifier, 'failover_status'):
        status = ''
    else:
        status = notifier().failover_status()
    return HttpResponse(status)


def failovers_force_master(request):
    ret = notifier().failover_force_master()
    if ret:
        return JsonResp(request, message='Failover force master initiated')
    else:
        return JsonResp(request, message='Failover force master failed')


def waitnode(request):

    data = 'WAITING'
    s = notifier().failover_rpc()
    try:
        ping = s.ping()
        if ping:
            version = s.version()
            data = 'UPDATE'
            if version:
                if version == SW_VERSION:
                    data = 'FINISHED'
    except (xmlrpclib.Fault, socket.error, IOError):
        pass

    return HttpResponse(
        json.dumps(data),
        content_type='application/json',
    )


def hareplication(request):
    if request.method == 'POST':
        form = forms.HAReplicationForm(request.POST)
        if form.is_valid():
            form.commit()
            return JsonResp(
                request,
                message=_("HA Replication successfully updated.")
            )
    else:
        form = forms.HAReplicationForm()
    return render(request, 'storage/hareplication.html', {
        'form': form,
    })


@public
def takeover(request):

    form = forms.TakeoverForm(request.POST)
    error = True
    message = ''
    if form.is_valid():
        error = False
        notifier().failover_force_master()
    else:
        for field, value in form.errors.items():
            message += str(value)

    return HttpResponse(json.dumps({
        'error': error,
        'message': message,
    }))


def ipmi(request):

    class IPMIFormB(IPMIForm):
        pass

    s = notifier().failover_rpc()
    if request.method == "POST":
        form = IPMIFormB(request.POST, auto_id='idb_%s')
        if form.is_valid():
            rv = s.notifier('ipmi_set_lan', [
                form.cleaned_data,
            ], {
                'channel': int(form.cleaned_data.get('channel')),
            })
            if rv == 0:
                return JsonResp(request, message=_("IPMI successfully edited"))
            else:
                return JsonResp(request, error=True, message=_("IPMI failed"))
    else:
        try:
            ipmi = s.notifier('ipmi_get_lan', [], {})

            # TODO: There might be a better way to convert netmask to CIDR
            mask = ipmi.get("SubnetMask")
            num, cidr = struct.unpack('>I', socket.inet_aton(mask))[0], 0
            while num > 0:
                num = num << 1 & 0xffffffff
                cidr += 1
            initial = {
                'dhcp': False
                if ipmi.get("IpAddressSource") == "Static Address"
                else True,
                'ipv4address': ipmi.get("IpAddress"),
                'ipv4gw': ipmi.get("DefaultGatewayIp"),
                'ipv4netmaskbit': str(cidr),
                'vlanid': ipmi.get("8021qVlanId")
                if ipmi.get("8021qVlanId") != 'Disabled'
                else '',
            }
        except Exception:
            initial = {}
        form = IPMIFormB(initial=initial, auto_id='idb_%s')
    return render(request, 'network/ipmi.html', {
        'form': form,
    })
