import gzip
import json
import os

from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.paginator import EmptyPage
from django.core.paginator import PageNotAnInteger
from django.core.paginator import Paginator
from django.db.models import Avg
from django.db.models import Count
from django.db.models import Max
from django.db.models import Min
from django.db.models import Q
from django.db.models import Sum
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.shortcuts import redirect
from django.shortcuts import render
from django.template import RequestContext
from django.utils.text import slugify
from django.views.generic import DeleteView
from individuals.forms import IndividualForm, ComparisonForm, GroupForm, BrowserForm
from individuals.models import Individual, Group
from individuals.tasks import VerifyVCF, AnnotateVariants, PopulateVariants
from variants.models import Variant

def response_mimetype(request):
    if "application/json" in request.META['HTTP_ACCEPT']:
        return "application/json"
    else:
        return "text/plain"


class JSONResponse(HttpResponse):
    """JSON response class."""
    def __init__(self,obj='',json_opts={},mimetype="application/json",*args,**kwargs):
        content = json.dumps(obj,**json_opts)
        super(JSONResponse,self).__init__(content,mimetype,*args,**kwargs)

def create(request):
    if request.method == 'POST':
        form = IndividualForm(request.POST, request.FILES)
        
        if form.is_valid():
            
            if request.user.is_authenticated:
                individual = Individual.objects.create(user=request.user, status='new')
            else:
                individual = Individual.objects.create(user=None, status='new')

            individual.vcf_file= request.FILES.get('file')
            
            print('file')
            print(request.FILES.get('file'))

            filename = individual.vcf_file.name.split('.')
            new_filename = [] 
            for tag in filename:
                new_filename.append(slugify(tag))

            individual.vcf_file.name = ".".join(new_filename)

            print('filename ', filename)

            #get name from inside vcf file
            individual.name= str(os.path.splitext(individual.vcf_file.name)[0]).replace('.vcf','').replace('.gz','').replace('.rar','').replace('.zip','').replace('._',' ').replace('.',' ')

            # individual.shared_with_groups = form.cleaned_data['shared_with_groups']

            individual.shared_with_groups.set(form.cleaned_data['shared_with_groups'])
            
            individual.save()
            
            f = individual.vcf_file
            
            #fix permissions
            #os.chmod("%s/genomes/%s/" % (settings.BASE_DIR, individual.user), 0777)

            #if request.user.is_authenticated:

            #    os.chmod("%s/genomes/%s/%s" % (settings.BASE_DIR, slugify(individual.user), individual.id), 0o777)
            #else:
            #    os.chmod("%s/genomes/public/%s" % (settings.BASE_DIR, individual.id), 0o777)

            # AnnotateVariants.delay(individual.id)
            VerifyVCF.delay(individual.id)

            data = {'files': [{'deleteType': 'DELETE', 'name': individual.name, 'url': '', 'thumbnailUrl': '', 'type': 'image/png', 'deleteUrl': '', 'size': f.size}]}

            response = JSONResponse(data, mimetype=response_mimetype(request))
            response['Content-Disposition'] = 'inline; filename=files.json'

            return response
        else:
            print(form.errors)

    else:
        form = IndividualForm()

    return render(request, 'individuals/create.html', {'form':form})

# Create your views here.
@login_required
def edit(request, individual_id):
    individual = get_object_or_404(Individual, pk=individual_id)
    if request.method == 'POST':
        form = IndividualForm(request.POST, instance=individual)
        if form.is_valid():
            form.save()
            return redirect('dashboard')
    #     form = IndividualForm(request.POST, request.FILES)
    #     if form.is_valid():
    #         individual = form.save(commit=False)
    #         individual.user = request.user
    #         individual.save()
    #         return redirect('dashboard')
    else:
        form = IndividualForm(instance=individual)

    return render(request, 'individuals/individual_form.html', {'form':form})


