from __future__ import unicode_literals
from db import Base, connect
from clientjob.model import Job
from main.model import Computer
from model import HardwareElement, HardwareProfile
from decorators import pi18n
from utils import adquire_thread_orm
import web

class RequestHardwareProfileJob(Job):

    def __init__(self, computer_id=None, computers=None, parent=None):
        Job.__init__(self, 'og ogListHardwareInfo')
        orm = adquire_thread_orm()
        if computers:
            # it's a group job
            for computer in computers:
                job = RequestHardwareProfileJob(computer_id=computer.id, parent=self)
                orm.add(job)
        else:
            self.parent = parent
            self.computer_id = computer_id

    @pi18n
    def get_user_message(self):
        if self.children:
            return _('Created a group job successfully!!')

        # WARNING! web.ctx.plugin_manager is not available in the server daemon
        if self.status != 'FINISHED' or not hasattr(web.ctx, 'plugin_manager'):
            return Job.get_user_message(self)

        hwinventory = web.ctx.plugin_manager.get_plugin_by_name("hardware_inventory")
        return _('Retrieved the <a href=\"%s\">hardware profile for %s</a>') %\
            (hwinventory.get_view_profile_url(self.computer.name), self.computer.name)

    def update(self):
        '''
        This function is called when a client replies to a
        "create hardware inventory" request. The job contains the text
        with the hardware description of the computer. This text is parsed
        and some hardware elements and a hardware profile are added
        to the data base (only if they aren't already). This profile
        hardware is related with the computer.

        Text is get with the command ogHardwareList.
        '''
        orm = adquire_thread_orm()

        if self.status != 'FINISHED':
            # If the job isn't finished we do nothing
            return

        elements = []
        print "hw inventory update: ", self.id, self.client_message

        # Parsing the text
        for line in self.client_message.splitlines():
            parts = line.split('=')
            # Errors may happen
            if (len(parts) != 2):
                print 'Hardware element incorrect: %s' % line
                continue

            if (len(parts[0]) != 3):
                print 'Type with size incorrect size (must be 3): %s' % line
                continue

            if (len(parts[1]) > 512):
                print '%s: Too long description: %s' % line
                continue

            # Locking for the hardware element in the data base
            hardware_element = self._search_specific_hardware_element(*parts)

            if not hardware_element:
                # If it is not in the data base we added
                hardware_element = HardwareElement()
                hardware_element.type = parts[0]
                hardware_element.description = parts[1]
                orm.add(hardware_element)

            # Saving the elements to make the profile later
            elements.append(hardware_element)

        # Locking for a profile with the same elements
        hardware_profile = self._search_specific_hardware_profile(elements)

        if not hardware_profile:
            # If hardware_profile doesn't exist in the db, it'll be added
            hardware_profile = HardwareProfile()
            hardware_profile.computers = []
            hardware_profile.elements = elements
            orm.add(hardware_profile)

        hardware_profile.computers.append(self.computer)

        orm.commit()

    def _search_specific_hardware_profile(self, elements):
        '''
        Searchs a profile with the given elements.
        It is returned if it found. None is returned in other case.
        '''
        profiles = self.orm.query(HardwareProfile).all()

        for profile in profiles:
            if set(profile.elements) == set(elements):
                return profile

        return None

    def _search_specific_hardware_element(self, hardware_type,
        description):
        '''
        Searchs a element with the given type and description.
        It is returned if it found. None is returned in other case.
        '''
        orm = adquire_thread_orm()
        elements = self.orm.query(HardwareElement).all()

        for element in elements:
            if (element.type == hardware_type and
                    element.description == description):
                return element

        return None
