from django import http
from autotest_lib.frontend.shared import query_lib, resource_lib
from autotest_lib.frontend.afe import control_file, models, rpc_utils
from autotest_lib.frontend.afe import model_attributes
from autotest_lib.frontend import thread_local
from autotest_lib.client.common_lib import host_protections

class EntryWithInvalid(resource_lib.InstanceEntry):
    def put(self):
        if self.instance.invalid:
            raise http.Http404('%s has been deleted' % self.instance)
        return super(EntryWithInvalid, self).put()


    def delete(self):
        if self.instance.invalid:
            raise http.Http404('%s has already been deleted' % self.instance)
        return super(EntryWithInvalid, self).delete()


class AtomicGroupClass(EntryWithInvalid):
    model = models.AtomicGroup


    @classmethod
    def from_uri_args(cls, request, ag_name, **kwargs):
        return cls(request, models.AtomicGroup.objects.get(name=ag_name))


    def _uri_args(self):
        return {'ag_name': self.instance.name}


    def short_representation(self):
        rep = super(AtomicGroupClass, self).short_representation()
        rep['name'] = self.instance.name
        return rep


    def full_representation(self):
        rep = super(AtomicGroupClass, self).full_representation()
        rep.update({'max_number_of_machines':
                    self.instance.max_number_of_machines,
                    'labels':
                    AtomicLabelTaggingCollection(fixed_entry=self).link()})
        return rep


    @classmethod
    def create_instance(cls, input_dict, containing_collection):
        cls._check_for_required_fields(input_dict, ('name',))
        return models.AtomicGroup.add_object(name=input_dict['name'])


    def update(self, input_dict):
        data = {'max_number_of_machines':
                input_dict.get('max_number_of_machines')}
        data = input_dict.remove_unspecified_fields(data)
        self.instance.update_object(**data)


class AtomicGroupClassCollection(resource_lib.Collection):
    queryset = models.AtomicGroup.valid_objects.all()
    entry_class = AtomicGroupClass


class Label(EntryWithInvalid):
    model = models.Label

    @classmethod
    def add_query_selectors(cls, query_processor):
        query_processor.add_field_selector('name')
        query_processor.add_field_selector(
                'is_platform', field='platform',
                value_transform=query_processor.read_boolean)


    @classmethod
    def from_uri_args(cls, request, label_name, **kwargs):
        return cls(request, models.Label.objects.get(name=label_name))


    def _uri_args(self):
        return {'label_name': self.instance.name}


    def short_representation(self):
        rep = super(Label, self).short_representation()
        rep.update({'name': self.instance.name,
                    'is_platform': bool(self.instance.platform)})
        return rep


    def full_representation(self):
        rep = super(Label, self).full_representation()
        atomic_group_class = AtomicGroupClass.from_optional_instance(
                self._request, self.instance.atomic_group)
        rep.update({'atomic_group_class':
                        atomic_group_class.short_representation(),
                    'hosts': HostLabelingCollection(fixed_entry=self).link()})
        return rep


    @classmethod
    def create_instance(cls, input_dict, containing_collection):
        cls._check_for_required_fields(input_dict, ('name',))
        return models.Label.add_object(name=input_dict['name'])


    def update(self, input_dict):
        # TODO update atomic group
        if 'is_platform' in input_dict:
            self.instance.platform = input_dict['is_platform']
            self.instance.save()


class LabelCollection(resource_lib.Collection):
    queryset = models.Label.valid_objects.all()
    entry_class = Label


class AtomicLabelTagging(resource_lib.Relationship):
    related_classes = {'label': Label, 'atomic_group_class': AtomicGroupClass}


class AtomicLabelTaggingCollection(resource_lib.RelationshipCollection):
    entry_class = AtomicLabelTagging