class IndividualDeleteView(DeleteView):
    model = Individual

    def delete(self, request, *args, **kwargs):
        """
        This does not actually delete the file, only the database record.  But
        that is easy to implement.
        """
        self.object = self.get_object()
        individual_id = self.object.id

        if self.object.user:
            username = self.object.user.username
        else:
            username = 'public'
        
        #delete files
        if self.object.vcf_file:
            self.object.vcf_file.delete()

        # if self.object.strs_file:
        #     self.object.strs_file.delete()
        # if self.object.cnvs_file:
        #     self.object.cnvs_file.delete()
        os.system('rm -rf %s/genomes/%s/%s' % (settings.BASE_DIR, username, individual_id))

        self.object.delete()
        
        
        
        
#        response = JSONResponse(True, {}, response_mimetype(self.request))
#        response['Content-Disposition'] = 'inline; filename=files.json'
#        return response
        messages.add_message(request, messages.INFO, "Individual deleted with success!")
        #return redirect('individuals_list')
        return redirect('individuals_list')


def view(request, individual_id):

    individual = get_object_or_404(Individual, pk=individual_id)

    variant_list = Variant.objects.filter(individual=individual)
    # snpeff = SnpeffAnnotation.objects.filter(individual=individual)

    individual.n_variants = variant_list.count()
    individual.novel_variants = variant_list.filter(variant_id = '.').count()

    individual.summary = []

    #get calculated values from database

    summary_item = {
                'type': 'Total SNVs',
                'total': variant_list.values('genotype').count(),
                'discrete': variant_list.values('genotype').annotate(total=Count('genotype'))
                    }
    individual.summary.append(summary_item)

    summary_item = {
                'type': 'Total Gene-associated SNVs',
                'total': variant_list.values('gene').exclude(gene="").count(),
                'discrete': variant_list.exclude(gene="").values('genotype').annotate(total=Count('genotype'))
                    }
    individual.summary.append(summary_item)

    individual.snp_eff = variant_list.values('snpeff_effect').annotate(Count('snpeff_effect')).order_by('snpeff_effect')
    # print 'individual.snp_eff', individual.snp_eff
    # variant_list.values('snpeff__effect').annotate(Count('snpeff__effect')).order_by('snpeff__effect')
    #
    individual.functional_class = variant_list.values('snpeff_func_class').annotate(Count('snpeff_func_class')).order_by('snpeff_func_class')
    individual.impact_variants = variant_list.values('snpeff_impact').annotate(Count('snpeff_impact')).order_by('snpeff_impact')

    individual.filter_variants = variant_list.values('filter').annotate(Count('filter')).order_by('filter')
    individual.quality = variant_list.aggregate(Avg('qual'), Max('qual'), Min('qual'))
    individual.read_depth = variant_list.aggregate(Avg('read_depth'), Max('read_depth'), Min('read_depth'))

    individual.clinvar_clnsig = variant_list.values('clinvar_clnsig').annotate(total=Count('clinvar_clnsig'))

    individual.chromossome = variant_list.values('chr').annotate(total=Count('chr')).order_by('chr')

    # variants_with_snpid = variant_list.values('variant_id').exclude(variant_id=".")
    #print variants_with_snpid

    # fields = Variant._meta.get_all_field_names()

    paginator = Paginator(variant_list, 25) # Show 25 contacts per page
    try:
        page = int(request.GET.get('page', '1'))
    except ValueError:
        page = 1
    try:
        variants = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        variants = paginator.page(1)
    except EmptyPage:
        # If page is out of range (e.g. 9999), deliver last page of results.
        variants = paginator.page(paginator.num_pages)
    #'fields':fields
    return render(request, 'individuals/view.html', {'individual': individual, 'variants':variants})

@login_required
def browse(request, individual_id):

    query_string = request.META['QUERY_STRING']
    individual = get_object_or_404(Individual, pk=individual_id)
    query = {}
    
