#
#   Copyright 2017 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
#
#   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  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.
#

import json

from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, JsonResponse
from django.middleware.csrf import get_token
from django.shortcuts import render, redirect
from django.template.loader import render_to_string
from lib.util import Util
from sf_user.models import CustomUser
import tarfile


from projecthandler.osm_model import OsmProject
from projecthandler.models import Project


Project.add_project_type('osm', OsmProject)



from projecthandler.models import Repository

@login_required
def home(request):
    return render(request, 'home.html', {})


@login_required
def create_new_project(request):
    if request.method == 'POST':
        error_msgs = []
        user = CustomUser.objects.get(id=request.user.id)
        name = request.POST.get('name', 'WithoutName')
        info = request.POST.get('info', ' ')
        type = request.POST.get('type', '')
        start_from = request.POST.get('startfrom', 'scratch')

        project_types = Project.get_project_types()
        if type in project_types:
            project_class = project_types[type]

        else:
            # FIXME this error is not handled
            error_msgs.append('Project type undefined.')
            return render(request, 'error.html',
                          {'error_msg': 'Error creating new project, project type undefined. Please retry.'})

        try:

            if start_from == 'scratch':
                print 'from scratch'
                data_project = {}

            elif start_from == 'files':
                print 'from files'
                data_project = project_class.data_project_from_files(request)

            elif start_from == 'example':
                print 'from example'
                data_project = project_class.data_project_from_example(request)

            project = project_class.create_project(name, user, False, info, data_project)
            # print project.get_dataproject()


        except Exception as e:
            print 'Error creating ' + type + ' project! Please retry.'
            print e
            return render(request, 'error.html', {'error_msg': 'Error creating ' + type + ' project! Please retry.'})
        return redirect('projects:open_project', project_id=project.id)

    elif request.method == 'GET':
        csrf_token_value = get_token(request)
        result = {}
        data_type_selector = [{
            'id': '-1',
            'text': 'Select an option'
        }]
        type_example_files = {}
        type_container_template = ''
        project_types = Project.get_project_types()
        print "project_types", project_types.keys()
        for type in project_types:
            project_class = project_types[type]
            type_example_files.update(project_class.get_example_list())
            data_type_selector.append({
                'id': type,
                'text': type,
                'value': type
            })
            type_container_template += render_to_string(type + '/' + type + '_new_project.html')

        result.update({'type_example_files': json.dumps(type_example_files)})
        result.update({'data_type_selector': json.dumps(data_type_selector)})
        result.update({'type_container_template': type_container_template})
        result.update({'csrf_token': csrf_token_value})
        return render(request, 'new_project.html', result)


@login_required
def user_projects(request):
    csrf_token_value = get_token(request)
    user = CustomUser.objects.get(id=request.user.id)
    projects = Project.objects.filter(owner=user).select_subclasses()

    return render(request, 'projectlist.html', {
        'projects': list(projects),
        'csrf_token': csrf_token_value
    })


@login_required
def open_project(request, project_id=None):
    try:
        projects = Project.objects.filter(id=project_id).select_subclasses()
        project_overview = projects[0].get_overview_data()
        prj_token = project_overview['type']
        print request.COOKIES.keys()
        return render(request, prj_token + '/' + prj_token + '_project_details.html',
                      {'project_overview': project_overview, 'project_id': project_id})

    except Exception as e:
        print e
        return render(request, 'error.html', {'error_msg': 'Error open project! Please retry.'})


@login_required
def delete_project(request, project_id=None):
    if request.method == 'POST':

        try:
            Project.objects.filter(id=project_id).delete()
            return redirect('projects:projects_list')
        except Exception as e:
            print e
            return render(request, 'error.html', {'error_msg': 'Error deleting Project.'})

    elif request.method == 'GET':
        try:
            projects = Project.objects.filter(id=project_id).select_subclasses()
            project_overview = projects[0].get_overview_data()
            prj_token = project_overview['type']
            #                 example: 'etsi/etsi_project_delete.html'
            print  prj_token + '/' + prj_token + '_project_delete.html', project_overview['name']
            return render(request, prj_token + '/' + prj_token + '_project_delete.html',
                          {'project_id': project_id, 'project_name': project_overview['name']})

        except Exception as e:
            print e
            return render(request, 'error.html', {'error_msg': 'Project not found.'})