class User(resource_lib.InstanceEntry):
    model = models.User
    _permitted_methods = ('GET,')


    @classmethod
    def from_uri_args(cls, request, username, **kwargs):
        if username == '@me':
            username = models.User.current_user().login
        return cls(request, models.User.objects.get(login=username))


    def _uri_args(self):
        return {'username': self.instance.login}


    def short_representation(self):
        rep = super(User, self).short_representation()
        rep['username'] = self.instance.login
        return rep


    def full_representation(self):
        rep = super(User, self).full_representation()
        accessible_hosts = HostCollection(self._request)
        accessible_hosts.set_query_parameters(accessible_by=self.instance.login)
        rep.update({'jobs': 'TODO',
                    'recurring_runs': 'TODO',
                    'acls':
                    UserAclMembershipCollection(fixed_entry=self).link(),
                    'accessible_hosts': accessible_hosts.link()})
        return rep


class UserCollection(resource_lib.Collection):
    _permitted_methods = ('GET',)
    queryset = models.User.objects.all()
    entry_class = User


class Acl(resource_lib.InstanceEntry):
    _permitted_methods = ('GET',)
    model = models.AclGroup

    @classmethod
    def from_uri_args(cls, request, acl_name, **kwargs):
        return cls(request, models.AclGroup.objects.get(name=acl_name))


    def _uri_args(self):
        return {'acl_name': self.instance.name}


    def short_representation(self):
        rep = super(Acl, self).short_representation()
        rep['name'] = self.instance.name
        return rep


    def full_representation(self):
        rep = super(Acl, self).full_representation()
        rep.update({'users':
                    UserAclMembershipCollection(fixed_entry=self).link(),
                    'hosts':
                    HostAclMembershipCollection(fixed_entry=self).link()})
        return rep


    @classmethod
    def create_instance(cls, input_dict, containing_collection):
        cls._check_for_required_fields(input_dict, ('name',))
        return models.AclGroup.add_object(name=input_dict['name'])


    def update(self, input_dict):
        pass


class AclCollection(resource_lib.Collection):
    queryset = models.AclGroup.objects.all()
    entry_class = Acl


class UserAclMembership(resource_lib.Relationship):
    related_classes = {'user': User, 'acl': Acl}

    # TODO: check permissions
    # TODO: check for and add/remove "Everyone"


class UserAclMembershipCollection(resource_lib.RelationshipCollection):
    entry_class = UserAclMembership