#    DEFAULT_SORT = 'pk'
#    sort_key = request.GET.get('sort', DEFAULT_SORT)
    # tags = ['genotype', 'snpeffannotation__effect']#, 'func_class', 'impact', 'cln_omim', 'chr' 
    # for tag in tags:
    #     criteria = request.GET.get(tag, '')
    #     if criteria:
    #         query[tag] = criteria

    
    if request.method == 'GET':
        form = BrowserForm(request.GET)   
        if form.is_valid():
            print('form is valid')
            #chr
            chr = request.GET.get('chr', '')
            if chr != '':
                query['chr'] = chr
            #pos
            pos = request.GET.get('pos', '')
            if pos != '':
                query['pos'] = pos

            effect = request.GET.get('effect', '')
            if effect != '':
                print('effect', effect)
                query['snpeff_effect'] = effect                
            #snp_id
            # snp_id = request.GET.get('snp_id', '')
            # if snp_id != '':
            #     query['variant_id'] = snp_id
            # snp_list = request.GET.get('snp_list', '')
            # snp_list = snp_list.split('\r\n')
            # if snp_list[0] != u'':
            #     query['variant_id__in'] = snp_list
            # snp_eff = request.GET.getlist('effect')
            # if len(snp_eff) > 0:
            #     query['snp_eff__in'] = snp_eff
            # func_class = request.GET.getlist('func_class')
            # if len(func_class) > 0:
            #     query['snp_eff_functional_class__in'] = func_class
            # gene = request.GET.get('gene', '')
            # if gene != '':
            #     query['gene_name'] = gene
            # gene_list = request.GET.get('gene_list', '')
            # gene_list = gene_list.split('\r\n')
            # if gene_list[0] != u'':
            #     query['gene_name__in'] = gene_list
            # cln = request.GET.get('cln_omim', '')
            # print 'clnomim', cln
            # if cln == 'on':
            #     query['cln_omim'] != ''

            variants = Variant.objects.filter(individual=individual, **query)

            # snpeff_annotations = SnpeffAnnotation.objects.filter(variant__in=variants)
            # #b.entry_set.filter(headline__contains='Lennon')

            # print 'snpeff_annotations', len(snpeff_annotations)

            # for variant in variants:
            #     print variant.entry_set.all()
            
            #     variant.snpeff=

    
    else:
        
        form = BrowserForm(request.GET)
        variants = Variant.objects.filter(individual=individual, **query)
        
        
    #Pagination
    paginator = Paginator(variants, 25) # Show 25 contacts per page
    try:
       page = int(request.GET.get('page', '1'))
    except ValueError:
       page = 1
    try:
       variants = paginator.page(page)
    except PageNotAnInteger:
       # If page is not an integer, deliver first page.
       variants = paginator.page(1)
    except EmptyPage:
       # If page is out of range (e.g. 9999), deliver last page of results.
       variants = paginator.page(paginator.num_pages)
    
    return render(request, 'variants/variants.html', {'individual': individual, 'variants':variants, 'form':form, 'query_string':query_string})

@login_required
def list(request):

    if request.method == 'POST':
        individuals = request.POST.getlist('individuals')
        print(individuals) 
        individuals = [int(x) for x in individuals]
        print(individuals)
        
        if request.POST['selectionField'] == "Show":
            for individual_id in individuals:
                individual = get_object_or_404(Individual, pk=individual_id)
                individual.is_featured = True
                individual.save()
        if request.POST['selectionField'] == "Hide":
            for individual_id in individuals:
                individual = get_object_or_404(Individual, pk=individual_id)
                individual.is_featured = False
                individual.save()
        if request.POST['selectionField'] == "Delete":
            for individual_id in individuals:
                individual = get_object_or_404(Individual, pk=individual_id)


                individual_id = individual.id
                username = individual.user.username

                #delete files
                if individual.vcf_file:
                    individual.vcf_file.delete()
                # if individual.strs_file:
                #     individual.strs_file.delete()
                # if individual.cnvs_file:
                #     individual.cnvs_file.delete()
                os.system('rm -rf %s/genomes/%s/%s' % (settings.BASE_DIR, username, individual_id))

                individual.delete()
            #os.system('rm -rf mendelmd14/site_media/media/genomes/%s/%s' % (username, individual_id))
        if request.POST['selectionField'] == "Populate":
            for individual_id in individuals:
                individual = get_object_or_404(Individual, pk=individual_id)
                PopulateVariants.delay(individual.id)
            
        if request.POST['selectionField'] == "Annotate":
            for individual_id in individuals:
                individual = get_object_or_404(Individual, pk=individual_id)
                AnnotateVariants.delay(individual.id)
        if request.POST['selectionField'] == "Find_Medical_Conditions_and_Medicines":
            for individual_id in individuals:
                individual = get_object_or_404(Individual, pk=individual_id)
                Find_Medical_Conditions_and_Medicines.delay(individual.id)
        
    
    args = []
    # groups = Groups.objects.filter(user=request.user, shared_with_users=).order_by("-id")
    args.append(Q(user=request.user) | Q(shared_with_users=request.user) | Q(shared_with_groups__members=request.user))
    
    if request.user.is_staff:
        individuals = Individual.objects.all()
    else:
        individuals = Individual.objects.filter(*args).order_by("-id")
    
    ind_featured = Individual.objects.filter(is_featured= True).order_by("id")
    # paginator = Paginator(individuals, 25) # Show 25 contacts per page
           
    # try:
    #    page = int(request.GET.get('page', '1'))
    # except ValueError:
    #    page = 1
    # try:
    #    individuals = paginator.page(page)
    # except PageNotAnInteger:
    #    # If page is not an integer, deliver first page.
    #    individuals = paginator.page(1)
    # except EmptyPage:
    #    # If page is out of range (e.g. 9999), deliver last page of results.
    #    individuals = paginator.page(paginator.num_pages)



    groups = Group.objects.all()
