# -*- coding: utf-8 -*-
"""
Created on Nov 17, 2016

@author: noob
"""
import collections
import json
import logging
from datetime import datetime
import re

from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponse, HttpResponseRedirect
from django.http.response import HttpResponseBadRequest
from django.shortcuts import render_to_response
from django.template.context import RequestContext
from django.views.decorators.csrf import csrf_exempt
from django_yauth.decorators import yalogin_required

import settings
from common.models import Task
from common.util.clients import link_and_create_task, TaskError, ClickhouseClient
from common.views import get_common
from mobilecompare.models import CompareMobileJobsManager
from mobilepage.models import MobileJob, MobileComponent


@yalogin_required
def mobilepage(request, job):
    """

    :param request: HTTP request
    :param job: Job NUMBER
    """
    user = request.yauser
    common_data = get_common(request)
    try:
        job_obj = MobileJob.objects.get(n=job)
    except ObjectDoesNotExist:
        return render_to_response('error.html',
                                  {'common': common_data, 'error': 'no_job'},
                                  RequestContext(request))
    try:
        task = Task.objects.filter(key=job_obj.task)[0]
        try:
            navfire_a = MobileJob.objects.filter(task=job_obj.task).order_by('-n')[:50]
        except:
            logging.exception('')
            navfire_a = []
        manager = CompareMobileJobsManager(user.login)
        return render_to_response('mobilepage.html',
                                  {'user': user,
                                   'common': common_data,
                                   'job': job_obj,
                                   'task': task,
                                   'navfire': navfire_a,
                                   'pagename': 'mobilepage',
                                   'is_in_compare': job_obj.n in manager.get_jobs(),
                                   'component': MobileComponent.objects.get(n=job_obj.component)
                                   if job_obj.component else None,
                                   },
                                  RequestContext(request))
    except:
        logging.exception('Could not render mobilepage for job {} due to:'.format(job))
        return render_to_response('error.html',
                                  {'common': common_data, 'error': 'no_job'},
                                  RequestContext(request))


@yalogin_required
def job_edit(request, job):
    """

    :param request: HTTP request
    :param job: Job NUMBER
    """
    user = request.yauser
    common = get_common(request)

    try:
        job_obj = MobileJob.objects.get(n=job)
    except ObjectDoesNotExist:
        return render_to_response('error.html', {'common': common, 'error': 'no_job'},
                                  RequestContext(request)
                                  )

    if request.method == 'GET':

        tasks = Task.objects.all().order_by('key')
        components = MobileComponent.objects.filter(tag=job_obj.task.split('-')[0])

        return render_to_response('mobile/edit.html', {'common': common,
                                                       'user': user,
                                                       'job': job_obj,
                                                       'tasks': tasks,
                                                       'components': components},
                                  RequestContext(request))
    elif request.method == 'POST':
        try:
            job_obj.name = request.POST.get('name_new')
            job_obj.dsc = request.POST.get('dsc_new')
            job_obj.device_model = request.POST.get('device_model_new')
            job_obj.device_os = request.POST.get('device_os_new')
            job_obj.app = request.POST.get('app_new')
            job_obj.ver = request.POST.get('ver_new')
            try:
                task_new = link_and_create_task(request, request.POST.get('task_new'))
                job_obj.task = task_new.key
            except TaskError:
                logging.exception('No such Task {}: \n'.format(request.POST.get('task_new')))
            component_new = request.POST.get('component_new')
            try:
                if component_new:
                    component_new = MobileComponent.objects.get(n=component_new)
                    component_new = component_new.n
                else:
                    component_new = 0
                job_obj.component = component_new
            except ObjectDoesNotExist:
                logging.exception('No such Component {}: \n'.format(component_new))

            job_obj.save()

        except Exception:
            logging.exception('Could not submit job {} editing, due to:'.format(job))

        return HttpResponseRedirect('/mobile/{}'.format(job_obj.n))