class Host(EntryWithInvalid):
    model = models.Host

    @classmethod
    def add_query_selectors(cls, query_processor):
        query_processor.add_field_selector('hostname')
        query_processor.add_field_selector(
                'locked', value_transform=query_processor.read_boolean)
        query_processor.add_field_selector(
                'locked_by', field='locked_by__login',
                doc='Username of user who locked this host, if locked')
        query_processor.add_field_selector('status')
        query_processor.add_field_selector(
                'protection_level', field='protection',
                doc='Verify/repair protection level',
                value_transform=cls._read_protection)
        query_processor.add_field_selector(
                'accessible_by', field='aclgroup__users__login',
                doc='Username of user with access to this host')
        query_processor.add_related_existence_selector(
                'has_label', models.Label, 'name')


    @classmethod
    def _read_protection(cls, protection_input):
        return host_protections.Protection.get_value(protection_input)


    @classmethod
    def from_uri_args(cls, request, hostname, **kwargs):
        return cls(request, models.Host.objects.get(hostname=hostname))


    def _uri_args(self):
        return {'hostname': self.instance.hostname}


    def short_representation(self):
        rep = super(Host, self).short_representation()
        # TODO calling platform() over and over is inefficient
        platform_rep = (Label.from_optional_instance(self._request,
                                                     self.instance.platform())
                        .short_representation())
        rep.update({'hostname': self.instance.hostname,
                    'locked': bool(self.instance.locked),
                    'status': self.instance.status,
                    'platform': platform_rep})
        return rep


    def full_representation(self):
        rep = super(Host, self).full_representation()
        protection = host_protections.Protection.get_string(
                self.instance.protection)
        locked_by = (User.from_optional_instance(self._request,
                                                 self.instance.locked_by)
                     .short_representation())
        labels = HostLabelingCollection(fixed_entry=self)
        acls = HostAclMembershipCollection(fixed_entry=self)
        queue_entries = QueueEntryCollection(self._request)
        queue_entries.set_query_parameters(host=self.instance.hostname)
        health_tasks = HealthTaskCollection(self._request)
        health_tasks.set_query_parameters(host=self.instance.hostname)

        rep.update({'locked_by': locked_by,
                    'locked_on': self._format_datetime(self.instance.lock_time),
                    'invalid': self.instance.invalid,
                    'protection_level': protection,
                    # TODO make these efficient
                    'labels': labels.full_representation(),
                    'acls': acls.full_representation(),
                    'queue_entries': queue_entries.link(),
                    'health_tasks': health_tasks.link()})
        return rep


    @classmethod
    def create_instance(cls, input_dict, containing_collection):
        cls._check_for_required_fields(input_dict, ('hostname',))
        # include locked here, rather than waiting for update(), to avoid race
        # conditions
        host = models.Host.add_object(hostname=input_dict['hostname'],
                                      locked=input_dict.get('locked', False))
        return host

    def update(self, input_dict):
        data = {'locked': input_dict.get('locked'),
                'protection': input_dict.get('protection_level')}
        data = input_dict.remove_unspecified_fields(data)

        if 'protection' in data:
            data['protection'] = self._read_protection(data['protection'])

        self.instance.update_object(**data)

        if 'platform' in input_dict:
            label = self.resolve_link(input_dict['platform']) .instance
            if not label.platform:
                raise BadRequest('Label %s is not a platform' % label.name)
            for label in self.instance.labels.filter(platform=True):
                self.instance.labels.remove(label)
            self.instance.labels.add(label)


class HostCollection(resource_lib.Collection):
    queryset = models.Host.valid_objects.all()
    entry_class = Host


class HostLabeling(resource_lib.Relationship):
    related_classes = {'host': Host, 'label': Label}


class HostLabelingCollection(resource_lib.RelationshipCollection):
    entry_class = HostLabeling


class HostAclMembership(resource_lib.Relationship):
    related_classes = {'host': Host, 'acl': Acl}

    # TODO: acl.check_for_acl_violation_acl_group()
    # TODO: models.AclGroup.on_host_membership_change()


class HostAclMembershipCollection(resource_lib.RelationshipCollection):
    entry_class = HostAclMembership


class Test(resource_lib.InstanceEntry):
    model = models.Test


    @classmethod
    def add_query_selectors(cls, query_processor):
        query_processor.add_field_selector('name')


    @classmethod
    def from_uri_args(cls, request, test_name, **kwargs):
        return cls(request, models.Test.objects.get(name=test_name))


    def _uri_args(self):
        return {'test_name': self.instance.name}


    def short_representation(self):
        rep = super(Test, self).short_representation()
        rep['name'] = self.instance.name
        return rep


    def full_representation(self):
        rep = super(Test, self).full_representation()
        rep.update({'author': self.instance.author,
                    'class': self.instance.test_class,
                    'control_file_type':
                    model_attributes.TestTypes.get_string(
                        self.instance.test_type),
                    'control_file_path': self.instance.path,
                    'sync_count': self.instance.sync_count,
                    'dependencies':
                    TestDependencyCollection(fixed_entry=self).link(),
                    })
        return rep


    @classmethod
    def create_instance(cls, input_dict, containing_collection):
        cls._check_for_required_fields(input_dict,
                                       ('name', 'control_file_type',
                                        'control_file_path'))
        test_type = model_attributes.TestTypes.get_value(
            input['control_file_type'])
        return models.Test.add_object(name=input_dict['name'],
                                      test_type=test_type,
                                      path=input_dict['control_file_path'])


    def update(self, input_dict):
        data = {'test_type': input_dict.get('control_file_type'),
                'path': input_dict.get('control_file_path'),
                'class': input_dict.get('class'),
                }
        data = input_dict.remove_unspecified_fields(data)
        self.instance.update_object(**data)