#    individuals = Individual.objects.annotate(number_of_variants=Count('variant'))
    
    
    return render(request, 'individuals/list.html', {'individuals': individuals, 'groups':groups, 'ind_featured':ind_featured})


@login_required
def annotate(request, individual_id):
    individual = get_object_or_404(Individual, pk=individual_id)
    individual.status = 'new'
    individual.n_lines = 0
    VerifyVCF.delay(individual.id)
    individual.save()
    messages.add_message(request, messages.INFO, "Your individual is being annotated.")
    return redirect('dashboard')

@login_required
def populate(request, individual_id):
    individual = get_object_or_404(Individual, pk=individual_id)
    PopulateVariants.delay(individual.id)
    messages.add_message(request, messages.INFO, "Your individual is being populated.")

    return redirect('dashboard')


@login_required
def populate_mongo(request, individual_id):
    individual = get_object_or_404(Individual, pk=individual_id)
    PopulateMongoVariants.delay(individual.id)
    messages.add_message(request, messages.INFO, "Your individual is being inserted at MongoDB.")

    return redirect('individuals_list')


def download(request, individual_id):
    individual = get_object_or_404(Individual, pk=individual_id)
    
    filepath = os.path.dirname(str(individual.vcf_file.name))
    filename = os.path.basename(str(individual.vcf_file.name))
    
    path = ''
    # os.chmod("%s/genomes/%s/%s" % (settings.MEDIA_ROOT, individual.user, individual.id), 0777)

    
    # if filename.endswith('vcf.zip'):
       # basename = filename.split('.vcf.zip')[0]       
    # elif filename.endswith('.zip'):
       # basename = filename.split('.zip')[0]       
    # else:
       # basename = filename.split('.vcf')[0]
    #print basename
    #print path
    #print filepath
    
    fullpath = '%s/%s' % (filepath, filename)
    if filename.endswith('.gz'):
        vcffile = gzip.open(fullpath, 'r')
    else:
        vcffile = open(fullpath, 'r')

    content = vcffile.read()
    vcffile.close()

    response = HttpResponse(content, content_type='text/plain')
    response['Content-Disposition'] = 'attachment; filename=%s' % filename
    response['Content-Length'] = os.path.getsize(fullpath)
    return response



def download_annotated(request, individual_id):
    individual = get_object_or_404(Individual, pk=individual_id)
    
    filepath = os.path.dirname(str(individual.vcf_file.name))
    filename = os.path.basename(str(individual.vcf_file.name))
    
    # path = settings.MEDIA_ROOT
    # if filename.endswith('vcf.zip'):
       # basename = filename.split('.vcf.zip')[0]       
    # else:
    
    basename = filename.split('.vcf')[0]
    
    fullpath = '%s/annotation.final.vcf.zip' % (filepath)

    vcffile = open(fullpath, 'rb')

    response = HttpResponse(vcffile, content_type='application/x-zip-compressed')
    # # response['Content-Encoding'] = 'gzip'
    response['Content-Disposition'] = 'attachment; filename=%s.annotated.mendelmd.vcf.zip' % basename
    response['Content-Length'] = os.path.getsize(fullpath)
    return response