@yalogin_required
def get_mobile_plot(request):
    plot_type_mapping = {
        'raw': MobileRawPlot,
        'quantiles': MobileTimelineQuantilesPlot,
    }
    try:
        plot_type = request.POST.get('type', '')
        test_id = request.POST.get('test_id', '')
        assert all((test_id, plot_type in list(plot_type_mapping.keys())))
        start = request.POST.get('start', '')
        end = request.POST.get('end', '')
        if settings.RUNTIME_ENV:
            ch_url = 'http://lunapark-clickhouse.n.yandex-team.ru:80'
        else:
            ch_url = 'https://' if request.is_secure() else 'http://'
            ch_url += request.get_host() + '/api/dungeon'
        plot = plot_type_mapping[plot_type](test_id, start=start, end=end, ch_url=ch_url)
        if plot_type == 'raw':
            return HttpResponse(plot.data(), content_type='application/json')
        else:
            return HttpResponse(json.dumps(plot.data()), content_type='application/json')

    except AssertionError:
        return HttpResponseBadRequest(json.dumps(
            {'error': 'test_id is mandatory and plot_type must be one of [{}]'
                      .format(','.join(list(plot_type_mapping.keys())))}
        ))


@yalogin_required
def get_logs_data(request):
    try:
        test_id = request.POST.get('test_id', '')
        assert test_id
        job_obj = MobileJob.objects.filter(test_id=test_id)[0]
        start = request.POST.get('start', '')
        end = request.POST.get('end', '')
        grep = re.escape(request.POST.get('grep', '^[volta]'))
        if settings.RUNTIME_ENV:
            ch_url = 'http://lunapark-clickhouse.n.yandex-team.ru:80'
        else:
            ch_url = 'https://' if request.is_secure() else 'http://'
            ch_url += request.get_host() + '/api/dungeon'
        ch_client = ClickhouseClient(url=ch_url, readonly=True)

        if job_obj.version == '2':
            start = int(float(start) * 1000)
            end = int(float(end) * 1000)
            sql = '''
                select time/1000, message 
                from (
                        select message, toUInt64(sys_uts+{test_start}+{sys_uts_offset}) time from volta.logentries 
                        where test_id='{test_id}'
                        and key_date='{key_date}'
                    union all 
                        select message, toUInt64(log_uts+{test_start}+{log_uts_offset}) time from volta.syncs 
                        where test_id='{test_id}'
                        and key_date='{key_date}'
                    union all 
                        select message, toUInt64(log_uts+{test_start}+{log_uts_offset}) time from volta.events
                        where test_id='{test_id}'
                        and key_date='{key_date}'
                    union all 
                        select concat(concat(tag, ' '), message), toUInt64(log_uts+{test_start}+{log_uts_offset}) time from volta.fragments
                        where test_id='{test_id}'
                        and key_date='{key_date}'
                    )
            '''
            if all((start, end)):
                sql += '''
                    where time >= {start}
                    and time <= {end}
                '''
            if grep and not all((start, end)):
                sql += '''
                    where match(message,'(?i)({grep})')
                '''
            elif grep:
                sql += '''
                    and match(message,'(?i)({grep})')
                '''
            sql += '''
                    order by time
                '''
        else:
            sql = '''
                select time/10, value
                from volta.{events_table} 
                where test_id='{test_id}'
                and key_date='{key_date}'
            '''
            if all((start, end)):
                start = float(start) * 10
                end = float(end) * 10
                sql += '''
                    and time >= {start}
                    and time <= {end}
                '''
            if grep:
                sql += '''
                    and match(value,'(?i)({grep})')
                '''
            sql += '''
                order by time
            '''
        query_params = {'test_id': test_id,
                        'start': start,
                        'end': end,
                        'grep': grep,
                        'key_date': test_id.split('_')[0],
                        'events_table': job_obj.events_table,
                        'logentries_table': job_obj.logentries_table,
                        'syncs_table': job_obj.syncs_table,
                        'test_start': job_obj.test_start,
                        'sys_uts_offset': job_obj.sys_uts_offset,
                        'log_uts_offset': job_obj.log_uts_offset,
                        }

        data = ch_client.select_tsv(sql, query_params=query_params)
        data = data.split('\n')
        data = [(
            float(v.split('\t')[0]),
            v.split('\t')[1],
            datetime.fromtimestamp(float(v.split('\t')[0]) / 1000).strftime("%H:%M:%S.%f")[:-3]
        )
            for v in data if v and v.find('\t') != -1]
    except:
        logging.exception('')
        data = []
    return render_to_response('mobile/logs_table.html', {'data': data}, RequestContext(request))
    # HttpResponse(json.dumps(data), content_type='application/json')