class TestCollection(resource_lib.Collection):
    queryset = models.Test.objects.all()
    entry_class = Test


class TestDependency(resource_lib.Relationship):
    related_classes = {'test': Test, 'label': Label}


class TestDependencyCollection(resource_lib.RelationshipCollection):
    entry_class = TestDependency


# TODO profilers


class ExecutionInfo(resource_lib.Resource):
    _permitted_methods = ('GET','POST')
    _job_fields = models.Job.get_field_dict()
    _DEFAULTS = {
            'control_file': '',
            'is_server': True,
            'dependencies': [],
            'machines_per_execution': 1,
            'run_verify': bool(_job_fields['run_verify'].default),
            'timeout_hrs': _job_fields['timeout'].default,
            'maximum_runtime_hrs': _job_fields['max_runtime_hrs'].default,
            'cleanup_before_job':
                model_attributes.RebootBefore.get_string(
                    models.DEFAULT_REBOOT_BEFORE),
            'cleanup_after_job':
                model_attributes.RebootAfter.get_string(
                    models.DEFAULT_REBOOT_AFTER),
            }


    def _query_parameters_accepted(self):
        return (('tests', 'Comma-separated list of test names to run'),
                ('kernels', 'TODO'),
                ('client_control_file',
                 'Client control file segment to run after all specified '
                 'tests'),
                ('profilers',
                 'Comma-separated list of profilers to activate during the '
                 'job'),
                ('use_container', 'TODO'),
                ('profile_only',
                 'If true, run only profiled iterations; otherwise, always run '
                 'at least one non-profiled iteration in addition to a '
                 'profiled iteration'),
                ('upload_kernel_config',
                 'If true, generate a server control file code that uploads '
                 'the kernel config file to the client and tells the client of '
                 'the new (local) path when compiling the kernel; the tests '
                 'must be server side tests'))


    @classmethod
    def execution_info_from_job(cls, job):
        return {'control_file': job.control_file,
                'is_server': job.control_type == models.Job.ControlType.SERVER,
                'dependencies': [label.name for label
                                 in job.dependency_labels.all()],
                'machines_per_execution': job.synch_count,
                'run_verify': bool(job.run_verify),
                'timeout_hrs': job.timeout,
                'maximum_runtime_hrs': job.max_runtime_hrs,
                'cleanup_before_job':
                    model_attributes.RebootBefore.get_string(job.reboot_before),
                'cleanup_after_job':
                    model_attributes.RebootAfter.get_string(job.reboot_after),
                }


    def _get_execution_info(self, input_dict):
        tests = input_dict.get('tests', '')
        client_control_file = input_dict.get('client_control_file', None)
        if not tests and not client_control_file:
            return self._DEFAULTS

        test_list = tests.split(',')
        if 'profilers' in input_dict:
            profilers_list = input_dict['profilers'].split(',')
        else:
            profilers_list = []
        kernels = input_dict.get('kernels', '') # TODO
        if kernels:
            kernels = [dict(version=kernel) for kernel in kernels.split(',')]

        cf_info, test_objects, profiler_objects, label = (
                rpc_utils.prepare_generate_control_file(
                        test_list, kernels, None, profilers_list))
        control_file_contents = control_file.generate_control(
                tests=test_objects, kernels=kernels,
                profilers=profiler_objects, is_server=cf_info['is_server'],
                client_control_file=client_control_file,
                profile_only=input_dict.get('profile_only', None),
                upload_kernel_config=input_dict.get(
                    'upload_kernel_config', None))
        return dict(self._DEFAULTS,
                    control_file=control_file_contents,
                    is_server=cf_info['is_server'],
                    dependencies=cf_info['dependencies'],
                    machines_per_execution=cf_info['synch_count'])


    def handle_request(self):
        result = self.link()
        result['execution_info'] = self._get_execution_info(
                self._request.REQUEST)
        return self._basic_response(result)