@login_required
def create_group(request):
    if request.method == 'POST':
        form = GroupForm(request.POST, request.FILES)        
        if form.is_valid():
            form.save()
            
            return redirect('individuals_list')
    else:
        form = GroupForm()
    return render(request, 'groups/create_group.html', {'form': form})

@login_required
def view_group(request, group_id):
    group = get_object_or_404(Group, pk=group_id)
    return render(request, 'groups/view_group.html', {'group': group})

class GroupDeleteView(DeleteView):
    model = Group

    def delete(self, request, *args, **kwargs):
        """
        This does not actually delete the file, only the database record.  But
        that is easy to implement.
        """
        self.object = self.get_object()
        
        #username = self.object.user.username
        
        self.object.delete()
        messages.add_message(request, messages.INFO, "Group deleted with success!")
        return redirect('individuals_list')


def comparison(request):
    query = {}
    summary = {}
    variants = []
    query_string = request.META['QUERY_STRING']
    if request.method == 'GET':
        form = ComparisonForm(request.user, request.GET, request.FILES)        
        if form.is_valid():
            
            individual_one_id = request.GET.get('individual_one', '')
            individual_two_id = request.GET.get('individual_two', '')
            read_depth = request.GET.get('read_depth', '')
            if read_depth != '':
                query['read_depth__gte'] = float(read_depth)
            if individual_one_id != '' and individual_two_id != '': 
                variants_ind_one = Variant.objects.filter(individual__id=individual_one_id, **query).values('chr', 'pos', 'genotype')
                
                variants_ind_two = Variant.objects.filter(individual__id=individual_two_id, **query).values('chr', 'pos', 'genotype')
                print('Got Variants from Both!')
    
                genotypes_in_common = 0
                genotypes_not_in_common = 0
                ind_one = {}
                ind_two = {}
                summary['variants_ind_one'] = variants_ind_one.count()
                 
                for variant in variants_ind_one:
                    id = '%s-%s' % (variant['chr'], variant['pos'])
                    if id in ind_one:                 
                        ind_one[id].append(variant['genotype'])
                    else:
                        ind_one[id] = []
                        ind_one[id].append(variant['genotype'])
                        
                summary['variants_ind_two'] = variants_ind_two.count()
                for variant in variants_ind_two:
                    id = '%s-%s' % (variant['chr'], variant['pos'])
                    if id in ind_two:                 
                        ind_two[id].append(variant['genotype'])
                    else:
                        ind_two[id] = []
                        ind_two[id].append(variant['genotype'])
                    
                
                print('Finished creating indexes')
                for pos in ind_one:
                    if pos in ind_two:
                        for genotype in ind_one[pos]:
                            
                            if genotype in ind_two[pos]:
                                genotypes_in_common += 1
    #                            variant ={}
    #                            variant['chr'] = item.split('-')[0]
    #                            variant['pos'] = item.split('-')[1]
    #                            variant['genotype'] = ind_two[item]
                                
    #                            variants.append(variant) 
                            else:
                                genotypes_not_in_common += 1
                        
    #                        
                print('genotypes in common: %s' % genotypes_in_common)
                summary['genotypes_in_common'] = genotypes_in_common
                summary['genotypes_not_in_common'] = genotypes_not_in_common
                summary['total_variants'] = genotypes_in_common + genotypes_not_in_common
                
                summary['percent_ind_one'] = round((float(genotypes_in_common)/summary['variants_ind_one'])*100, 2)
                summary['percent_ind_two'] = round((float(genotypes_in_common)/summary['variants_ind_two'])*100, 2)
                print(summary)
            
    else:
        form = ComparisonForm(request.user)
        
        
    return render(request, 'individuals/comparison.html', {'form':form, 'summary':summary, 'query_string':query_string})