def get_syncs(request):
    """
    Для отображения на графике тока, чтобы пользователь мог сразу визуально оценить синхронность логов и тока.
    :param request:
    :return:
    """
    test_id = request.POST.get('test_id', '')
    if not test_id:
        return HttpResponseBadRequest('invalid test_id')
    job_obj = MobileJob.objects.filter(test_id=test_id)[0]
    if settings.RUNTIME_ENV:
        ch_url = 'http://lunapark-clickhouse.n.yandex-team.ru:80'
    else:
        ch_url = 'https://' if request.is_secure() else 'http://'
        ch_url += request.get_host() + '/api/dungeon'
    ch_client = ClickhouseClient(url=ch_url, readonly=True)

    if job_obj.version == '2':
        sql = '''
            select toUInt64(log_uts+{test_start}+{log_uts_offset}) time from volta.syncs 
            where test_id='{test_id}'
            and key_date='{key_date}'
        '''
        query_params = {'test_id': test_id,
                        'key_date': test_id.split('_')[0],
                        'test_start': job_obj.test_start,
                        'log_uts_offset': job_obj.log_uts_offset,
                        }

        syncs = ch_client.select(sql, query_params=query_params)
    else:
        syncs = []

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


@yalogin_required
def render_fragments_modal(request):
    try:
        test_id = request.POST.get('test_id', '')
        assert test_id
        if settings.RUNTIME_ENV:
            ch_url = 'http://lunapark-clickhouse.n.yandex-team.ru:80'
        else:
            ch_url = 'https://' if request.is_secure() else 'http://'
            ch_url += request.get_host() + '/api/dungeon'

        fragments = get_fragments(test_id, ch_url)

        data = []
        for v in fragments.items():
            start = v[1].get('start', 0)
            end = v[1].get('end', 0) or v[1].get('stop', 0)
            if all([start, end]):
                data.append((v[0], start, end))

    except:
        logging.exception('')
        data = []
    return render_to_response(
        'mobile/fragments_modal.html',
        {'fragments': data},
        RequestContext(request)
    )
    # HttpResponse(json.dumps(data), content_type='application/json')


@yalogin_required
def render_fragments_table(request):
    try:
        test_id = request.POST.get('test_id', '')
        assert test_id

        if settings.RUNTIME_ENV:
            ch_url = 'http://lunapark-clickhouse.n.yandex-team.ru:80'
        else:
            ch_url = 'https://' if request.is_secure() else 'http://'
            ch_url += request.get_host() + '/api/dungeon'

        fragments = get_fragments(test_id, ch_url)

        data = []
        for fragment in fragments.items():
            avg_consumption = fragment_avg_consumption(test_id, ch_url, fragment[1]['start'], fragment[1].get('end', 0)
                                                       or fragment[1].get('stop', 0))
            data.append((
                fragment[0],
                float((fragment[1].get('end', 0)
                      or fragment[1].get('stop', 0)) - fragment[1]['start']) / 1000,  # миллисекунды
                avg_consumption,
                # divide by 3600 to get mAh
                round(float(avg_consumption) / 3600 * (
                    (fragment[1].get('end', 0)
                     or fragment[1].get('stop', 0)) - fragment[1]['start']) / 1000000, 3),  # секунды
            ))
    except:
        logging.exception('')
        data = []
    return render_to_response(
        'mobile/fragments_table.html',
        {'fragments': data},
        RequestContext(request)
    )


def _fragments_data(request):
    job_id = request.GET.get('job')
    if not job_id:
        return HttpResponseBadRequest('job is required')
    try:
        job_obj = MobileJob.objects.get(pk=job_id)
    except MobileJob.DoesNotExist:
        return HttpResponseBadRequest('job is invalid')

    test_id = job_obj.test_id
    assert test_id

    if settings.RUNTIME_ENV:
        ch_url = 'http://lunapark-clickhouse.n.yandex-team.ru:80'
    else:
        ch_url = 'https://' if request.is_secure() else 'http://'
        ch_url += request.get_host() + '/api/dungeon'

    fragments = get_fragments(test_id, ch_url)

    data = {}
    for fragment in fragments.items():
        avg_consumption = fragment_avg_consumption(test_id, ch_url, fragment[1]['start'], fragment[1].get('end', 0)
                                                   or fragment[1].get('stop', 0))
        data[fragment[0]] = [
            float((fragment[1].get('end', 0)
                   or fragment[1].get('stop', 0)) - fragment[1]['start']) / 1000,  # миллисекунды
            avg_consumption,
            # divide by 3600 to get mAh
            round(float(avg_consumption) / 3600 * (
                    (fragment[1].get('end', 0)
                     or fragment[1].get('stop', 0)) - fragment[1]['start']) / 1000000, 3),  # секунды
        ]
    return HttpResponse(json.dumps(data), content_type='application/json')