class QueueEntriesRequest(resource_lib.Resource):
    _permitted_methods = ('GET',)


    def _query_parameters_accepted(self):
        return (('hosts', 'Comma-separated list of hostnames'),
                ('one_time_hosts',
                 'Comma-separated list of hostnames not already in the '
                 'Autotest system'),
                ('meta_hosts',
                 'Comma-separated list of label names; for each one, an entry '
                 'will be created and assigned at runtime to an available host '
                 'with that label'),
                ('atomic_group_class', 'TODO'))


    def _read_list(self, list_string):
        if list_string:
            return list_string.split(',')
        return []


    def handle_request(self):
        request_dict = self._request.REQUEST
        hosts = self._read_list(request_dict.get('hosts'))
        one_time_hosts = self._read_list(request_dict.get('one_time_hosts'))
        meta_hosts = self._read_list(request_dict.get('meta_hosts'))
        atomic_group_class = request_dict.get('atomic_group_class')

        # TODO: bring in all the atomic groups magic from create_job()

        entries = []
        for hostname in one_time_hosts:
            models.Host.create_one_time_host(hostname)
        for hostname in hosts:
            entry = Host.from_uri_args(self._request, hostname)
            entries.append({'host': entry.link()})
        for label_name in meta_hosts:
            entry = Label.from_uri_args(self._request, label_name)
            entries.append({'meta_host': entry.link()})
        if atomic_group_class:
            entries.append({'atomic_group_class': atomic_group_class})

        result = self.link()
        result['queue_entries'] = entries
        return self._basic_response(result)


