#    Eve W-Space
#    Copyright (C) 2013  Andrew Austin and other contributors
#
#    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 3 of the License, or
#    (at your option) any later version. An additional term under section
#    7 of the GPL is included in the LICENSE file.
#
#    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, see <http://www.gnu.org/licenses/>.
from Map.models import *
from Map import utils
from API import utils as handler
from POS import tasks as pos_tasks
from POS.models import POS
from core.models import Type, Corporation
from core.utils import get_config
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
from django.http import Http404, HttpResponseRedirect, HttpResponse
from django.template.response import TemplateResponse
from django.core.urlresolvers import reverse
from django.template import RequestContext
from django.template.loader import render_to_string
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.models import Group, Permission
from django.shortcuts import render, get_object_or_404
from django.conf import settings
from datetime import datetime, timedelta, time
import pytz
import json
import eveapi
import csv

# Decorator to check map permissions. Takes request and mapID
# Permissions are 0 = None, 1 = View, 2 = Change
# When used without a permission=x specification, requires Change access

def require_map_permission(permission=2):
    def _dec(view_func):
        def _view(request, mapID, *args, **kwargs):
            map = get_object_or_404(Map, pk=mapID)
            if map.get_permission(request.user) < permission:
                raise PermissionDenied
            else:
                return view_func(request, mapID, *args, **kwargs)
        _view.__name__ = view_func.__name__
        _view.__doc__ = view_func.__doc__
        _view.__dict__ = view_func.__dict__
        return _view
    return _dec

@login_required
@require_map_permission(permission=1)
def get_map(request, mapID):
    """Get the map and determine if we have permissions to see it.
    If we do, then return a TemplateResponse for the map. If map does not
    exist, return 404. If we don't have permission, return PermissionDenied.
    """
    map = get_object_or_404(Map, pk=mapID)
    context = {'map': map, 'access': map.get_permission(request.user),
            'systemsJSON': map.as_json(request.user)}
    return TemplateResponse(request, 'map.html', context)


@login_required
@require_map_permission(permission=1)
def map_checkin(request, mapID):
    # Initialize json return dict
    jsonvalues = {}
    profile = request.user.get_profile()
    currentmap = get_object_or_404(Map, pk=mapID)

    # Out AJAX requests should post a JSON datetime called loadtime
    # back that we use to get recent logs.
    if  'loadtime' not in request.POST:
        return HttpResponse(json.dumps({error: "No loadtime"}),mimetype="application/json")
    timestring = request.POST['loadtime']

    loadtime = datetime.strptime(timestring, "%Y-%m-%d %H:%M:%S.%f")
    loadtime = loadtime.replace(tzinfo=pytz.utc)

    if request.is_igb_trusted:
        dialogHtml = checkin_igb_trusted(request, currentmap)
        if dialogHtml is not None:
            jsonvalues.update({'dialogHTML': dialogHtml})

    newlogquery = MapLog.objects.filter(timestamp__gt=loadtime, visible=True,
            map=currentmap)
    loglist = []

    for log in newlogquery:
        loglist.append("<strong>User:</strong> %s <strong>Action:</strong> %s" % (
            log.user.username, log.action))

    logstring = render_to_string('log_div.html', {'logs': loglist})
    jsonvalues.update({'logs': logstring})

    return HttpResponse(json.dumps(jsonvalues), mimetype="application/json")

@login_required
@require_map_permission(permission=1)
def map_re
fresh(request, mapID):
    """
    Returns an HttpResponse with the updated systemJSON for an asynchronous
    map refresh.
    """
    if not request.is_ajax():
        raise PermissionDenied
    map = get_object_or_404(Map, pk=mapID)
    result = [datetime.strftime(datetime.now(pytz.utc), "%Y-%m-%d %H:%M:%S.%f"),
            utils.MapJSONGenerator(map, request.user).get_systems_json()]
    return HttpResponse(json.dumps(result))

def checkin_igb_trusted(request, map):
    """
    Runs
 the specific code for the case that the request came from an igb that
    trusts us, returns None if no further action is required, returns a string
    containing the html for a system add dialog if we detect that a new system
    needs to be added
    """
    profile = request.user.get_profile()
    currentsystem = System.objects.get(name=request.eve_systemname)
    oldsystem = None
    result = None
    threshold = datetime.now(pytz.utc) - timedelta(minutes=5)
    recentlyactive = request.user.locations.filter(timestamp__gt=threshold,
            charactername=request.eve_charname).all()
    if recentlyactive.count():
        oldsystem = request.user.locations.get(charactername=request.eve_charname).system

    #Conditions for the system to be automagically added to the map. The case
    #of oldsystem == None is handled by a condition on "sys in map" (None cannot
    #be in any map), the case oldsystem == currentsystem is handled by the
    #condition that if two systems are equal one cannot be in and the other not
    #in the same map (i.e 'oldsystem in map and currentsystem not in map' will be
    #False).
    if (
      oldsystem in map
      and currentsystem not in map
      #Stop it from adding everyone's paths through k-space to the map
      and not (oldsystem.is_kspace() and currentsystem.is_kspace())
      and recentlyactive.count()
      ):
        context = { 'oldsystem' : map.systems.filter(system=oldsystem).all()[0],
                    'newsystem' : currentsystem,
                    'wormholes'  : utils.get_possible_wh_types(oldsystem, currentsystem),
                  }
        result = render_to_string('igb_system_add_dialog.html', context,
                                  context_instance=RequestContext(request))

    currentsystem.add_active_pilot(request.user, request.eve_charname,
            request.eve_shipname, request.eve_shiptypename)
    return result

def get_system_context(msID):
    mapsys = get_object_or_404(MapSystem, pk=msID)
    currentmap = mapsys.map

    #if mapsys represents a k-space system get the relevent KSystem object
    if mapsys.system.is_kspace():
        system = mapsys.system.ksystem
    #otherwise get the relevant WSystem
    else:
        system = mapsys.system.wsystem

    scanthreshold = datetime.now(pytz.utc) - timedelta(hours=int(get_config("MAP_SCAN_WARNING", None).value))
    interest_offset = int(get_config("MAP_INTEREST_TIME", None).value)
    interestthreshold = datetime.now(pytz.utc) - timedelta(minutes=interest_offset)

    scanwarning = system.lastscanned < scanthreshold
    if  interest_offset > 0:
        interest = mapsys.interesttime and mapsys.interesttime > interestthreshold
    else:
        interest = mapsys.interesttime
    return { 'system' : system, 'mapsys' : mapsys,
             'scanwarning' : scanwarning, 'isinterest' : interest }


@login_required
@require_map_permission(permission=2)
def add_system(request, mapID):
    """
    AJAX view to add a system to a map. Requires POST containing:
       topMsID: MapSystem ID of the parent MapSystem
       bottomSystem: Name of the new system
       topType: WormholeType name of the parent side
       bottomType: WormholeType name of the new side
       timeStatus: Womrhole time status integer value
       massStatus: Wormhole mass status integer value
       topBubbled: 1 if Parent side bubbled
 