def get_fragments(test_id, ch_url):
    """

    :param test_id:
    :param ch_url:
    :return: {tag: {message: time}}
    """
    ch_client = ClickhouseClient(url=ch_url, readonly=True)
    job_obj = MobileJob.objects.filter(test_id=test_id)[0]

    sql = '''
        select tag, message, (log_uts + {test_start}+{log_uts_offset}) time
        from volta.{fragments_table}
        where test_id='{test_id}'
        and key_date='{key_date}'
        order by time
    '''
    query_params = {'test_id': test_id,
                    'key_date': test_id.split('_')[0],
                    'fragments_table': job_obj.fragments_table,
                    'test_start': job_obj.test_start,
                    'log_uts_offset': job_obj.log_uts_offset,
                    }

    data = ch_client.select(sql, query_params=query_params)

    data_dict = collections.defaultdict(dict)
    for v in data:
        data_dict[v[0]][v[1]] = int(v[2])

    return data_dict


def fragment_avg_consumption(test_id, ch_url, start, end):
    job_obj = MobileJob.objects.filter(test_id=test_id)[0]
    ch_client = ClickhouseClient(url=ch_url, readonly=True)
    sql = '''
        select round(avg(value), 3)
        from volta.{current_table}
        where test_id='{test_id}'
        and key_date='{key_date}'
        and uts+{test_start} >= {start}
        and uts+{test_start} <= {end}
    '''

    query_params = {'test_id': test_id,
                    'key_date': test_id.split('_')[0],
                    'start': start,
                    'end': end,
                    'current_table': job_obj.current_table,
                    'test_start': job_obj.test_start,
                    }

    avg_consumption = ch_client.select(sql, query_params=query_params) or [[0]]
    return avg_consumption[0][0]


@csrf_exempt
def create_job(request):
    try:
        task = request.POST.get('task', '').upper()
        test_id = request.POST.get('test_id', '')
        assert all((task, test_id)), 'task and test_id are mandatory'
        link_and_create_task(request, task)

        component = request.POST.get('component')
        if component:
            component_number = MobileComponent.objects.get_or_create(name=component,
                                                                     tag=task.split('-')[0]
                                                                     )[0].n
        else:
            component_number = None

        mj = MobileJob.objects.get_or_create(
            task=task,
            test_id=test_id,
            name=request.POST.get('name', ''),
            dsc=request.POST.get('dsc', ''),
            device_id=request.POST.get('device_id', ''),
            device_model=request.POST.get('device_model', ''),
            device_os=request.POST.get('device_os', ''),
            app=request.POST.get('app', ''),
            ver=request.POST.get('ver', ''),
            person=request.POST.get('operator', ''),
            component=component_number,
            # v2 fields
            version=request.POST.get('version', ''),
            meta=request.POST.get('meta', ''),
        )
        success = True
        error = ''
        jobno = mj[0].id
    except AssertionError as aexc:
        logging.error(repr(aexc))
        success = False
        error = repr(aexc)
        return HttpResponseBadRequest(json.dumps({'success': success, 'error': error}),
                                      content_type='application/json')
    except TaskError:
        logging.exception('')
        success = False
        error = "Invalid task"
        return HttpResponseBadRequest(json.dumps({'success': success, 'error': error}),
                                      content_type='application/json')
    except Exception as exc:
        logging.exception('')
        success = False
        error = str(exc)
        return HttpResponseBadRequest(json.dumps({'success': success, 'error': error}),
                                      content_type='application/json')
    else:
        return HttpResponse(json.dumps({'success': success, 'error': error, 'jobno': jobno}),
                            content_type='application/json')


