from main.model import Computer
from clientjob.model import Job
from jobs import DiskCurrentStateJob
from model import DiskProfile, Disk, Image, Partition
import datetime
import time
import web
from web import form
from decorators import pi18n
from decimal import Decimal

class CurrentState:
    '''
    This a intermediate view. First it looks for a previus job sent to
    the computer to know its disk state. If this job is recently
    the user will be redirect to the view of that disk state.
    If not a new job is sent.
    '''

    EXPIRED_JOB = datetime.timedelta(minutes = 15)
    def GET(self, computer_name):
        computer = web.ctx.orm.query(Computer).filter(Computer.name ==
                computer_name).first()
        if not computer:
            return web.notfound()

        if not computer.online:
            return web.ctx.render.plugins.disk_image.\
                    diskstate_computer_offline(computer)

        image_plugin = web.ctx.plugin_manager.get_plugin_by_name('disk_image')

        job = web.ctx.orm.query(Job).\
                filter(Job.request == DiskCurrentStateJob.command).\
                filter(Job.computer.name == computer_name).\
                filter(not Job.status in ['CANCELLED', 'ERROR']).\
                order_by(Job.last_modified_date)[1]

        if job and datetime.datetime.now() - job.last_modified_date\
                > CurrentState.EXPIRED_JOB:
            url = image_plugin.get_view_disk_state_url(job.id)
        
        else:
            new_job_id = image_plugin.create_new_current_state(computer.id)
            url = image_plugin.get_view_disk_state_url(new_job_id)

        raise web.seeother(url)


class ShowDiskProfile:
    def GET(self, disk_profile_id, child_id, child_is_a_computer):
        orm = web.ctx.orm
        disk_profile = orm.query(DiskProfile).filter(
                DiskProfile.id == disk_profile_id).firts()
        if not disk_profile:
            return web.notfound()

class DiskState:
    @pi18n
    def GET(self, job_id): #, noupdate = False, force = False):
        '''
        job = web.ctx.orm.query(Job).filter(Job.id == job_id).one()

        if job.request != DiskCurrentStateJob.command:
            raise web.notfound()
            
        if job.state in ('CANCELLED', 'ERROR'):
            image_plugin = web.ctx.plugin_manager.get_plugin_by_name('disk_image')
            url = image_plugin.get_new_disk_state_url(job.computer.name)
            return web.ctx.render.plugins.disk_image.diskstate_error(url)

        elif job.state in ('CREATED', 'WAITING', 'SENT'):
            return web.ctx.render.plugins.disk_image.diskstate_no_started(job)

        elif job.state == 'INPROGRESS':
            web.ctx.notify(_('The information is comming. This process can\
                    takes some minutes. Please wait. %d% complete.') %
                    (job.progress))

        elif job.state == 'FINISHED':
            web.ctx.notify(_("Disk profile was retrieve %s from %s.\
                    If you aren't sure that this information is recent, you\
                    can <a href=\"%s\">update disk profile</a>.") %
                (fancy_datetime(job.last_modified), job.computer.name))

        #TODO make from the job.message a disk profile

        '''

        profile = DiskProfile()
        disk = Disk()
        disk.add_partition(size = 50, primary=True)
        disk.add_partition(size = 10, primary=False)
        disk.add_partition(size = 20, primary=False)
        disk.add_partition(size = 10, primary=True)
        #disk.add_partition(size = 5, primary=False, at_begining=False)
        profile.add_disk(disk)

        return web.ctx.render.plugins.disk_image.disk_state(profile)


class AdminImages:
    @pi18n
    def GET(self, *args):
        images = web.ctx.orm.query(Image).all()
        return web.ctx.render.plugins.disk_image.adminimages(images)


class EditImage:
    @pi18n
    def GET(self, type, value):
        orm = web.ctx.orm
        image = None
        if type == 'name':
            image = orm.query(Image).filter(Image.name == value).first()

        elif type == 'admin':
            image = orm.query(Image).filter(Image.id == value).first()

        else:
            raise web.notfound()

        if not image:
            raise web.notfound()

        return web.render.plugins.disk_image.edit_image(image)

class NewDiskProfile:
    @pi18n
    def GET(self):
        orm = web.ctx.orm
        lt = time.localtime()
        string = _('profile')
        name = ('%s_%d/%d/%d_%d:%d:%d' % (string, lt.tm_year, lt.tm_mon,
                lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec))

        '''
        if orm.query(DiskProfile).filter(DiskProfile.name == name).first():
            for n in range(1, 10):
                pos_name = ('%s-%d' % (name, n))
                if not orm.query(DiskProfile).filter(DiskProfile.name ==
                        pos_name).first():
                    name = pos_name
                    break
        '''

        diskprofile = DiskProfile(name)
        disk = diskprofile.add_empty_disk()
        disk.set_cache(20)

        orm.add(diskprofile)
        orm.commit()

        pm = web.ctx.plugin_manager
        disk_image = pm.get_plugin_by_name('disk_image')
        raise web.seeother(disk_image.get_edit_disk_profile_url(
            diskprofile.id))