class Job(resource_lib.InstanceEntry):
    _permitted_methods = ('GET',)
    model = models.Job


    class _StatusConstraint(query_lib.Constraint):
        def apply_constraint(self, queryset, value, comparison_type,
                             is_inverse):
            if comparison_type != 'equals' or is_inverse:
                raise query_lib.ConstraintError('Can only use this selector '
                                                'with equals')
            non_queued_statuses = [
                    status for status, _
                    in models.HostQueueEntry.Status.choices()
                    if status != models.HostQueueEntry.Status.QUEUED]
            if value == 'queued':
                return queryset.exclude(
                        hostqueueentry__status__in=non_queued_statuses)
            elif value == 'active':
                return queryset.filter(
                        hostqueueentry__status__in=non_queued_statuses).filter(
                        hostqueueentry__complete=False).distinct()
            elif value == 'complete':
                return queryset.exclude(hostqueueentry__complete=False)
            else:
                raise query_lib.ConstraintError('Value must be one of queued, '
                                                'active or complete')


    @classmethod
    def add_query_selectors(cls, query_processor):
        query_processor.add_field_selector('id')
        query_processor.add_field_selector('name')
        query_processor.add_selector(
                query_lib.Selector('status',
                                   doc='One of queued, active or complete'),
                Job._StatusConstraint())
        query_processor.add_keyval_selector('has_keyval', models.JobKeyval,
                                            'key', 'value')


    @classmethod
    def from_uri_args(cls, request, job_id, **kwargs):
        return cls(request, models.Job.objects.get(id=job_id))


    def _uri_args(self):
        return {'job_id': self.instance.id}


    @classmethod
    def _do_prepare_for_full_representation(cls, instances):
        models.Job.objects.populate_relationships(instances, models.JobKeyval,
                                                  'keyvals')


    def short_representation(self):
        rep = super(Job, self).short_representation()
        rep.update({'id': self.instance.id,
                    'owner': self.instance.owner,
                    'name': self.instance.name,
                    'priority':
                        models.Job.Priority.get_string(self.instance.priority),
                    'created_on':
                        self._format_datetime(self.instance.created_on),
                    })
        return rep


    def full_representation(self):
        rep = super(Job, self).full_representation()
        queue_entries = QueueEntryCollection(self._request)
        queue_entries.set_query_parameters(job=self.instance.id)
        drone_set = self.instance.drone_set and self.instance.drone_set.name
        rep.update({'email_list': self.instance.email_list,
                    'parse_failed_repair':
                        bool(self.instance.parse_failed_repair),
                    'drone_set': drone_set,
                    'execution_info':
                        ExecutionInfo.execution_info_from_job(self.instance),
                    'queue_entries': queue_entries.link(),
                    'keyvals': dict((keyval.key, keyval.value)
                                    for keyval in self.instance.keyvals)
                    })
        return rep


    @classmethod
    def create_instance(cls, input_dict, containing_collection):
        owner = input_dict.get('owner')
        if not owner:
            owner = models.User.current_user().login

        cls._check_for_required_fields(input_dict, ('name', 'execution_info',
                                                    'queue_entries'))
        execution_info = input_dict['execution_info']
        cls._check_for_required_fields(execution_info, ('control_file',
                                                        'is_server'))

        if execution_info['is_server']:
            control_type = models.Job.ControlType.SERVER
        else:
            control_type = models.Job.ControlType.CLIENT
        options = dict(
                name=input_dict['name'],
                priority=input_dict.get('priority', None),
                control_file=execution_info['control_file'],
                control_type=control_type,
                is_template=input_dict.get('is_template', None),
                timeout=execution_info.get('timeout_hrs'),
                max_runtime_hrs=execution_info.get('maximum_runtime_hrs'),
                synch_count=execution_info.get('machines_per_execution'),
                run_verify=execution_info.get('run_verify'),
                email_list=input_dict.get('email_list', None),
                dependencies=execution_info.get('dependencies', ()),
                reboot_before=execution_info.get('cleanup_before_job'),
                reboot_after=execution_info.get('cleanup_after_job'),
                parse_failed_repair=input_dict.get('parse_failed_repair', None),
                drone_set=input_dict.get('drone_set', None),
                keyvals=input_dict.get('keyvals', None))

        host_objects, metahost_label_objects, atomic_group = [], [], None
        for queue_entry in input_dict['queue_entries']:
            if 'host' in queue_entry:
                host = queue_entry['host']
                if host: # can be None, indicated a hostless job
                    host_entry = containing_collection.resolve_link(host)
                    host_objects.append(host_entry.instance)
            elif 'meta_host' in queue_entry:
                label_entry = containing_collection.resolve_link(
                        queue_entry['meta_host'])
                metahost_label_objects.append(label_entry.instance)
            if 'atomic_group_class' in queue_entry:
                atomic_group_entry = containing_collection.resolve_link(
                        queue_entry['atomic_group_class'])
                if atomic_group:
                    assert atomic_group_entry.instance.id == atomic_group.id
                else:
                    atomic_group = atomic_group_entry.instance

        job_id = rpc_utils.create_new_job(
                owner=owner,
                options=options,
                host_objects=host_objects,
                metahost_objects=metahost_label_objects,
                atomic_group=atomic_group)
        return models.Job.objects.get(id=job_id)


    def update(self, input_dict):
        # Required for POST, doesn't actually support PUT
        pass


class JobCollection(resource_lib.Collection):
    queryset = models.Job.objects.order_by('-id')
    entry_class = Job