@csrf_exempt
def update_job(request):
    try:
        test_id = request.POST.get('test_id', '')
        assert test_id, 'test_id is mandatory'

        try:
            mj = MobileJob.objects.get(
                test_id=test_id)
        except MobileJob.MultipleObjectsReturned:
            mj = MobileJob.objects.filter(
                test_id=test_id)[0]

        task = request.POST.get('task', '').upper()
        if task:
            link_and_create_task(request, task)

        component = request.POST.get('component')
        if component:
            component_number = MobileComponent.objects.get_or_create(name=component,
                                                                     tag=task.split('-')
                                                                     )[0].n
        else:
            component_number = mj.component

        mj.task = task
        mj.name = request.POST.get('name', mj.name)
        mj.dsc = request.POST.get('dsc', mj.dsc)
        mj.device_id = request.POST.get('device_id', mj.device_id)
        mj.device_model = request.POST.get('device_model', mj.device_model)
        mj.device_os = request.POST.get('device_os', mj.device_os)
        mj.app = request.POST.get('app', mj.app)
        mj.ver = request.POST.get('ver', mj.ver)
        mj.person = request.POST.get('operator', mj.person)
        mj.component = component_number
        # v2 fields
        mj.test_start = request.POST.get('test_start', mj.test_start)
        mj.sys_uts_offset = request.POST.get('sys_uts_offset', mj.sys_uts_offset)
        mj.log_uts_offset = request.POST.get('log_uts_offset', mj.log_uts_offset)
        mj.sync_sample = request.POST.get('sync_sample', mj.sync_sample)
        mj.version = request.POST.get('version', mj.version)
        mj.meta = request.POST.get('meta', mj.meta)

        mj.save()

        success = True
        error = ''
    except AssertionError as aexc:
        logging.error(repr(aexc))
        success = False
        error = repr(aexc)
        return HttpResponseBadRequest(json.dumps({'success': success, 'error': error}),
                                      content_type='application/json')
    except MobileJob.DoesNotExist:
        logging.exception('')
        success = False
        error = "Invalid job test_id"
        return HttpResponseBadRequest(json.dumps({'success': success, 'error': error}),
                                      content_type='application/json')
    except TaskError:
        logging.exception('')
        success = False
        error = "Invalid task"
        return HttpResponseBadRequest(json.dumps({'success': success, 'error': error}),
                                      content_type='application/json')
    except Exception as exc:
        logging.exception('')
        success = False
        error = repr(exc)
        return HttpResponseBadRequest(json.dumps({'success': success, 'error': error}),
                                       content_type='application/json')
    else:
        return HttpResponse(json.dumps({'success': success, 'error': error}),
                            content_type='application/json')


@yalogin_required
def add_to_compare(request):
    user = request.yauser
    manager = CompareMobileJobsManager(user.login)
    manager.add_jobs([request.GET.get('job_n')])
    return HttpResponse(json.dumps({'success': 1}), content_type='text/json')


class MobilePlot(object):
    def __init__(self, test_id, start=None, end=None, ch_url=None):
        """

        :param test_id:
        :param start:
        :param end:
        """
        self.test_id = test_id
        self.start = start
        self.end = end

        self.job_obj = MobileJob.objects.filter(test_id=test_id)[0]

        self.ch_client = ClickhouseClient(url=ch_url, readonly=True)

        self.query_params = {'test_id': self.test_id,
                             'start': float(self.start) * 10 if self.start else '',
                             'end': float(self.end) * 10 if self.end else '',
                             'key_date': self.test_id.split('_')[0],
                             'current_table': self.job_obj.current_table,
                             'events_table': self.job_obj.events_table,
                             'test_start': self.job_obj.test_start,
                             }


class MobileRawPlot(MobilePlot):
    def data(self):
        try:
            if self.job_obj.version == '2':
                # прибавлять start_time тут
                sql = '''
                    select toFloat64(uts+{test_start})/1000, round(any(value), 3) 
                    from volta.{current_table}
                    where test_id='{test_id}'
                    and key_date='{key_date}'
                '''
                if all((self.start, self.end)):
                    sql += '''
                        and uts >= {start}
                        and uts <= {end}
                    '''
                sql += '''
                    group by uts
                    order by uts
                '''
            else:
                sql = '''select toFloat64(time)/10, round(any(value), 3) as t
                    from volta.{current_table}
                    where test_id='{test_id}'
                    and key_date='{key_date}'
                '''
                if all((self.start, self.end)):
                    sql += '''
                        and time >= {start}
                        and time <= {end}
                    '''
                sql += '''
                    group by time
                    order by time
                '''
            # use execute to prevent json serialization;
            data = self.ch_client.select(sql, query_params=self.query_params, deserialize=False)
            data = data

        except:
            logging.exception('')
            data = "[]"  # строка, потому что deserialize=False
        return data