@login_required
def show_descriptors(request, project_id=None, descriptor_type=None):
    csrf_token_value = get_token(request)
    projects = Project.objects.filter(id=project_id).select_subclasses()
    project_overview = projects[0].get_overview_data()
    prj_token = project_overview['type']

    page = prj_token + '/' + prj_token + '_project_descriptors.html'

    return render(request, page, {
        'descriptors': projects[0].get_descriptors(descriptor_type),
        'project_id': project_id,
        'project_type': prj_token,
        'project_overview_data': project_overview,
        "csrf_token_value": csrf_token_value,
        'descriptor_type': descriptor_type
    })


@login_required
def graph(request, project_id=None):
    if request.method == 'GET':
        csrf_token_value = get_token(request)
        projects = Project.objects.filter(id=project_id).select_subclasses()
        project_overview = projects[0].get_overview_data()
        prj_token = project_overview['type']
        # example : 'etsi/project_graph.html'
        return render(request, prj_token + '/project_graph.html', {
            'project_id': project_id,
            'project_overview_data': projects[0].get_overview_data(),
            'collapsed_sidebar': False
        })


@login_required
def graph_data(request, project_id=None, descriptor_id=None):
    print 'graph_data', project_id, descriptor_id
    projects = Project.objects.filter(id=project_id).select_subclasses()
    project_overview = projects[0].get_overview_data()
    # data = projects[0].get_overview_data()
    prj_token = project_overview['type']

    topology = projects[0].get_graph_data_json_topology(descriptor_id)
    response = HttpResponse(topology, content_type="application/json")
    response["Access-Control-Allow-Origin"] = "*"

    return response


@login_required
def delete_descriptor(request, project_id=None, descriptor_type=None, descriptor_id=None):
    csrf_token_value = get_token(request)
    projects = Project.objects.filter(id=project_id).select_subclasses()
    result = projects[0].delete_descriptor(descriptor_type, descriptor_id)
    project_overview = projects[0].get_overview_data()
    prj_token = project_overview['type']
    page = prj_token + '/' + prj_token + '_project_descriptors.html'

    return render(request, page, {
        'descriptors': projects[0].get_descriptors(descriptor_type),
        'project_id': project_id,
        'project_overview_data': project_overview,
        "csrf_token_value": csrf_token_value,
        'descriptor_type': descriptor_type,
        #'alert_message': {
        #    'success': result,
        #    'message': "Delete succeeded!" if result else 'Error in delete'}
    })


@login_required
def clone_descriptor(request, project_id=None, descriptor_type=None, descriptor_id=None):
    csrf_token_value = get_token(request)
    projects = Project.objects.filter(id=project_id).select_subclasses()
    new_id = request.GET.get('newid', '')
    result = projects[0].clone_descriptor(descriptor_type, descriptor_id, new_id)
    project_overview = projects[0].get_overview_data()
    prj_token = project_overview['type']
    page = prj_token + '/' + prj_token + '_project_descriptors.html'

    return render(request, page, {
        'descriptors': projects[0].get_descriptors(descriptor_type),
        'project_id': project_id,
        'project_overview_data': project_overview,
        "csrf_token_value": csrf_token_value,
        'descriptor_type': descriptor_type,
        'alert_message': {
            'success': result,
            'message': "Cloned!" if result else 'Error in cloning'}
    })


@login_required
def new_descriptor(request, project_id=None, descriptor_type=None):
    projects = Project.objects.filter(id=project_id).select_subclasses()
    project_overview = projects[0].get_overview_data()
    prj_token = project_overview['type']
    page = prj_token + '/descriptor/descriptor_new.html'
    if request.method == 'GET':
        request_id = request.GET.get('id', '')

        json_template = projects[0].get_new_descriptor(descriptor_type, request_id)
        print 'new descriptor GET', json_template

        descriptor_string_yaml = Util.json2yaml(json_template)
        descriptor_string_json = json.dumps(json_template)

        return render(request, page, {
            'project_id': project_id,
            'descriptor_type': descriptor_type,
            'descriptor_id': request_id,
            'project_overview_data': project_overview,
            'descriptor_strings': {'descriptor_string_yaml': descriptor_string_yaml,
                                   'descriptor_string_json': descriptor_string_json}
        })
    elif request.method == 'POST':
        csrf_token_value = get_token(request)
        data_type = request.POST.get('type')
        print "TYPE", data_type
        if data_type == "file":
            file_uploaded = request.FILES['file']
            text = file_uploaded.read()
            data_type = file_uploaded.name.split(".")[-1]
            desc_name = file_uploaded.name.split(".")[0]
            result = projects[0].create_descriptor(desc_name, descriptor_type, text, data_type, file_uploaded)
        else:
            text = request.POST.get('text')
            desc_name = request.POST.get('id')
            result = projects[0].create_descriptor(desc_name, descriptor_type, text, data_type)


        response_data = {
            'project_id': project_id,
            'descriptor_type': descriptor_type,
            'project_overview_data': projects[0].get_overview_data(),
            'descriptor_id': result,
            'alert_message': {
                'success': True if result != False else False,
                'message': "Descriptor created" if result else 'Error in creation'}
        }
        status_code = 200 if result != False else 500
        response = HttpResponse(json.dumps(response_data), content_type="application/json", status=status_code)
        response["Access-Control-Allow-Origin"] = "*"
        return response