class QueueEntry(resource_lib.InstanceEntry):
    _permitted_methods = ('GET', 'PUT')
    model = models.HostQueueEntry


    @classmethod
    def add_query_selectors(cls, query_processor):
        query_processor.add_field_selector('host', field='host__hostname')
        query_processor.add_field_selector('job', field='job__id')


    @classmethod
    def from_uri_args(cls, request, queue_entry_id):
        instance = models.HostQueueEntry.objects.get(id=queue_entry_id)
        return cls(request, instance)


    def _uri_args(self):
        return {'queue_entry_id': self.instance.id}


    def short_representation(self):
        rep = super(QueueEntry, self).short_representation()
        if self.instance.host:
            host = (Host(self._request, self.instance.host)
                    .short_representation())
        else:
            host = None
        job = Job(self._request, self.instance.job)
        host = Host.from_optional_instance(self._request, self.instance.host)
        label = Label.from_optional_instance(self._request,
                                             self.instance.meta_host)
        atomic_group_class = AtomicGroupClass.from_optional_instance(
                self._request, self.instance.atomic_group)
        rep.update(
                {'job': job.short_representation(),
                 'host': host.short_representation(),
                 'label': label.short_representation(),
                 'atomic_group_class':
                     atomic_group_class.short_representation(),
                 'status': self.instance.status,
                 'execution_path': self.instance.execution_subdir,
                 'started_on': self._format_datetime(self.instance.started_on),
                 'aborted': bool(self.instance.aborted)})
        return rep


    def update(self, input_dict):
        if 'aborted' in input_dict:
            if input_dict['aborted'] != True:
                raise BadRequest('"aborted" can only be set to true')
            query = models.HostQueueEntry.objects.filter(pk=self.instance.pk)
            models.AclGroup.check_abort_permissions(query)
            rpc_utils.check_abort_synchronous_jobs(query)
            self.instance.abort(thread_local.get_user())


class QueueEntryCollection(resource_lib.Collection):
    queryset = models.HostQueueEntry.objects.order_by('-id')
    entry_class = QueueEntry


class HealthTask(resource_lib.InstanceEntry):
    _permitted_methods = ('GET',)
    model = models.SpecialTask


    @classmethod
    def add_query_selectors(cls, query_processor):
        query_processor.add_field_selector('host', field='host__hostname')


    @classmethod
    def from_uri_args(cls, request, task_id):
        instance = models.SpecialTask.objects.get(id=task_id)
        return cls(request, instance)


    def _uri_args(self):
        return {'task_id': self.instance.id}


    def short_representation(self):
        rep = super(HealthTask, self).short_representation()
        host = Host(self._request, self.instance.host)
        queue_entry = QueueEntry.from_optional_instance(
                self._request, self.instance.queue_entry)
        rep.update(
                {'host': host.short_representation(),
                 'task_type': self.instance.task,
                 'started_on':
                     self._format_datetime(self.instance.time_started),
                 'status': self.instance.status,
                 'queue_entry': queue_entry.short_representation()
                 })
        return rep


    @classmethod
    def create_instance(cls, input_dict, containing_collection):
        cls._check_for_required_fields(input_dict, ('task_type',))
        host = containing_collection.base_entry.instance
        models.AclGroup.check_for_acl_violation_hosts((host,))
        return models.SpecialTask.schedule_special_task(host,
                                                        input_dict['task_type'])


    def update(self, input_dict):
        # Required for POST, doesn't actually support PUT
        pass


class HealthTaskCollection(resource_lib.Collection):
    entry_class = HealthTask


    def _fresh_queryset(self):
        return models.SpecialTask.objects.order_by('-id')


class ResourceDirectory(resource_lib.Resource):
    _permitted_methods = ('GET',)

    def handle_request(self):
        result = self.link()
        result.update({
                'atomic_group_classes':
                AtomicGroupClassCollection(self._request).link(),
                'labels': LabelCollection(self._request).link(),
                'users': UserCollection(self._request).link(),
                'acl_groups': AclCollection(self._request).link(),
                'hosts': HostCollection(self._request).link(),
                'tests': TestCollection(self._request).link(),
                'execution_info': ExecutionInfo(self._request).link(),
                'queue_entries_request':
                QueueEntriesRequest(self._request).link(),
                'jobs': JobCollection(self._request).link(),
                })
        return self._basic_response(result)