class EditDiskProfile:
    @pi18n
    def GET(self, profile_id):
        orm = web.ctx.orm
        profile = orm.query(DiskProfile).filter(DiskProfile.id ==
                profile_id).first()

        if not profile:
            raise web.notfound()

        return web.ctx.render.plugins.disk_image.editdiskprofile(profile,
                FormCreator())

    def POST(self, profile_id):
        orm = web.ctx.orm
        profile = orm.query(DiskProfile).filter(DiskProfile.id ==
                profile_id).first()

        if not profile:
            raise web.notfound()

        user_data = web.input(command="")
        command = user_data['command']

        if command == 'remove_partition':
            disk = profile.get_disk(int(user_data['disk']))
            disk.remove_partition(int(user_data['partition']))

        elif command == 'add_partition':
            disk = profile.get_disk(int(user_data['disk']))
            primary = (user_data['type'] == 'Primary')
            begining = (user_data['position'] == 'Begining')
            disk.add_partition(size=Decimal(user_data['size']),
                    primary=primary, begining=begining,
                    filesystem=user_data['filesystem'])

        elif command == 'remove_disk':
            profile.remove_disk(int(user_data['disk']))

        elif command == 'add_disk':
            profile.add_empty_disk()

        elif command == 'profile':
            profile.name = user_data['name']
            profile.description = user_data['description']
            profile.set_cache(Decimal(user_data['cache']))

        orm.commit()

        return self.GET(profile_id)


class FormCreator:
    @pi18n
    def size_validator(self):
        return [form.regexp(r"\d?\d(.\d\d?)?",
                _("Must be a number. You can use two decimals")),
                form.Validator(_("Must be higher than 0 and less than 50"),
                lambda x:float(x) < 50 and float(x) > 0)]

    def disk_profile_form(self, profile):
        cache_size = 0
        cache = profile.get_cache()
        if cache:
            cache_size = cache.size

        return form.Form(
                form.Textbox('name',
                    form.notnull,
                    maxlenght=256,
                    description=_("Name"),
                    value=profile.name),
                form.Textarea('description',
                    description=_("Description"),
                    maxlenght=4096,
                    value=profile.description),
                form.Textbox('cache',
                    self.size_validator(),
                    maxlenght=5,
                    description=_("Cache Size"),
                    value=cache_size),
                form.Hidden(name='command', value='profile'),
                form.Button(_('Apply'), type='submit',
                    description=_("Apply changes")))
                    # value=profile.get_cache().size))

    @pi18n
    def remove_partition_form(self, partition):
        return form.Form(
                form.Hidden(name='command', value='remove_partition'),
                form.Hidden(name='disk', value=partition.disk.number),
                form.Hidden(name='partition', value=partition.number),
                form.Button(_('Remove'), type='submit',
                    description=_("Remove the partition")))


    @pi18n
    def add_partition_form(self, disk):
        primary_free_space = disk.can_add_primary_partition()
        logic_free_space = disk.can_add_logic_partition()

        if not primary_free_space and not logic_free_space:
            return None

        dropdown_args = []
        default_value = None
        size_value = 0

        if logic_free_space:
            dropdown_args.append(_("Logic"))
            default_value = _("Logic")
            size_value = logic_free_space

        if primary_free_space:
            dropdown_args.append(_("Primary"))
            default_value = _("Primary")
            size_value = logic_free_space


        return form.Form(
                form.Dropdown(name="type", args=dropdown_args, value=default_value),
                form.Dropdown(name="position", args=[_("Begining"),_("End")],
                    value=_("Begining")),
                form.Textbox("size", self.size_validator(),
                    description="Size", value=size_value),
                # form.Dropdown(name="image", args=get_repo().images, value=),
                form.Dropdown(name="filesystem", description="FileSystem",
                    args=Partition.filesystems),
                form.Hidden(name='command', value='add_partition'),
                form.Hidden(name='disk', value=disk.number),
                form.Button(_("Add"), type="submit",
                    description=_("Add partition")))

    @pi18n
    def remove_disk_form(self, disk):
        # The first disk can't be removed
        if disk.number == 1:
            return None
        return form.Form(
                form.Hidden(name='command', value='remove_disk'),
                form.Hidden(name='disk', value=disk.number),
                form.Button(_('Remove Disk'), type='submit',
                    description=_('Remove disk from profile')))

    @pi18n
    def add_disk_form(self):
        return form.Form(
                form.Hidden(name='command', value='add_disk'),
                form.Button(_('Add Disk'), type='submit',
                    decription=_('Add a new disk')))