@login_required
def edit_descriptor(request, project_id=None, descriptor_id=None, descriptor_type=None):
    if request.method == 'POST':
        print "edit_descriptor"
        projects = Project.objects.filter(id=project_id).select_subclasses()
        result = projects[0].edit_descriptor(descriptor_type, descriptor_id, request.POST.get('text'),
                                             request.POST.get('type'))
        response_data = {
            'project_id': project_id,
            'descriptor_type': descriptor_type,
            #'project_overview_data': projects[0].get_overview_data(),
            'alert_message': {
                'success':  True if result else False,
                'message': "Descriptor modified." if result else 'Error during descriptor editing.'}
        }
        status_code = 200 if result else 500
        response = HttpResponse(json.dumps(response_data), content_type="application/json", status=status_code)
        response["Access-Control-Allow-Origin"] = "*"
        return response

    elif request.method == 'GET':
        csrf_token_value = get_token(request)
        projects = Project.objects.filter(id=project_id).select_subclasses()
        project_overview = projects[0].get_overview_data()
        print project_overview
        prj_token = project_overview['type']
        page = prj_token + '/descriptor/descriptor_view.html'

        descriptor = projects[0].get_descriptor(descriptor_id, descriptor_type)

        descriptor_string_json = json.dumps(descriptor)
        descriptor_string_yaml = Util.json2yaml(descriptor)
        # print descriptor
        return render(request, page, {
            'project_id': project_id,
            'descriptor_id': descriptor_id,
            'project_overview_data': projects[0].get_overview_data(),
            'descriptor_type': descriptor_type,
            'descriptor_strings': {'descriptor_string_yaml': descriptor_string_yaml,
                                   'descriptor_string_json': descriptor_string_json}})


@login_required
def graph_positions(request, project_id=None):
    if request.method == 'POST':
        projects = Project.objects.filter(id=project_id).select_subclasses()
        result = projects[0].edit_graph_positions(json.loads(request.POST.get('positions')))
        status_code = 200 if result else 500
        response = HttpResponse(json.dumps({}), content_type="application/json", status=status_code)
        response["Access-Control-Allow-Origin"] = "*"
        return response


@login_required
def add_element(request, project_id=None):
    if request.method == 'POST':
        projects = Project.objects.filter(id=project_id).select_subclasses()
        result = projects[0].get_add_element(request)

        status_code = 200 if result else 500
        response = HttpResponse(json.dumps({}), content_type="application/json", status=status_code)
        response["Access-Control-Allow-Origin"] = "*"
        return response


@login_required
def remove_element(request, project_id=None):
    if request.method == 'POST':
        projects = Project.objects.filter(id=project_id).select_subclasses()
        result = projects[0].get_remove_element(request)

        status_code = 200 if result else 500
        response = HttpResponse(json.dumps({}), content_type="application/json", status=status_code)
        response["Access-Control-Allow-Origin"] = "*"
        return response


@login_required
def add_link(request, project_id=None):
    if request.method == 'POST':
        projects = Project.objects.filter(id=project_id).select_subclasses()
        result = projects[0].get_add_link(request)

        status_code = 200 if result else 500
        response = HttpResponse(json.dumps({}), content_type="application/json", status=status_code)
        response["Access-Control-Allow-Origin"] = "*"
        return response


@login_required
def remove_link(request, project_id=None):
    if request.method == 'POST':
        projects = Project.objects.filter(id=project_id).select_subclasses()
        result = projects[0].get_remove_link(request)

        status_code = 200 if result else 500
        response = HttpResponse(json.dumps({}), content_type="application/json", status=status_code)
        response["Access-Control-Allow-Origin"] = "*"
        return response

