RequestBuilder.py 6.78 KB
from django.contrib.auth.models import User
from pyrosapp.models import *
import scheduler.tasks

from decimal import Decimal

from django.conf import settings


class RequestBuilder():

    def __init__(self):
        '''
            Might do nothing if this is not a simulation
        '''
        if settings.SIMULATION == False:
            pass
        else:
            ''' creating dependencies in DB if they don't exist '''
            if PyrosUser.objects.count() == 0:
                if Country.objects.count() == 0:
                    country = Country.objects.create(name="default")
                else:
                    country = Country.objects.get()
                if UserLevel.objects.count() == 0:
                    user_level = UserLevel.objects.create(name="default")
                else:
                    user_level = UserLevel.objects.get()
                if User.objects.count() == 0:
                    user = User.objects.create(username="default")
                else:
                    user = User.objects.get()
                PyrosUser.objects.create(
                    country=country, user_level=user_level, user=user, quota=1000)

            if ScientificProgram.objects.count() == 0:
                ScientificProgram.objects.create(name="default")

    def start_new_request(self, pyros_user, scientific_program, is_alert, name="default"):
        '''
            This function MUST be called to build a request.
            It erases the previous one, and creates the sequences', albums' and plans' dictionaries.
        '''
        if settings.SIMULATION == False:
            self.request = Request(name=name,
                scientific_program=scientific_program, pyros_user=pyros_user, is_alert=is_alert)
        else:
            self.request = Request(name=name, scientific_program=ScientificProgram.objects.get(
            ), pyros_user=PyrosUser.objects.get(), is_alert=True)
        self.sequence_id = 1
        self.album_id = 1
        self.plan_id = 1
        self.sequences = {}
        self.albums = {}
        self.plans = {}

    def add_sequence(self, priority, jd1, jd2, t_prefered=-1, name="default", duration=0):
        '''
            Add a sequence to the current request
            start_new_request must be called one before it
            :returns : The local ID of the sequence (to add albums to it)
        '''

        if not hasattr(self, "request"):
            raise RuntimeError(
                "start_new_request MUST be invoked before creating any sequence")

        sequence = Sequence(name=name, status=Sequence.OBSERVABLE, priority=priority,
                            jd1=jd1, jd2=jd2, t_prefered=t_prefered, duration=duration)
        self.sequences[self.sequence_id] = sequence
        self.sequence_id += 1
        return self.sequence_id - 1

    def delete_sequence(self, seq_id):
        '''
            Removes locally a sequence from the current request
        '''
        if seq_id in self.sequences.keys():
            del self.sequences[seq_id]

    def add_album(self, seq_id, detector_name, name="default"):
        '''
            Creates a new album for the given sequence
            :returns : The local ID of the new album
        '''

        if not Detector.objects.filter(device__name=detector_name).exists():
            raise RuntimeError("Detector %s doesn't exist" % (detector_name,))
        if seq_id not in self.sequences.keys():
            raise RuntimeError("The sequence %d doesn't exist" % (seq_id,))

        detector = Detector.objects.get(device__name=detector_name)

        album = Album(name=name, detector=detector)
        self.albums[self.album_id] = (album, seq_id)
        self.album_id += 1
        return self.album_id - 1

    def del_album(self, album_id):
        '''
            Removes locally an album from the current request
        '''
        if album_id in self.albums.keys():
            del self.albums[album_id]

    def add_plan(self, album_id, filter_name, duration, nb_images, name="default"):
        '''
            Creates a new plan for the given album
            :returns : The local ID of the new plan
        '''

        if not Filter.objects.filter(device__name=filter_name).exists():
            raise RuntimeError("Filer %s doesn't exist" % (filter_name,))
        if album_id not in self.albums.keys():
            raise RuntimeError("The album %d doesn't exist" % (album_id,))

        filter_ = Filter.objects.get(device__name=filter_name)

        duration = Decimal(float(duration) / 86400.0)
        plan = Plan(name=name, filter=filter_,
                    duration=duration, nb_images=nb_images)
        self.plans[self.plan_id] = (plan, album_id)
        self.plan_id += 1
        return self.plan_id - 1

    def del_plan(self, plan_id):
        '''
            Removes locally a plan from the current request
        '''
        if plan_id in self.plans.keys():
            del self.plans[plan_id]

    def validate_request(self):
        '''
            Saves the different objects : request, sequences, albums, plans
            Computes sequences' duration
            Creates a scheduling task
            :returns : The request
        '''

        if len(self.sequences) == 0:
            raise RuntimeError(
                "There must be at least one sequence in a request")

        if settings.SIMULATION == False:
            sequences_having_album = list(set([
                seq_id for album, seq_id in self.albums.values()]))
            if len(sequences_having_album) != len(self.sequences):
                raise RuntimeError("All sequences must have at least one album")
            albums_having_plan = list(set([
                album_id for plan, album_id in self.plans.values()]))
            if len(albums_having_plan) != len(self.albums):
                raise RuntimeError("All albums must have at least one plan")

        self.request.save()
        for sequence in self.sequences.values():
            sequence.request = self.request
            sequence.save()
        for album, seq_id in self.albums.values():
            album.sequence = self.sequences[seq_id]
            album.save()
        for plan, album_id in self.plans.values():
            plan.album = self.albums[album_id][0]
            plan.save()

        if settings.SIMULATION == False:
            ''' computes the duration of all sequences '''
            for sequence in self.sequences.values():
                max_duration = 0
                for album in sequence.albums.all():
                    duration = sum([plan.duration for plan in album.plans.all()])
                    max_duration = duration if duration > max_duration else max_duration
                sequence.duration = max_duration
                sequence.save()
        scheduler.tasks.scheduling.delay(first_schedule=True, alert=self.request.is_alert)
        return self.request