class MobileTimelineQuantilesPlot(MobilePlot):
    quantiles = 50, 75, 80, 85, 90, 95, 98, 99, 100

    def data(self):
        data = {'compress_ratio': 1, 'data': []}
        try:
            sql = 'select '
            if self.job_obj.version == '2':
                sql += 'intDiv(uts+{test_start}, 1000000)*1000000 as t, '  # прибавлять start_time тут
            else:
                sql += 'intDiv(time, 10000)*10000 as t, '
            sql += '''
                round(avg(value), 3), 
                round(quantile(0.50)(value), 3),
                round(quantile(0.75)(value), 3),
                round(quantile(0.80)(value), 3),
                round(quantile(0.85)(value), 3),
                round(quantile(0.90)(value), 3),
                round(quantile(0.95)(value), 3),
                round(quantile(0.98)(value), 3),
                round(quantile(0.99)(value), 3),
                round(max(value), 3)
                from volta.{current_table}
                where test_id='{test_id}'
                and key_date='{key_date}'
            '''
            if all((self.start, self.end)):
                if self.job_obj.version == '2':
                    sql += '''
                        and uts >= {start}
                        and uts <= {end}
                    '''
                else:
                    sql += '''
                        and time >= {start}
                        and time <= {end}
                    '''
            sql += '''
                group by t
                order by t
            '''
            fetched_data = self.ch_client.select(sql, query_params=self.query_params)
            if self.job_obj.version == '2':
                times = [float(v[0]) / 1000 for v in fetched_data]
            else:
                times = [float(v[0]) / 10 for v in fetched_data]

            quantiles = [[v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10]]
                         for v in fetched_data] if fetched_data else [[0] * 9]
            transponed_quantiles = list(zip(*quantiles))
            for q in reversed(self.quantiles):
                i = self.quantiles.index(q)
                data['data'].append({
                    'name': '{}%'.format(q),
                    'data': list(zip(times, transponed_quantiles[i])),
                    'type': 'line' if q in (99, 100) else 'area',
                    'visible': q not in (99, 100),
                    'color': self.color_mapping(q),
                })

            avg = [float(v[1]) for v in fetched_data]
            data['data'].append({
                'name': 'avg',
                'data': list(zip(times, avg)),
                'type': 'line',
                'color': '#333',
            })
        except:
            logging.exception('')
            data = {'compress_ratio': 1, 'data': []}
        return data

    @staticmethod
    def color_mapping(quantile):
        color_map = {
            50: '#f85750',
            75: 'Coral',
            80: 'DarkOrange',
            85: 'Orange',
            90: 'gold',
            95: '#b8e13d',
            98: '#66af5f',
            99: '#7cb3f1',
            100: '#b2b8c8'
        }
        try:
            color = color_map[quantile]
            return color
        except KeyError:
            logging.warning('Unexpected quantile: {}'.format(quantile))
            return None


@yalogin_required
def mobilejobs_stream(request):
    try:
        # user = request.GET.get('user', '')
        limit = request.GET.get('limit', 50)
        try:
            assert str(limit).isdigit()
            assert int(limit) < 1000
        except AssertionError:
            logging.warning(
                "Limit for mobile jobs passed in GET parameters is too large ({}). Limit is set to 50".format(limit))
            limit = 50

        jobs = MobileJob.objects.all().order_by('-n')[:limit]
        # not implemented
        # if user:
        # jobs = MobileJob.objects.filter(person=user).exclude(td=None).order_by('-n')[:limit]
        data = {'success': 1, 'objects': []}
        for job in jobs:
            try:
                data['objects'].append({  # 'person': job.person,
                    'n': job.n,
                    'name': job.name,
                    'task': job.task,
                })
            except:
                continue

    except ObjectDoesNotExist:
        data = {'success': 0, 'error': 'No jobs offline'}
    except Exception as exc:
        logging.exception('could not retrieve offline jobs due to:')
        data = {'success': 0, 'error': exc.__class__.__name__}

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