# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2011 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Copyright 2011 Fourth Paradigm Development, Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

from django import template
from django import http
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.shortcuts import render_to_response
from django.utils.translation import ugettext as _

import datetime
import logging

from django.contrib import messages

from django_openstack import api
from django_openstack import forms
from django_openstack.dash.views import instances as dash_instances
from openstackx.api import exceptions as api_exceptions


TerminateInstance = dash_instances.TerminateInstance
RebootInstance = dash_instances.RebootInstance

LOG = logging.getLogger('django_openstack.syspanel.views.instances')


def _next_month(date_start):
    y = date_start.year + (date_start.month + 1)/13
    m = ((date_start.month + 1)%13)
    if m == 0:
        m = 1
    return datetime.date(y, m, 1)


def _current_month():
    today = datetime.date.today()
    return datetime.date(today.year, today.month,1)


def _get_start_and_end_date(request):
    try:
        date_start = datetime.date(int(request.GET['date_year']), int(request.GET['date_month']), 1)
    except:
        today = datetime.date.today()
        date_start = datetime.date(today.year, today.month,1)

    date_end = _next_month(date_start)
    datetime_start = datetime.datetime.combine(date_start, datetime.time())
    datetime_end = datetime.datetime.combine(date_end, datetime.time())
    return (date_start, date_end, datetime_start, datetime_end)


@login_required
def usage(request):
    (date_start, date_end, datetime_start, datetime_end) = _get_start_and_end_date(request)
    service_list = []
    usage_list = []
    max_vcpus = max_gigabytes = 0

    if date_start > _current_month():
        messages.error(request, 'No data for the selected period')
        date_end = date_start
        datetime_end = datetime_start
    else:
        try:
            service_list = api.service_list(request)
        except api_exceptions.ApiException, e:
            LOG.error('ApiException fetching service list in instance usage',
                      exc_info=True)
            messages.error(request,
                           'Unable to get service info: %s' % e.message)

        for service in service_list:
            if service.type == 'nova-compute':
                max_vcpus += service.stats['max_vcpus']
                max_gigabytes += service.stats['max_gigabytes']

        try:
            usage_list = api.usage_list(request, datetime_start, datetime_end)
        except api_exceptions.ApiException, e:
            LOG.error('ApiException fetching usage list in instance usage'
                      ' on date range "%s to %s"' % (datetime_start,
                                                     datetime_end),
                      exc_info=True)
            messages.error(request, 'Unable to get usage info: %s' % e.message)

    dateform = forms.DateForm()
    dateform['date'].field.initial = date_start



    global_summary = {'max_vcpus': max_vcpus, 'max_gigabytes': max_gigabytes,
                      'total_active_disk_size': 0, 'total_active_vcpus': 0,
                      'total_active_ram_size': 0}

    for usage in usage_list:
        # FIXME: api needs a simpler dict interface (with iteration) - anthony
        # NOTE(mgius): Changed this on the api end.  Not too much neater, but
        # at least its not going into private member data of an external
        # class anymore
        #usage = usage._info
        for k in usage._attrs:
            v = usage.__getattr__(k)
            if type(v) in [float, int]:
                if not k in global_summary:
                    global_summary[k] = 0
                global_summary[k] += v

    max_disk_tb = used_disk_tb = available_disk_tb = 0

    max_disk_tb = global_summary['max_gigabytes'] / float(1000)
    used_disk_tb = global_summary['total_active_disk_size'] / float(1000)
    available_disk_tb = (global_summary['max_gigabytes'] / float(1000) - \
                        global_summary['total_active_disk_size'] / float(1000))
    total_ram = settings.TOTAL_CLOUD_RAM_GB
    used_ram = global_summary['total_active_ram_size'] / float(1024)
    avail_ram = total_ram - used_ram

    ram_unit = "GB"
    if total_ram > 999:
        ram_unit = "TB"
        total_ram /= float(1024)
        used_ram /= float(1024)
        avail_ram /= float(1024)

    return render_to_response(
    'syspanel_usage.html',{
        'dateform': dateform,
        'usage_list': usage_list,
        'global_summary': global_summary,
        'available_cores': global_summary['max_vcpus'] - global_summary['total_active_vcpus'],
        'available_disk': global_summary['max_gigabytes'] - global_summary['total_active_disk_size'],
        'max_disk_tb': max_disk_tb,
        'used_disk_tb': used_disk_tb,
        'available_disk_tb': available_disk_tb,
        'total_ram': total_ram,
        'used_ram': used_ram,
        'avail_ram': avail_ram,
        'ram_unit': ram_unit,
        'external_links': settings.EXTERNAL_MONITORING,
    }, context_instance = template.RequestContext(request))


@login_required
def tenant_usage(request, tenant_id):
    (date_start, date_end, datetime_start, datetime_end) = _get_start_and_end_date(request)
    if date_start > _current_month():
        messages.error(request, 'No data for the selected period')
        date_end = date_start
        datetime_end = datetime_start

    dateform = forms.DateForm()
    dateform['date'].field.initial = date_start

    usage = {}
    try:
        usage = api.usage_get(request, tenant_id, datetime_start, datetime_end)
    except api_exceptions.ApiException, e:
        LOG.error('ApiException getting usage info for tenant "%s"'
                  ' on date range "%s to %s"' % (tenant_id,
                                                 datetime_start,
                                                 datetime_end))
        messages.error(request, 'Unable to get usage info: %s' % e.message)

    return render_to_response(
    'syspanel_tenant_usage.html',{
        'dateform': dateform,
        'usage': usage,
    }, context_instance = template.RequestContext(request))


@login_required
def index(request):
    for f in (TerminateInstance, RebootInstance):
        _, handled = f.maybe_handle(request)
        if handled:
            return handled

    instances = []
    try:
        instances = api.server_list(request)
    except Exception as e:
        LOG.error('Unspecified error in instance index', exc_info=True)
        messages.error(request, 'Unable to get instance list: %s' % e.message)

    # We don't have any way of showing errors for these, so don't bother
    # trying to reuse the forms from above
    terminate_form = TerminateInstance()
    reboot_form = RebootInstance()

    return render_to_response('syspanel_instances.html', {
        'instances': instances,
        'terminate_form': terminate_form,
        'reboot_form': reboot_form,
    }, context_instance=template.RequestContext(request))