@login_required
def get_available_nodes(request, project_id=None):
    if request.method == 'GET':
        csrf_token_value = get_token(request)
        projects = Project.objects.filter(id=project_id).select_subclasses()
        print "get_available_nodes", request.GET.dict()
        result = projects[0].get_available_nodes(request.GET.dict())
        status_code = 500 if result == None else 200
        print json.dumps(result)
        response = HttpResponse(json.dumps(result), content_type="application/json", status=status_code)
        response["Access-Control-Allow-Origin"] = "*"
        return response

@login_required
def overviewelement(request, project_id=None):
    if request.method == 'GET':
        result = {}
        error_msg = None
        try:
            projects = Project.objects.filter(id=project_id).select_subclasses()
            project = projects[0]
            parameters = request.GET.dict()
            print "parameters", parameters
            result = project.get_node_overview(**parameters)
        except Exception as e:
            error_msg = str(e)

        if error_msg is not None:
            return JsonResponse({'error': {'error_msg': str(error_msg)}})

        return JsonResponse({'node_overview': result})

# ETSI specific method #
@login_required
def add_node_to_vnffg(request, project_id=None):
    print "add_node_to_vnffg"  # TODO log
    if request.method == 'POST':
        projects = Project.objects.filter(id=project_id).select_subclasses()
        result = projects[0].add_node_to_vnffg(request)

        status_code = 200 if result else 500
        response = HttpResponse(json.dumps({}), content_type="application/json", status=status_code)
        response["Access-Control-Allow-Origin"] = "*"
        return response


@login_required
def unused_vnf(request, project_id=None, nsd_id=None):
    if request.method == 'GET':
        print 'in method unused_vnf : ', project_id, nsd_id  # TODO log
        projects = Project.objects.filter(id=project_id).select_subclasses()
        result = projects[0].get_unused_vnf(nsd_id)
        status_code = 500 if result == None else 200
        response = HttpResponse(json.dumps(result), content_type="application/json", status=status_code)
        response["Access-Control-Allow-Origin"] = "*"
        return response

# end ETSI specific method #


# OSM specific method #
def get_package_files_list(request, project_id, project, descriptor_id, descriptor_type):
    files_list = []
    try:
        files_list = project.get_package_files_list(descriptor_type, descriptor_id)
        result = {'files': files_list}
    except Exception as e:
        print e
        url = 'error.html'
        result = {'error_msg': 'Unknown error.'}
    return __response_handler(request, result)


def download_pkg(request, project_id, project, descriptor_id, descriptor_type):
    tar_pkg = project.download_pkg(project, descriptor_id, descriptor_type)

    response = HttpResponse(content_type="application/tgz")
    response["Content-Disposition"] = "attachment; filename=osm_export.tar.gz"
    response.write(tar_pkg.getvalue())
    return response


def create_ns(request, project_id, project, descriptor_id, descriptor_type):
    files_list = []
    try:
        ns_data={
          "nsName": request.POST.get('nsName', 'WithoutName'),
          "nsDescription": request.POST.get('nsDescription', ''),
          "nsdId": request.POST.get('nsdId', ''),
          "vimAccountId": request.POST.get('vimAccountId', ''),
          "ssh-authorized-key": [
            {
              request.POST.get('key-pair-ref', ''): request.POST.get('keyValue', '')
            }
          ]
        }
        #result = project.create_ns(descriptor_type, descriptor_id, ns_data)

    except Exception as e:
        print e
        url = 'error.html'
        result = {'error_msg': 'Unknown error.'}
    return __response_handler(request, result)

# end OSM specific method #

@login_required
def custom_action(request, project_id=None, descriptor_id=None, descriptor_type=None, action_name=None):
    if request.method == 'GET':
        projects = Project.objects.filter(id=project_id).select_subclasses()
        print "Custom action: " + action_name
        return globals()[action_name](request, project_id, projects[0], descriptor_id, descriptor_type)


def __response_handler(request, data_res, url=None, to_redirect=None, *args, **kwargs):
    raw_content_types = request.META.get('HTTP_ACCEPT', '*/*').split(',')
    if 'application/json' in raw_content_types:
        return JsonResponse(data_res)
    elif to_redirect:
        return redirect(url, *args, **kwargs)
    else:
        return render(request, url, data_res)
